From 39d4c1be0ec948c06c2dfb37bfb9d2c514471f7d Mon Sep 17 00:00:00 2001 From: "peter.gromov" Date: Wed, 17 Nov 2010 18:20:46 +0300 Subject: [PATCH] smart completion after new in groovy argument lists --- .../GroovyCompletionContributor.java | 75 +----------------- .../GroovySmartCompletionContributor.java | 79 ++++++++++++++++++- .../impl/types/GrClosureSignatureUtil.java | 10 ++- .../groovy/GroovyCompletionTest.groovy | 2 + .../completion/SmartAfterNewInCall.groovy | 2 + .../SmartAfterNewInCall_after.groovy | 2 + 6 files changed, 90 insertions(+), 80 deletions(-) create mode 100644 plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall.groovy create mode 100644 plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall_after.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index d8641a3ad51c..833a8ce6b5a3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -19,8 +19,6 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.codeInsight.lookup.LookupItem; -import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.util.Iconable; @@ -30,19 +28,15 @@ import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; -import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.GroovyIcons; -import org.jetbrains.plugins.groovy.lang.completion.handlers.AfterNewClassInsertHandler; -import org.jetbrains.plugins.groovy.lang.completion.handlers.ArrayInsertHandler; import org.jetbrains.plugins.groovy.lang.completion.handlers.NamedArgumentInsertHandler; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; @@ -70,6 +64,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; @@ -89,10 +84,6 @@ import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.skipWhitespaces */ public class GroovyCompletionContributor extends CompletionContributor { - private static final ElementPattern AFTER_NEW = - psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).andNot(psiElement().afterLeaf(psiElement().withText(PsiKeyword.THROW)))) - .withSuperParent(3, GrVariable.class); - private static final ElementPattern AFTER_DOT = psiElement().afterLeaf(".").withParent(GrReferenceExpression.class); private static final String[] MODIFIERS = @@ -299,44 +290,6 @@ public class GroovyCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, AFTER_NEW, new CompletionProvider(false) { - protected void addCompletions(@NotNull final CompletionParameters parameters, - final ProcessingContext matchingContext, - @NotNull final CompletionResultSet result) { - final PsiElement identifierCopy = parameters.getPosition(); - - final List expectedClassTypes = new SmartList(); - final List expectedArrayTypes = new ArrayList(); - - PsiType psiType = ((GrVariable)identifierCopy.getParent().getParent().getParent()).getTypeGroovy(); - if (psiType instanceof PsiClassType) { - PsiType type = JavaCompletionUtil.eliminateWildcards(JavaCompletionUtil.originalize(psiType)); - final PsiClassType classType = (PsiClassType)type; - if (classType.resolve() != null) { - expectedClassTypes.add(classType); - } - } - else if (psiType instanceof PsiArrayType) { - expectedArrayTypes.add((PsiArrayType)psiType); - } - - for (final PsiArrayType type : expectedArrayTypes) { - final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), identifierCopy); - if (item.getObject() instanceof PsiClass) { - JavaCompletionUtil.setShowFQN(item); - } - item.setInsertHandler(new ArrayInsertHandler()); - result.addElement(item); - } - - JavaInheritorsGetter.processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { - public void consume(final PsiType type) { - addExpectedType(result, type, identifierCopy); - } - }); - } - }); - //provide 'this' and 'super' completions in ClassName. extend(CompletionType.BASIC, AFTER_DOT, new CompletionProvider() { @Override @@ -353,7 +306,7 @@ public class GroovyCompletionContributor extends CompletionContributor { GrReferenceExpression referenceExpression = (GrReferenceExpression)qualifier; final PsiElement resolved = referenceExpression.resolve(); if (!(resolved instanceof PsiClass)) return; - if (!org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.hasEnclosingInstanceInScope((PsiClass)resolved, position, false)) return; + if (!PsiUtil.hasEnclosingInstanceInScope((PsiClass)resolved, position, false)) return; for (String keyword : THIS_SUPER) { result.addElement(LookupElementBuilder.create(keyword)); @@ -494,7 +447,7 @@ public class GroovyCompletionContributor extends CompletionContributor { Map writableProperties = new HashMap(); for (PsiMethod method : containingClass.getAllMethods()) { if (GroovyPropertyUtils.isSimplePropertySetter(method)) { - if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isStaticsOK(method, call)) { + if (PsiUtil.isStaticsOK(method, call)) { final String name = GroovyPropertyUtils.getPropertyNameBySetter(method); if (name != null && !writableProperties.containsKey(name)) { writableProperties.put(name, method); @@ -538,28 +491,6 @@ public class GroovyCompletionContributor extends CompletionContributor { } } - - private static boolean checkForInnerClass(PsiClass psiClass, PsiElement identifierCopy) { - return !PsiUtil.isInnerClass(psiClass) || - org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil - .hasEnclosingInstanceInScope(psiClass.getContainingClass(), identifierCopy, true); - } - - private static void addExpectedType(final CompletionResultSet result, final PsiType type, final PsiElement place) { - if (!JavaCompletionUtil.hasAccessibleConstructor(type)) return; - - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass == null) return; - - if (psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) return; - if (!checkForInnerClass(psiClass, place)) return; - - final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), place); - JavaCompletionUtil.setShowFQN(item); - item.setInsertHandler(new AfterNewClassInsertHandler((PsiClassType)type, place)); - result.addElement(item); - } - public void beforeCompletion(@NotNull final CompletionInitializationContext context) { if (context.getCompletionType() == CompletionType.BASIC && context.getFile() instanceof GroovyFile) { if (semicolonNeeded(context)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java index 6321909f292e..ceb96c6eba0c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java @@ -26,20 +26,20 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; +import com.intellij.util.SmartList; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.completion.handlers.AfterNewClassInsertHandler; +import org.jetbrains.plugins.groovy.lang.completion.handlers.ArrayInsertHandler; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; @@ -53,6 +53,7 @@ import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.Arrays; +import java.util.List; import java.util.Set; import static com.intellij.patterns.PlatformPatterns.psiElement; @@ -69,6 +70,8 @@ public class GroovySmartCompletionContributor extends CompletionContributor { GrAssignmentExpression.class), psiElement( GrVariable.class)))); + private static final ElementPattern AFTER_NEW = + psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).andNot(psiElement().afterLeaf(psiElement().withText(PsiKeyword.THROW)))); private static final TObjectHashingStrategy EXPECTED_TYPE_INFO_STRATEGY = new TObjectHashingStrategy() { public int computeHashCode(final TypeConstraint object) { @@ -183,8 +186,76 @@ public class GroovySmartCompletionContributor extends CompletionContributor { } } }); + + extend(CompletionType.SMART, AFTER_NEW, new CompletionProvider() { + protected void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext matchingContext, + @NotNull final CompletionResultSet result) { + final PsiElement identifierCopy = parameters.getPosition(); + final GrExpression expression = PsiTreeUtil.getParentOfType(identifierCopy, GrExpression.class); + if (expression == null) return; + + final Set types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(expression); + for (PsiType type : types) { + if (type instanceof PsiArrayType) { + final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), identifierCopy); + if (item.getObject() instanceof PsiClass) { + JavaCompletionUtil.setShowFQN(item); + } + item.setInsertHandler(new ArrayInsertHandler()); + result.addElement(item); + } + } + + + final List expectedClassTypes = new SmartList(); + + for (PsiType psiType : types) { + if (psiType instanceof PsiClassType) { + PsiType type = JavaCompletionUtil.eliminateWildcards(JavaCompletionUtil.originalize(psiType)); + final PsiClassType classType = (PsiClassType)type; + if (classType.resolve() != null) { + expectedClassTypes.add(classType); + } + } + } + + JavaInheritorsGetter.processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { + public void consume(final PsiType type) { + addExpectedType(result, type, identifierCopy); + } + }); + } + }); + } + @Override + public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { + super.fillCompletionVariants(parameters, result); + } + + private static void addExpectedType(final CompletionResultSet result, final PsiType type, final PsiElement place) { + if (!JavaCompletionUtil.hasAccessibleConstructor(type)) return; + + final PsiClass psiClass = com.intellij.psi.util.PsiUtil.resolveClassInType(type); + if (psiClass == null) return; + + if (psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) return; + if (!checkForInnerClass(psiClass, place)) return; + + final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), place); + JavaCompletionUtil.setShowFQN(item); + item.setInsertHandler(new AfterNewClassInsertHandler((PsiClassType)type, place)); + result.addElement(item); + } + + private static boolean checkForInnerClass(PsiClass psiClass, PsiElement identifierCopy) { + return !com.intellij.psi.util.PsiUtil.isInnerClass(psiClass) || + PsiUtil.hasEnclosingInstanceInScope(psiClass.getContainingClass(), identifierCopy, true); + } + + @Override public void beforeCompletion(@NotNull CompletionInitializationContext context) { if (context.getCompletionType() != CompletionType.SMART) return; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java index c2fb0b745c07..654b85a0a82d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java @@ -440,7 +440,7 @@ public class GrClosureSignatureUtil { @NotNull GrClosableBlock[] closureArguments, final boolean partial) { List innerArgs = new ArrayList(); - boolean hasNamedArgs = namedArgs != null && namedArgs.length > 0; + boolean hasNamedArgs = namedArgs.length > 0; GrClosureParameter[] params = signature.getParameters(); if (hasNamedArgs) { @@ -454,10 +454,12 @@ public class GrClosureSignatureUtil { } } - if (expressionArgs != null) { - for (GrExpression expression : expressionArgs) { - innerArgs.add(new InnerArg(expression.getType(), expression)); + for (GrExpression expression : expressionArgs) { + PsiType type = expression.getType(); + if (expression instanceof GrNewExpression && com.intellij.psi.util.PsiUtil.resolveClassInType(type) == null) { + type = null; } + innerArgs.add(new InnerArg(type, expression)); } for (GrClosableBlock closureArgument : closureArguments) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy index fc130ccb5715..7867af903ed6 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy @@ -68,6 +68,8 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { doSmartTest(); } + public void testSmartAfterNewInCall() throws Throwable { doSmartTest(); } + public void testNamedParametersForApplication() throws Throwable { doVariantableTest("abx", "aby"); } diff --git a/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall.groovy b/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall.groovy new file mode 100644 index 000000000000..f61e84642448 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall.groovy @@ -0,0 +1,2 @@ +def foo(List l) {} +foo(new ArrLi) \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall_after.groovy b/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall_after.groovy new file mode 100644 index 000000000000..f5e5b6c60266 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/SmartAfterNewInCall_after.groovy @@ -0,0 +1,2 @@ +def foo(List l) {} +foo(new ArrayList()) \ No newline at end of file