From 0fd86dea1f0f28405b0fc735c2f79ac49e086faf Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 18 Apr 2014 12:22:02 +0200 Subject: [PATCH] IDEA-122946 final modifier not inserted when completing a sequence of parameters from an inner method IDEA-123493 Smart completion makes completed variable final --- .../analysis/HighlightControlFlowUtil.java | 2 +- .../SameSignatureCallParametersProvider.java | 18 ++++++++++++--- .../lookup/VariableLookupItem.java | 23 ++++++++----------- .../completion/NormalCompletionTest.groovy | 11 ++++++++- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 964239067aeb..73603037a187 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -716,7 +716,7 @@ public class HighlightControlFlowUtil { } @Nullable - public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) { + public static PsiClass getInnerClassVariableReferencedFrom(@NotNull PsiVariable variable, @NotNull PsiElement context) { final PsiElement[] scope; if (variable instanceof PsiResourceVariable) { scope = ((PsiResourceVariable)variable).getDeclarationScope(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java index d3f0b2e62782..d898bb77ae5a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; @@ -72,8 +73,8 @@ class SameSignatureCallParametersProvider extends CompletionProvider() { @Override public String fun(PsiParameter psiParameter) { @@ -86,7 +87,18 @@ class SameSignatureCallParametersProvider extends CompletionProvider() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + context.commitDocument(); + for (PsiParameter parameter : CompletionUtil.getOriginalOrSelf(takeParametersFrom).getParameterList().getParameters()) { + VariableLookupItem.makeFinalIfNeeded(context, parameter); + } + } + }); + } element.putUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS, Boolean.TRUE); return TailTypeDecorator.withTail(element, ExpectedTypesProvider.getFinalCallParameterTailType(call, invoked.getReturnType(), invoked)); diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index 9f23dba0b7df..21e32a3e3aeb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -123,7 +123,10 @@ public class VariableLookupItem extends LookupItem implements Typed } ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false); - makeVariableFinalIfNeeded(context, ref); + PsiElement target = ref == null ? null : ref.resolve(); + if (target instanceof PsiLocalVariable || target instanceof PsiParameter) { + makeFinalIfNeeded(context, (PsiVariable)target); + } final char completionChar = context.getCompletionChar(); if (completionChar == '=') { @@ -151,22 +154,16 @@ public class VariableLookupItem extends LookupItem implements Typed } } - private static void makeVariableFinalIfNeeded(InsertionContext context, @Nullable PsiReferenceExpression ref) { + public static void makeFinalIfNeeded(@NotNull InsertionContext context, @NotNull PsiVariable variable) { + PsiElement place = context.getFile().findElementAt(context.getTailOffset() - 1); if (!Registry.is("java.completion.make.outer.variables.final") || - ref == null || PsiUtil.isLanguageLevel8OrHigher(ref) || JspPsiUtil.isInJspFile(ref)) { + place == null || PsiUtil.isLanguageLevel8OrHigher(place) || JspPsiUtil.isInJspFile(place)) { return; } - PsiElement target = ref.resolve(); - if (target instanceof PsiLocalVariable || target instanceof PsiParameter) { - PsiClass placeClass = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiClass.class, false); - if (placeClass != null && !PsiTreeUtil.isAncestor(placeClass, target, true) && - !HighlightControlFlowUtil.isReassigned((PsiVariable)target, new HashMap>())) { - PsiModifierList modifierList = ((PsiVariable)target).getModifierList(); - if (modifierList != null) { - modifierList.setModifierProperty(PsiModifier.FINAL, true); - } - } + if (HighlightControlFlowUtil.getInnerClassVariableReferencedFrom(variable, place) != null && + !HighlightControlFlowUtil.isReassigned(variable, new HashMap>())) { + PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index d30e3520f932..cbb86bb2fed6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1283,9 +1283,18 @@ class XInternalError {} lookup.currentItem = lookup.items[1] type '\n' checkResult() - } + public void testMakeMultipleArgumentsFinalWhenInInner() { + configure() + def item = lookup.items.find { 'a, b' == it.lookupString } + assert item + lookup.currentItem = item + type '\n' + checkResult() + } + + public void testNoFinalInAnonymousConstructor() { doTest() } public void testListArrayListCast() { doTest('\n') } public void testInterfaceImplementationNoCast() { doTest() } public void testStaticallyImportedMethodsBeforeExpression() { doTest() }