diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java index bd035b15048a..3b62d8d9ec37 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java @@ -1,11 +1,8 @@ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.TailType; -import com.intellij.codeInsight.completion.simple.PsiMethodInsertHandler; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; /** @@ -13,34 +10,6 @@ import org.jetbrains.annotations.NotNull; */ public class JavaGlobalMemberNameCompletionContributor extends CompletionContributor { - private static final InsertHandler STATIC_METHOD_INSERT_HANDLER = new InsertHandler() { - @Override - public void handleInsert(InsertionContext context, JavaGlobalMemberLookupElement item) { - PsiMethodInsertHandler.INSTANCE.handleInsert(context, item); - if (item.getObject().getReturnType() == PsiType.VOID) { - TailType.SEMICOLON.processTail(context.getEditor(), context.getTailOffset()); - } - final PsiClass containingClass = item.getContainingClass(); - PsiDocumentManager.getInstance(containingClass.getProject()).commitDocument(context.getDocument()); - final PsiReferenceExpression ref = PsiTreeUtil - .findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false); - if (ref != null) { - ref.bindToElementViaStaticImport(containingClass); - } - } - }; - private static final InsertHandler QUALIFIED_METHOD_INSERT_HANDLER = new InsertHandler() { - @Override - public void handleInsert(InsertionContext context, JavaGlobalMemberLookupElement item) { - PsiMethodInsertHandler.INSTANCE.handleInsert(context, item); - if (item.getObject().getReturnType() == PsiType.VOID) { - TailType.SEMICOLON.processTail(context.getEditor(), context.getTailOffset()); - } - context.getDocument().insertString(context.getStartOffset(), "."); - JavaCompletionUtil.insertClassReference(item.getContainingClass(), context.getFile(), context.getStartOffset()); - } - }; - @Override public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) { if (parameters.getCompletionType() != CompletionType.CLASS_NAME) { @@ -67,7 +36,7 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib } public static StaticMemberProcessor completeStaticMembers(final PsiElement position) { - final StaticMemberProcessor processor = new StaticMemberProcessor(position, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_METHOD_INSERT_HANDLER) { + final StaticMemberProcessor processor = new StaticMemberProcessor(position) { @NotNull @Override protected LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index e5a0103f360a..19236cf93232 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -21,21 +21,15 @@ import static com.intellij.util.containers.ContainerUtil.addIfNotNull; /** * @author peter */ -public class StaticMemberProcessor { +public abstract class StaticMemberProcessor { private final Set myStaticImportedClasses = hashSet(); private final PsiElement myPosition; - private final InsertHandler myQualifiedInsert; - private final InsertHandler myImportInsert; private final Project myProject; private final PsiResolveHelper myResolveHelper; private boolean myHintShown = false; - public StaticMemberProcessor(final PsiElement position, - final InsertHandler qualifiedInsert, - final InsertHandler importInsert) { + public StaticMemberProcessor(final PsiElement position) { myPosition = position; - myQualifiedInsert = qualifiedInsert; - myImportInsert = importInsert; myProject = myPosition.getProject(); myResolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); } @@ -124,7 +118,5 @@ public class StaticMemberProcessor { } @NotNull - protected LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport) { - return new JavaGlobalMemberLookupElement(method, containingClass, myQualifiedInsert, myImportInsert, shouldImport); - } + protected abstract LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport); } diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionResultSet.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionResultSet.java index f2a93de7a63b..4100eee3f3ed 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionResultSet.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionResultSet.java @@ -48,7 +48,7 @@ public abstract class CompletionResultSet { } } - public void addAll(@NotNull final Iterable elements) { + public void addAllElements(@NotNull final Iterable elements) { for (LookupElement element : elements) { addElement(element); } 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 edf0b7cab223..f3618c56a3fa 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 @@ -73,6 +73,7 @@ import java.util.Map; import java.util.Set; import static com.intellij.patterns.PlatformPatterns.psiElement; +import static com.intellij.util.containers.CollectionFactory.hashMap; import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.skipWhitespaces; /** @@ -144,11 +145,29 @@ public class GroovyCompletionContributor extends CompletionContributor { final PsiElement position = parameters.getPosition(); final PsiElement reference = position.getParent(); if (reference instanceof GrReferenceElement) { + final Map staticMethods = hashMap(); + ((GrReferenceElement)reference).processVariants(new Consumer() { public void consume(Object element) { - result.addElement(element instanceof PsiClass ? AllClassesGetter.createLookupItem((PsiClass)element) : GroovyCompletionUtil.getLookupElement(element)); + final LookupElement lookupElement = element instanceof PsiClass + ? AllClassesGetter.createLookupItem((PsiClass)element) + : GroovyCompletionUtil.getLookupElement(element); + if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) { + staticMethods.put((PsiMethod)element, lookupElement); + } else { + result.addElement(lookupElement); + } } }); + + completeStaticMembers(position).processMethodsOfRegisteredClasses(result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + staticMethods.remove(element.getObject()); + } + }); + result.addAllElements(staticMethods.values()); } } }); @@ -361,29 +380,39 @@ public class GroovyCompletionContributor extends CompletionContributor { final String s = result.getPrefixMatcher().getPrefix(); if (StringUtil.isEmpty(s) || !Character.isLowerCase(s.charAt(0))) return; - final StaticMemberProcessor processor = new StaticMemberProcessor(position, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER); - final PsiFile file = position.getContainingFile(); - if (file instanceof GroovyFile) { - for (GrImportStatement statement : ((GroovyFile)file).getImportStatements()) { - if (statement.isStatic()) { - GrCodeReferenceElement importReference = statement.getImportReference(); - if (importReference != null) { - if (!statement.isOnDemand()) { - importReference = importReference.getQualifier(); - } - if (importReference != null) { - final PsiElement target = importReference.resolve(); - if (target instanceof PsiClass) { - processor.importMembersOf((PsiClass)target); - } - } + completeStaticMembers(position).processStaticMethodsGlobally(result); + } + }); + } + + private static StaticMemberProcessor completeStaticMembers(PsiElement position) { + final StaticMemberProcessor processor = new StaticMemberProcessor(position) { + @NotNull + @Override + protected LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport) { + return new JavaGlobalMemberLookupElement(method, containingClass, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER, shouldImport); + } + }; + final PsiFile file = position.getContainingFile(); + if (file instanceof GroovyFile) { + for (GrImportStatement statement : ((GroovyFile)file).getImportStatements()) { + if (statement.isStatic()) { + GrCodeReferenceElement importReference = statement.getImportReference(); + if (importReference != null) { + if (!statement.isOnDemand()) { + importReference = importReference.getQualifier(); + } + if (importReference != null) { + final PsiElement target = importReference.resolve(); + if (target instanceof PsiClass) { + processor.importMembersOf((PsiClass)target); } } } } - processor.processStaticMethodsGlobally(result); } - }); + } + return processor; } private static void addPropertiesForClass(CompletionResultSet result, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index 0b3906d41147..35a6f001530c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.UserDataCache; import com.intellij.openapi.util.text.StringUtil; @@ -30,7 +29,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.ElementBase; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.file.impl.FileManagerImpl; -import com.intellij.psi.scope.BaseScopeProcessor; +import com.intellij.psi.scope.DelegatingScopeProcessor; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubElement; @@ -139,14 +138,9 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { final String expectedName = ResolveUtil.getNameHint(processor); - PsiScopeProcessor importProcessor = !processClasses || expectedName == null ? processor : new BaseScopeProcessor() { + PsiScopeProcessor importProcessor = !processClasses || expectedName == null ? processor : new DelegatingScopeProcessor(processor) { public boolean execute(PsiElement element, ResolveState state) { - return isImplicitlyImported(element, expectedName) || processor.execute(element, state); - } - - @Override - public T getHint(Key hintKey) { - return processor.getHint(hintKey); + return isImplicitlyImported(element, expectedName) || super.execute(element, state); } }; for (GrImportStatement importStatement : getImportStatements()) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy similarity index 94% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy index 2d15fd3c67de..f5c7f2afedf1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.groovy @@ -237,4 +237,28 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { public void testSmartCastCompletion() {doSmartTest();} public void testSmartCastCompletionWithoutRParenth() {doSmartTest();} public void testSmartCastCompletionWithRParenth() {doSmartTest();} + + public void testWhenSiblingIsStaticallyImported() throws Exception { + myFixture.addFileToProject "foo/Foo.groovy", """package foo + class Foo { + static def abcMethod() {} + static def defMethod() {} + } + """ + + myFixture.configureByText("a.groovy", """ + import static foo.Foo.abcMethod + + abdMethod() + defM + """) + myFixture.completeBasic() + myFixture.checkResult """ + import static foo.Foo.abcMethod + import static foo.Foo.defMethod + + abdMethod() + defMethod() + """ + } } \ No newline at end of file