KtBlockExpression as lazy reparseable node (KT-13841)

Changed KtBlockExpression to support LazyReparseable behaviour
Added LazyKtBlockExpressionTest
Added new BlockWrapper delegations
This commit is contained in:
Igor Yakovlev
2019-03-12 13:43:13 +03:00
parent e774f3fe77
commit 1f29b42cd3
16 changed files with 443 additions and 128 deletions
@@ -108,7 +108,7 @@ class CodeFragmentAnalyzer(
}
}
is KtSecondaryConstructor -> {
val expression = context.bodyExpression ?: context.getDelegationCall().calleeExpression
val expression = (context.bodyExpression ?: context.getDelegationCall().calleeExpression) as? KtExpression
if (expression != null) {
bindingContext = resolutionFactory(expression)
scope = bindingContext[BindingContext.LEXICAL_SCOPE, expression]
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.editor
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.EditorTestUtil
import com.intellij.testFramework.EditorTestUtil.*
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCaseBase
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.Assert
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class LazyElementTypeTest : KotlinLightCodeInsightFixtureTestCaseBase() {
fun testSplitArrow() = reparse("val t = { a: Int -<caret>> }", ' ')
fun testDeleteArrow() = reparse("val t = { a: Int -><caret> }", BACKSPACE_FAKE_CHAR)
fun testReformatNearArrow() = noReparse("val t = { a: Int<caret>-> }", ' ')
fun testChangeAfterArrow() = noReparse("val t = { a: Int -> <caret> }", 'a')
fun testDeleteIrrelevantArrow() = noReparse("val t = { a: Int -> (1..3).filter { b -><caret> b > 2 } }", BACKSPACE_FAKE_CHAR)
fun testReformatNearLambdaStart() = noReparse("val t = {<caret>a: Int -> }", ' ')
fun testNoArrow() = noReparse("val t = { <caret> }", 'a')
fun testAfterRemovingParameterComma() = reparse(inIf("{t,<caret>}"), BACKSPACE_FAKE_CHAR)
fun testAfterRemovingNoParameterComma() = noReparse(inIf("{,<caret>}"), BACKSPACE_FAKE_CHAR)
fun testAfterRemovingNotLastParameterComma() = noReparse(inIf("{a, b,<caret>}"), BACKSPACE_FAKE_CHAR)
fun testAfterRemovingSecondParameter() = noReparse(inIf("{a,b<caret>}"), BACKSPACE_FAKE_CHAR)
fun testAfterFirstParameterRenamed() = noReparse(inIf("{a<caret>,}"), 'b')
fun testAfterRemovingFirstParameterWithOther() = reparse(inIf("{a<caret>,b}"), BACKSPACE_FAKE_CHAR)
fun testAfterRemovingFirstParameter() = reparse(inIf("{a<caret>,}"), BACKSPACE_FAKE_CHAR)
fun testAfterTypeComma() = reparse(inIf("{a<caret>}"), ',')
fun reparse(text: String, char: Char): Unit = doTest(text, char, true)
fun noReparse(text: String, char: Char): Unit = doTest(text, char, false)
fun doTest(text: String, char: Char, reparse: Boolean) {
val file = myFixture.configureByText("a.kt", text.trimMargin())
val lambdaExpressionBefore = PsiTreeUtil.findChildOfType(file, KtLambdaExpression::class.java)
performTypingAction(myFixture.editor, char)
PsiDocumentManager.getInstance(LightPlatformTestCase.getProject()).commitDocument(myFixture.getDocument(file))
val lambdaExpressionAfter = PsiTreeUtil.findChildOfType(file, KtLambdaExpression::class.java)
val actualReparse = lambdaExpressionAfter != lambdaExpressionBefore
Assert.assertEquals("Lazy element behaviour was unexpected", reparse, actualReparse)
}
private fun inIf(lambda: String) = "val t: Unit = if (true) $lambda else {}"
override fun getProjectDescriptor() = LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.editor
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.EditorTestUtil.*
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCaseBase
import org.junit.Assert
abstract class LazyElementTypeTestBase<T>(private val lazyElementClass: Class<T>) :
KotlinLightCodeInsightFixtureTestCaseBase() where T : PsiElement {
protected fun reparse(text: String, char: Char): Unit = doTest(text, char, true)
protected fun noReparse(text: String, char: Char): Unit = doTest(text, char, false)
fun doTest(text: String, char: Char, reparse: Boolean) {
val file = myFixture.configureByText("a.kt", text.trimMargin())
val expressionBefore = PsiTreeUtil.findChildOfType(file, lazyElementClass)
performTypingAction(myFixture.editor, char)
PsiDocumentManager.getInstance(LightPlatformTestCase.getProject()).commitDocument(myFixture.getDocument(file))
val expressionAfter = PsiTreeUtil.findChildOfType(file, lazyElementClass)
val actualReparse = expressionAfter != expressionBefore
Assert.assertEquals("Lazy element behaviour was unexpected", reparse, actualReparse)
}
protected fun inIf(then: String) = "val t: Unit = if (true) $then else {}"
override fun getProjectDescriptor() = LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.editor
import com.intellij.testFramework.EditorTestUtil
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class LazyKtBlockExpressionTest : LazyElementTypeTestBase<KtBlockExpression>(KtBlockExpression::class.java) {
fun testSimpleReparse() = noReparse(inIf(" { a<caret>b }"), 'c')
fun testSimpleNotReparse() = reparse(inIf(" { a-<caret>b }"), '>')
fun testSplitArrow() = reparse(inIf("{ a: Int -<caret>> }"), ' ')
fun testDeleteArrow() = reparse(inIf("{ a: Int -<caret>> }"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testImbalance1() = noReparse(inIf(" { {}<caret> }"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testImbalance2() = noReparse(inIf(" { }<caret>"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testBlockWithArrowInside() = noReparse(inIf(" { { a: Int -<caret> a } }"), '>')
fun testBlockWithArrowInside2() = noReparse(inIf(" { } a: Int -<caret> a } }"), '>')
fun testBlockWithCommaAsLambdaArgument() = reparse(inIf(" { a<caret> }"), ',')
fun testBlockWithCommaAsBlockContent() = noReparse(inIf(" { a.b<caret> c.d = 3 }"), ',')
fun testBlockWithCommaAsBlockContent2() = noReparse(inIf(" { a(b<caret> c) }"), ',')
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.editor
import com.intellij.testFramework.EditorTestUtil
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class LazyKtLambdaExpressionTest : LazyElementTypeTestBase<KtLambdaExpression>(KtLambdaExpression::class.java) {
fun testSplitArrow() = reparse("val t = { a: Int -<caret>> }", ' ')
fun testDeleteArrow() = reparse("val t = { a: Int -><caret> }", EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testReformatNearArrow() = noReparse("val t = { a: Int<caret>-> }", ' ')
fun testChangeAfterArrow() = noReparse("val t = { a: Int -> <caret> }", 'a')
fun testDeleteIrrelevantArrow() = noReparse(
"val t = { a: Int -> (1..3).filter { b -><caret> b > 2 } }",
EditorTestUtil.BACKSPACE_FAKE_CHAR
)
fun testReformatNearLambdaStart() = noReparse("val t = {<caret>a: Int -> }", ' ')
fun testNoArrow() = noReparse("val t = { <caret> }", 'a')
fun testAfterRemovingParameterComma() = reparse(inIf("{t,<caret>}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterRemovingNoParameterComma() = noReparse(inIf("{,<caret>}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterRemovingNotLastParameterComma() = noReparse(inIf("{a, b,<caret>}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterRemovingSecondParameter() = noReparse(inIf("{a,b<caret>}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterFirstParameterRenamed() = noReparse(inIf("{a<caret>,}"), 'b')
fun testAfterRemovingFirstParameterWithOther() = reparse(inIf("{a<caret>,b}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterRemovingFirstParameter() = reparse(inIf("{a<caret>,}"), EditorTestUtil.BACKSPACE_FAKE_CHAR)
fun testAfterTypeComma() = reparse(inIf("{a<caret>}"), ',')
}