From c71a1e71366535735029b1cc61b6dd515289f9d1 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 27 Jul 2016 12:15:56 +0200 Subject: [PATCH] IDEA-158267 Parameter completion overwrites the following lambda declaration ' () -> {}' --- .../completion/JavaCompletionUtil.java | 26 ++++++++++++++----- .../smartType/CallBeforeLambda-out.java | 7 +++++ .../smartType/CallBeforeLambda.java | 7 +++++ .../completion/normal/CallBeforeLambda.java | 5 ++++ .../normal/CallBeforeLambda_after.java | 5 ++++ .../completion/Normal8CompletionTest.groovy | 5 ++++ .../completion/SmartType18CompletionTest.java | 2 ++ .../util/ParenthesesInsertHandler.java | 17 ++++++++---- 8 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index dea033613fd2..f4d75ccc4bec 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -749,12 +749,26 @@ public class JavaCompletionUtil { final CommonCodeStyleSettings styleSettings = context.getCodeStyleSettings(); final PsiElement elementAt = file.findElementAt(context.getStartOffset()); if (elementAt == null || !(elementAt.getParent() instanceof PsiMethodReferenceExpression)) { - ParenthesesInsertHandler.getInstance(hasParams, - styleSettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES, - styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES && hasParams, - needRightParenth, - styleSettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE - ).handleInsert(context, item); + final boolean hasParameters = hasParams; + final boolean spaceBetweenParentheses = styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES && hasParams; + new ParenthesesInsertHandler(styleSettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES, spaceBetweenParentheses, + needRightParenth, styleSettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE) { + @Override + protected boolean placeCaretInsideParentheses(InsertionContext context1, LookupElement item1) { + return hasParameters; + } + + @Override + protected PsiElement findExistingLeftParenthesis(@NotNull InsertionContext context) { + PsiElement token = super.findExistingLeftParenthesis(context); + return isPartOfLambda(token) ? null : token; + } + + private boolean isPartOfLambda(PsiElement token) { + return token != null && token.getParent() instanceof PsiExpressionList && + PsiUtilCore.getElementType(PsiTreeUtil.nextVisibleLeaf(token.getParent())) == JavaTokenType.ARROW; + } + }.handleInsert(context, item); } if (hasParams) { diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda-out.java b/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda-out.java new file mode 100644 index 000000000000..30518fbb403b --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda-out.java @@ -0,0 +1,7 @@ +class Foo { + { + foo(hashCode(), () -> {}); + } + + void foo(int i, Runnable r) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda.java b/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda.java new file mode 100644 index 000000000000..7aac826727de --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CallBeforeLambda.java @@ -0,0 +1,7 @@ +class Foo { + { + foo(hash() -> {}); + } + + void foo(int i, Runnable r) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda.java new file mode 100644 index 000000000000..8056da38658d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda.java @@ -0,0 +1,5 @@ +class Foo { + { + foo(hash() -> {}); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda_after.java new file mode 100644 index 000000000000..91c8077e5c78 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/CallBeforeLambda_after.java @@ -0,0 +1,5 @@ +class Foo { + { + foo(hashCode()() -> {}); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy index 8c55f26d8057..4d52ee6b479d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy @@ -247,6 +247,11 @@ class Test88 { checkResultByFile(getTestName(false) + "_after.java") } + public void testCallBeforeLambda() { + configureByTestName() + checkResultByFile(getTestName(false) + "_after.java") + } + public void testLambdaInAmbiguousCall() { configureByTestName() myFixture.assertPreferredCompletionItems(0, 'toString', 'wait') diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java index bf243b5f9139..b5c66455f18a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java @@ -210,4 +210,6 @@ public void testConvertToObjectStream() { public void testSuggestMapInheritors() { doTest(); } public void testUnboundTypeArgs() { doTest(); } + + public void testCallBeforeLambda() { doTest(false); } } diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/util/ParenthesesInsertHandler.java b/platform/lang-api/src/com/intellij/codeInsight/completion/util/ParenthesesInsertHandler.java index 149c6f850d72..1b32fce1184d 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/util/ParenthesesInsertHandler.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/util/ParenthesesInsertHandler.java @@ -24,6 +24,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -94,7 +95,7 @@ public abstract class ParenthesesInsertHandler implemen final Editor editor = context.getEditor(); final Document document = editor.getDocument(); context.commitDocument(); - PsiElement element = findNextToken(context); + PsiElement lParen = findExistingLeftParenthesis(context); final char completionChar = context.getCompletionChar(); final boolean putCaretInside = completionChar == '(' || placeCaretInsideParentheses(context, item); @@ -103,8 +104,8 @@ public abstract class ParenthesesInsertHandler implemen context.setAddCompletionChar(false); } - if (isToken(element, "(")) { - int lparenthOffset = element.getTextRange().getStartOffset(); + if (lParen != null) { + int lparenthOffset = lParen.getTextRange().getStartOffset(); if (mySpaceBeforeParentheses && lparenthOffset == context.getTailOffset()) { document.insertString(context.getTailOffset(), " "); lparenthOffset++; @@ -118,7 +119,7 @@ public abstract class ParenthesesInsertHandler implemen context.setTailOffset(lparenthOffset + 1); - PsiElement list = element.getParent(); + PsiElement list = lParen.getParent(); PsiElement last = list.getLastChild(); if (isToken(last, ")")) { int rparenthOffset = last.getTextRange().getStartOffset(); @@ -163,7 +164,13 @@ public abstract class ParenthesesInsertHandler implemen } @Nullable - protected PsiElement findNextToken(final InsertionContext context) { + protected PsiElement findExistingLeftParenthesis(@NotNull InsertionContext context) { + PsiElement element = findNextToken(context); + return isToken(element, "(") ? element : null; + } + + @Nullable + protected PsiElement findNextToken(@NotNull InsertionContext context) { final PsiFile file = context.getFile(); PsiElement element = file.findElementAt(context.getTailOffset()); if (element instanceof PsiWhiteSpace) {