From a48dd6e1de59406d3a41eccbd9c8bb47b0055439 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 28 Sep 2011 18:53:22 +0200 Subject: [PATCH] IDEA-71518 let parameters completion pass method parameters --- .../codeInsight/ExpectedTypesProvider.java | 6 +- .../JavaSmartCompletionContributor.java | 2 +- .../SameSignatureCallParametersProvider.java | 79 +++++++++++++------ .../smartType/SameNamedArguments-out.java | 9 +++ .../smartType/SameNamedArguments.java | 9 +++ ...eIntConstantsFromConstructedClass-out.java | 2 +- .../completion/SmartTypeCompletionTest.java | 7 ++ 7 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments.java diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 0ab601395ec0..e0040f8b7348 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -1214,13 +1214,13 @@ public class ExpectedTypesProvider { return TailTypes.CALL_RPARENTH_SEMICOLON; } - final boolean chainable = !PsiType.VOID.equals(returnType) && returnType != null; + final boolean chainable = !PsiType.VOID.equals(returnType) && returnType != null || method.isConstructor() && call instanceof PsiNewExpression; final PsiElement parent = call.getParent(); final boolean statementContext = parent instanceof PsiExpressionStatement || parent instanceof PsiVariable || - parent instanceof PsiCodeBlock || parent instanceof PsiThrowStatement; + parent instanceof PsiCodeBlock; - if (statementContext && !chainable) { + if (parent instanceof PsiThrowStatement || statementContext && !chainable) { return TailTypes.CALL_RPARENTH_SEMICOLON; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index ed7ca4e2030f..15b4966bc7a4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -114,7 +114,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { extend(CompletionType.SMART, psiElement().beforeLeaf(psiElement(JavaTokenType.RPARENTH)).afterLeaf("(").withParent( psiElement(PsiReferenceExpression.class).withParent( - psiElement(PsiExpressionList.class).withParent(PsiMethodCallExpression.class))), new SameSignatureCallParametersProvider()); + psiElement(PsiExpressionList.class).withParent(PsiCall.class))), new SameSignatureCallParametersProvider()); extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.INSTANCEOF), new CompletionProvider() { protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { 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 3705cfa5eb77..93c1645c4947 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SameSignatureCallParametersProvider.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.completion; +import com.google.common.collect.Maps; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; @@ -30,9 +31,11 @@ import com.intellij.util.Function; import com.intellij.util.PlatformIcons; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * @author peter @@ -42,18 +45,19 @@ class SameSignatureCallParametersProvider extends CompletionProvider> candidates = getSuperMethodCandidates(expression); + List> candidates = getCallCandidates(methodCall); PsiMethod container = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); while (container != null) { for (final Pair candidate : candidates) { - if (container.getParameterList().getParametersCount() > 1 && isSuperMethod(container, candidate.first, candidate.second)) { - result.addElement(createParametersLookupElement(container, methodCall)); - return; + if (container.getParameterList().getParametersCount() > 1 && candidate.first.getParameterList().getParametersCount() > 1) { + PsiMethod from = getMethodToTakeParametersFrom(container, candidate.first, candidate.second); + if (from != null) { + result.addElement(createParametersLookupElement(from, methodCall, candidate.first)); + return; + } } } @@ -62,8 +66,8 @@ class SameSignatureCallParametersProvider extends CompletionProvider() { + private static LookupElement createParametersLookupElement(PsiMethod takeParametersFrom, PsiElement call, PsiMethod invoked) { + final String lookupString = StringUtil.join(takeParametersFrom.getParameterList().getParameters(), new Function() { public String fun(PsiParameter psiParameter) { return psiParameter.getName(); } @@ -77,12 +81,19 @@ class SameSignatureCallParametersProvider extends CompletionProvider> getSuperMethodCandidates(PsiReferenceExpression expression) { + private static List> getCallCandidates(PsiCall expression) { List> candidates = new ArrayList>(); - for (final JavaResolveResult candidate : expression.multiResolve(true)) { + JavaResolveResult[] results; + if (expression instanceof PsiMethodCallExpression) { + results = ((PsiMethodCallExpression)expression).getMethodExpression().multiResolve(false); + } else { + results = new JavaResolveResult[]{expression.resolveMethodGenerics()}; + } + + for (final JavaResolveResult candidate : results) { final PsiElement element = candidate.getElement(); if (element instanceof PsiMethod) { final PsiClass psiClass = ((PsiMethod)element).getContainingClass(); @@ -100,26 +111,42 @@ class SameSignatureCallParametersProvider extends CompletionProvider requiredNames = Maps.newHashMap(); + final PsiParameter[] parameters = place.getParameterList().getParameters(); + final PsiParameter[] callParams = invoked.getParameterList().getParameters(); + if (callParams.length > parameters.length) { + return null; } - final boolean checkNames = callee.isConstructor(); - for (int i = 0; i < parameters.length; i++) { + + final boolean checkNames = invoked.isConstructor(); + boolean sameTypes = true; + for (int i = 0; i < callParams.length; i++) { + PsiParameter callParam = callParams[i]; PsiParameter parameter = parameters[i]; - final PsiParameter superParam = superParams[i]; - if (checkNames && !Comparing.equal(parameter.getName(), superParam.getName()) || - !Comparing.equal(parameter.getType(), substitutor.substitute(superParam.getType()))) { - return false; + requiredNames.put(callParam.getName(), substitutor.substitute(callParam.getType())); + if (checkNames && !Comparing.equal(parameter.getName(), callParam.getName()) || + !Comparing.equal(parameter.getType(), substitutor.substitute(callParam.getType()))) { + sameTypes = false; } } - return true; + if (sameTypes && callParams.length == parameters.length) { + return place; + } + + for (PsiParameter parameter : parameters) { + PsiType type = requiredNames.remove(parameter.getName()); + if (type != null && !parameter.getType().equals(type)) { + return null; + } + } + + return requiredNames.isEmpty() ? invoked : null; } } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments-out.java new file mode 100644 index 000000000000..fd9c8d0a33d3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments-out.java @@ -0,0 +1,9 @@ +public class SomeClass { + Border createBorder(Color color, int top, boolean isOpaque, int bottom, int right, int left) { + new Insets(top, left, bottom, right) + } +} + +class Insets { + Insets(int top, int left, int bottom, int right) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments.java b/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments.java new file mode 100644 index 000000000000..e9a6bcea8cc1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SameNamedArguments.java @@ -0,0 +1,9 @@ +public class SomeClass { + Border createBorder(Color color, int top, boolean isOpaque, int bottom, int right, int left) { + new Insets() + } +} + +class Insets { + Insets(int top, int left, int bottom, int right) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/UseIntConstantsFromConstructedClass-out.java b/java/java-tests/testData/codeInsight/completion/smartType/UseIntConstantsFromConstructedClass-out.java index 945a588b682b..eb9855b1b277 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/UseIntConstantsFromConstructedClass-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/UseIntConstantsFromConstructedClass-out.java @@ -10,6 +10,6 @@ class Foo { public class Bar { { - new Foo(Foo.FOO_BAR); + new Foo(Foo.FOO_BAR) } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 578d1d29439b..a88db44ac360 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -757,6 +757,13 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { checkResultByTestName(); } + public void testSameNamedArguments() throws Throwable { + configureByTestName(); + getLookup().setCurrentItem(getLookup().getItems().get(4)); + select(); + checkResultByTestName(); + } + public void testWrongAnonymous() throws Throwable { configureByTestName(); select();