diff --git a/compiler/frontend/src/org/jetbrains/kotlin/LambdaExpressionElementType.java b/compiler/frontend/src/org/jetbrains/kotlin/LambdaExpressionElementType.java index 7560a4cf750..a477476bcff 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/LambdaExpressionElementType.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/LambdaExpressionElementType.java @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.parsing.KotlinParser; import org.jetbrains.kotlin.psi.KtFunctionLiteral; import org.jetbrains.kotlin.psi.KtLambdaExpression; +import org.jetbrains.kotlin.psi.KtParameterList; class LambdaExpressionElementType extends IErrorCounterReparseableElementType { public LambdaExpressionElementType() { @@ -55,7 +56,7 @@ class LambdaExpressionElementType extends IErrorCounterReparseableElementType { @Override public boolean isParsable(@Nullable ASTNode parent, CharSequence buffer, Language fileLanguage, Project project) { return super.isParsable(parent, buffer, fileLanguage, project) && - !wasArrowMovedOrDeleted(parent, buffer); + !wasArrowMovedOrDeleted(parent, buffer) && !wasParameterCommaMovedOrDeleted(parent, buffer); } private static boolean wasArrowMovedOrDeleted(@Nullable ASTNode parent, CharSequence buffer) { @@ -75,6 +76,27 @@ class LambdaExpressionElementType extends IErrorCounterReparseableElementType { return hasTokenMoved(lambdaExpression.getText(), buffer, arrowOffset, KtTokens.ARROW); } + private static boolean wasParameterCommaMovedOrDeleted(@Nullable ASTNode parent, CharSequence buffer) { + KtLambdaExpression lambdaExpression = findLambdaExpression(parent); + if (lambdaExpression == null) { + return false; + } + + KtFunctionLiteral literal = lambdaExpression.getFunctionLiteral(); + KtParameterList valueParameterList = literal.getValueParameterList(); + if (valueParameterList == null || valueParameterList.getParameters().size() <= 1) { + return false; + } + + PsiElement comma = valueParameterList.getFirstComma(); + if (comma == null) { + return false; + } + + int commaOffset = comma.getTextOffset() - lambdaExpression.getTextOffset(); + return hasTokenMoved(lambdaExpression.getText(), buffer, commaOffset, KtTokens.COMMA); + } + private static KtLambdaExpression findLambdaExpression(@Nullable ASTNode parent) { if (parent == null) return null; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameterList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameterList.java index 71f068dece3..6a241ba296c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameterList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameterList.java @@ -89,4 +89,9 @@ public class KtParameterList extends KtElementImplStub> }", ' ') - fun testDeleteArrow() = reparse("val t = { a: Int -> }", EditorTestUtil.BACKSPACE_FAKE_CHAR) + fun testDeleteArrow() = reparse("val t = { a: Int -> }", BACKSPACE_FAKE_CHAR) fun testReformatNearArrow() = noReparse("val t = { a: Int-> }", ' ') fun testChangeAfterArrow() = noReparse("val t = { a: Int -> }", 'a') - fun testDeleteIrrelevantArrow() = noReparse("val t = { a: Int -> (1..3).filter { b -> b > 2 } }", EditorTestUtil.BACKSPACE_FAKE_CHAR) + fun testDeleteIrrelevantArrow() = noReparse("val t = { a: Int -> (1..3).filter { b -> b > 2 } }", BACKSPACE_FAKE_CHAR) fun testReformatNearLambdaStart() = noReparse("val t = {a: Int -> }", ' ') fun testNoArrow() = noReparse("val t = { }", 'a') + fun testAfterRemovingParameterComma() = reparse(inIf("{t,}"), BACKSPACE_FAKE_CHAR) + fun testAfterRemovingNoParameterComma() = noReparse(inIf("{,}"), BACKSPACE_FAKE_CHAR) + fun testAfterRemovingNotLastParameterComma() = noReparse(inIf("{a, b,}"), BACKSPACE_FAKE_CHAR) + fun testAfterRemovingSecondParameter() = noReparse(inIf("{a,b}"), BACKSPACE_FAKE_CHAR) + fun testAfterFirstParameterRenamed() = noReparse(inIf("{a,}"), 'b') + + fun testAfterRemovingFirstParameterWithOther() = reparse(inIf("{a,b}"), BACKSPACE_FAKE_CHAR) + fun testAfterRemovingFirstParameter() = reparse(inIf("{a,}"), BACKSPACE_FAKE_CHAR) + fun testAfterTypeComma() = reparse(inIf("{a}"), ',') + fun reparse(text: String, char: Char): Unit = doTest(text, char, true) fun noReparse(text: String, char: Char): Unit = doTest(text, char, false) @@ -43,7 +54,7 @@ class LazyElementTypeTest : KotlinLightCodeInsightFixtureTestCaseBase() { val lambdaExpressionBefore = PsiTreeUtil.findChildOfType(file, KtLambdaExpression::class.java) - EditorTestUtil.performTypingAction(myFixture.editor, char) + performTypingAction(myFixture.editor, char) PsiDocumentManager.getInstance(LightPlatformTestCase.getProject()).commitDocument(myFixture.getDocument(file)) val lambdaExpressionAfter = PsiTreeUtil.findChildOfType(file, KtLambdaExpression::class.java) @@ -53,5 +64,7 @@ class LazyElementTypeTest : KotlinLightCodeInsightFixtureTestCaseBase() { 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 } \ No newline at end of file