From c56b6edddb574fb9d3a413709bc8da5398125737 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 30 Aug 2010 18:23:48 +0100 Subject: [PATCH] IDEA-43317 Complete static members from classes that are already mentioned in import block as static import (java) --- .../ImportStaticLookupActionProvider.java | 12 +- .../completion/JavaCompletionUtil.java | 8 ++ .../JavaDocCompletionContributor.java | 9 +- .../JavaGlobalMemberLookupElement.java | 17 ++- ...GlobalMemberNameCompletionContributor.java | 44 +++++-- .../completion/JavaMethodCallElement.java | 101 +++++++++++++-- .../completion/StaticMemberProcessor.java | 115 +++++++++++++----- .../completion/StaticallyImportable.java | 12 ++ .../impl/JavaElementLookupRenderer.java | 2 +- .../psi/impl/source/PsiJavaFileBaseImpl.java | 6 +- .../GlobalMemberNameCompletionTest.groovy | 2 +- ...nTest.java => NormalCompletionTest.groovy} | 60 ++++++--- .../GroovyCompletionContributor.java | 4 +- .../GroovyClassNameCompletionTest.groovy | 23 ++-- 14 files changed, 315 insertions(+), 100 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/StaticallyImportable.java rename java/java-tests/testSrc/com/intellij/codeInsight/completion/{NormalCompletionTest.java => NormalCompletionTest.groovy} (94%) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ImportStaticLookupActionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/ImportStaticLookupActionProvider.java index 4fe765adbe0e..4c8e8b878b4a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ImportStaticLookupActionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ImportStaticLookupActionProvider.java @@ -14,19 +14,23 @@ import javax.swing.*; public class ImportStaticLookupActionProvider implements LookupActionProvider { @Override public void fillActions(final LookupElement element, Lookup lookup, Consumer consumer) { - if (!(element instanceof JavaGlobalMemberLookupElement)) { + if (!(element instanceof StaticallyImportable)) { + return; + } + + final StaticallyImportable item = (StaticallyImportable)element; + if (!item.canBeImported()) { return; } - final JavaGlobalMemberLookupElement item = (JavaGlobalMemberLookupElement)element; final Icon checkIcon = Icons.CHECK_ICON; - final Icon icon = item.isShouldImport() ? checkIcon : new EmptyIcon(checkIcon.getIconWidth(), checkIcon.getIconHeight()); + final Icon icon = item.willBeImported() ? checkIcon : new EmptyIcon(checkIcon.getIconWidth(), checkIcon.getIconHeight()); consumer.consume(new LookupElementAction(icon, "Import statically") { @Override public Result performLookupAction() { FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.IMPORT_STATIC); - item.setShouldImport(!item.isShouldImport()); + item.setShouldBeImported(!item.willBeImported()); return Result.REFRESH_ITEM; } }); 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 3ddd53cdc621..0b5c57bebf91 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -59,6 +59,7 @@ import com.intellij.psi.util.*; import com.intellij.psi.xml.XmlToken; import com.intellij.psi.xml.XmlTokenType; import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; import com.intellij.util.NullableFunction; import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; @@ -886,6 +887,13 @@ public class JavaCompletionUtil { } } + JavaGlobalMemberNameCompletionContributor.completeStaticMembers(element).processMethodsOfRegisteredClasses(matcher, new Consumer() { + @Override + public void consume(LookupElement element) { + set.add(element); + } + }); + return set; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index 1a58f978c496..aee7bfbbaa17 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -82,7 +82,13 @@ public class JavaDocCompletionContributor extends CompletionContributor { ((PsiJavaReference) ref).processVariants(processor); for (final CompletionElement _item : processor.getResults()) { - LookupItem item = (LookupItem)LookupItemUtil.objectToLookupItem(_item.getElement()); + final Object element = _item.getElement(); + LookupItem item = element instanceof PsiMethod ? new JavaMethodCallElement((PsiMethod)element) { + @Override + public void handleInsert(InsertionContext context) { + new MethodSignatureInsertHandler().handleInsert(context, this); + } + } : (LookupItem)LookupItemUtil.objectToLookupItem(element); if (onlyConstants) { Object o = item.getObject(); if (!(o instanceof PsiField)) continue; @@ -95,7 +101,6 @@ public class JavaDocCompletionContributor extends CompletionContributor { if (isArg) { item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); } - item.setInsertHandler(new MethodSignatureInsertHandler()); result.addElement(item); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java index 95b3f99a3fdb..57340cae05e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; /** * @author peter */ -public class JavaGlobalMemberLookupElement extends LookupElement { +public class JavaGlobalMemberLookupElement extends LookupElement implements StaticallyImportable { private final PsiMethod myMethod; private final PsiClass myContainingClass; private final InsertHandler myQualifiedInsertion; @@ -77,12 +77,19 @@ public class JavaGlobalMemberLookupElement extends LookupElement { } } - public boolean isShouldImport() { - return myShouldImport; + @Override + public void setShouldBeImported(boolean shouldImportStatic) { + myShouldImport = shouldImportStatic; } - public void setShouldImport(boolean shouldImport) { - myShouldImport = shouldImport; + @Override + public boolean canBeImported() { + return true; + } + + @Override + public boolean willBeImported() { + return myShouldImport; } @Override 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 a80c659fc0da..bd035b15048a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java @@ -1,8 +1,12 @@ 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; /** * @author peter @@ -13,6 +17,9 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib @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 @@ -26,6 +33,9 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib @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()); } @@ -53,18 +63,34 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return; } - final StaticMemberProcessor processor = new StaticMemberProcessor(); - final PsiFile file = position.getContainingFile(); - if (file instanceof PsiJavaFile) { - final PsiImportList importList = ((PsiJavaFile)file).getImportList(); - if (importList != null) { - for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) { - processor.importMembersOf(statement.resolveTargetClass()); + completeStaticMembers(position).processStaticMethodsGlobally(result); + } + + public static StaticMemberProcessor completeStaticMembers(final PsiElement position) { + final StaticMemberProcessor processor = new StaticMemberProcessor(position, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_METHOD_INSERT_HANDLER) { + @NotNull + @Override + protected LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport) { + final JavaMethodCallElement element = new JavaMethodCallElement(method, true); + element.setShouldBeImported(shouldImport); + return element; + } + }; + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + final PsiFile file = position.getContainingFile(); + if (file instanceof PsiJavaFile) { + final PsiImportList importList = ((PsiJavaFile)file).getImportList(); + if (importList != null) { + for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) { + processor.importMembersOf(statement.resolveTargetClass()); + } + } } } - } + }); - processor.processStaticMethods(result, position, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_METHOD_INSERT_HANDLER); + return processor; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index ad2d0e1e9628..7cfd3511725e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -17,30 +17,43 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.simple.PsiMethodInsertHandler; +import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer; +import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.codeInsight.lookup.TypedLookupItem; +import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer; import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiSubstitutor; -import com.intellij.psi.PsiType; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; /** * @author peter */ -public class JavaMethodCallElement extends LookupItem implements TypedLookupItem { +public class JavaMethodCallElement extends LookupItem implements TypedLookupItem, StaticallyImportable { private static final Key INFERENCE_SUBSTITUTOR = Key.create("INFERENCE_SUBSTITUTOR"); + private final PsiClass myContainingClass; + private final PsiMethod myMethod; + private final boolean myCanImportStatic; + private boolean myShouldImportStatic; - public JavaMethodCallElement(PsiMethod method) { + public JavaMethodCallElement(@NotNull PsiMethod method) { + this(method, false); + } + + public JavaMethodCallElement(PsiMethod method, boolean canImportStatic) { super(method, method.getName()); + myMethod = method; + myContainingClass = method.getContainingClass(); + myCanImportStatic = canImportStatic; PsiType type = method.getReturnType(); setTailType(PsiType.VOID.equals(type) ? TailType.SEMICOLON : TailType.NONE); - setInsertHandler(PsiMethodInsertHandler.INSTANCE); } public PsiType getType() { return getSubstitutor().substitute(getInferenceSubstitutor().substitute(getObject().getReturnType())); - } public void setInferenceSubstitutor(@NotNull final PsiSubstitutor substitutor) { @@ -49,17 +62,81 @@ public class JavaMethodCallElement extends LookupItem implements Type @NotNull public PsiSubstitutor getSubstitutor() { - final PsiSubstitutor substitutor = (PsiSubstitutor)getAttribute(LookupItem.SUBSTITUTOR); + final PsiSubstitutor substitutor = (PsiSubstitutor)getAttribute(SUBSTITUTOR); return substitutor == null ? PsiSubstitutor.EMPTY : substitutor; } - public void setSubstitutor(@NotNull PsiSubstitutor substitutor) { - setAttribute(SUBSTITUTOR, substitutor); - } - @NotNull public PsiSubstitutor getInferenceSubstitutor() { final PsiSubstitutor substitutor = getAttribute(INFERENCE_SUBSTITUTOR); return substitutor == null ? PsiSubstitutor.EMPTY : substitutor; } + + @Override + public void setShouldBeImported(boolean shouldImportStatic) { + assert myCanImportStatic; + myShouldImportStatic = shouldImportStatic; + } + + @Override + public boolean canBeImported() { + return myCanImportStatic; + } + + @Override + public boolean willBeImported() { + return myShouldImportStatic; + } + + @Override + public void handleInsert(InsertionContext context) { + PsiMethodInsertHandler.INSTANCE.handleInsert(context, this); + if (myCanImportStatic) { + final int startOffset = context.getStartOffset(); + final PsiFile file = context.getFile(); + PsiDocumentManager.getInstance(file.getProject()).commitDocument(context.getDocument()); + if (myShouldImportStatic) { + final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiReferenceExpression.class, false); + if (ref != null) { + ref.bindToElementViaStaticImport(myContainingClass); + } + } else { + context.getDocument().insertString(startOffset, "."); + JavaCompletionUtil.insertClassReference(myContainingClass, file, startOffset); + } + } + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + final String className = myContainingClass.getName(); + + presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); + + final String methodName = myMethod.getName(); + final boolean qualify = myCanImportStatic && !myShouldImportStatic || getAttribute(FORCE_QUALIFY) != null; + if (qualify && StringUtil.isNotEmpty(className)) { + presentation.setItemText(className + "." + methodName); + } else { + presentation.setItemText(methodName); + } + + presentation.setStrikeout(JavaElementLookupRenderer.isToStrikeout(this)); + presentation.setItemTextBold(getAttribute(HIGHLIGHTED_ATTR) != null); + + + final String params = PsiFormatUtil.formatMethod(myMethod, PsiSubstitutor.EMPTY, + PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE); + if (myShouldImportStatic && StringUtil.isNotEmpty(className)) { + presentation.setTailText(params + " in " + className); + } else { + presentation.setTailText(params); + } + + final PsiType type = myMethod.getReturnType(); + if (type != null) { + presentation.setTypeText(getSubstitutor().substitute(type).getPresentableText()); + } + } } 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 be16e0ae433f..e5a0103f360a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -1,15 +1,16 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -22,26 +23,43 @@ import static com.intellij.util.containers.ContainerUtil.addIfNotNull; */ public 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) { + myPosition = position; + myQualifiedInsert = qualifiedInsert; + myImportInsert = importInsert; + myProject = myPosition.getProject(); + myResolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); + } public void importMembersOf(@Nullable PsiClass psiClass) { addIfNotNull(myStaticImportedClasses, psiClass); } - public void processStaticMethods(final CompletionResultSet resultSet, - final PsiElement position, - final InsertHandler qualifiedInsert, - final InsertHandler importInsert) { - PrefixMatcher matcher = resultSet.getPrefixMatcher(); - final Project project = position.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final PsiShortNamesCache namesCache = JavaPsiFacade.getInstance(project).getShortNamesCache(); - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper(); + public void processStaticMethodsGlobally(final CompletionResultSet resultSet) { + final Consumer consumer = new Consumer() { + @Override + public void consume(LookupElement element) { + resultSet.addElement(element); + } + }; + + final PrefixMatcher matcher = resultSet.getPrefixMatcher(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); + final PsiShortNamesCache namesCache = JavaPsiFacade.getInstance(myProject).getShortNamesCache(); final String[] methodNames = ApplicationManager.getApplication().runReadAction(new Computable() { public String[] compute() { return namesCache.getAllMethodNames(); } }); - final boolean[] hintShown = {false}; for (final String methodName : methodNames) { if (matcher.prefixMatches(methodName)) { final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable() { @@ -49,33 +67,64 @@ public class StaticMemberProcessor { return namesCache.getMethodsByName(methodName, scope); } }); - ContainerUtil.process(methods, new ReadActionProcessor() { - @Override - public boolean processInReadAction(PsiMethod method) { - if (method.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(method, position, null)) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - if (!JavaCompletionUtil.isInExcludedPackage(containingClass) && !StaticImportMethodFix.isExcluded(method)) { - if (!hintShown[0] && - FeatureUsageTracker.getInstance().isToBeShown(JavaCompletionFeatures.IMPORT_STATIC, project) && - CompletionService.getCompletionService().getAdvertisementText() == null) { - final String shortcut = CompletionContributor.getActionShortcut("EditorRight"); - if (shortcut != null) { - CompletionService.getCompletionService().setAdvertisementText("To import the method statically, press " + shortcut); - } - hintShown[0] = true; - } + for (final PsiMethod method : methods) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + processMethod(method, consumer); + } + }); - final boolean shouldImport = myStaticImportedClasses.contains(containingClass); - resultSet.addElement(new JavaGlobalMemberLookupElement(method, containingClass, qualifiedInsert, importInsert, shouldImport)); - } + } + } + } + } - } + public void processMethodsOfRegisteredClasses(@Nullable final PrefixMatcher matcher, final Consumer consumer) { + for (final PsiClass psiClass : myStaticImportedClasses) { + final PsiMethod[] classMethods = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiMethod[] compute() { + return psiClass.getAllMethods(); + } + }); + for (final PsiMethod method : classMethods) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (matcher == null || matcher.prefixMatches(method.getName())) { + processMethod(method, consumer); } - return true; } }); } } } + + + private void processMethod(final PsiMethod method, final Consumer consumer) { + if (method.hasModifierProperty(PsiModifier.STATIC) && myResolveHelper.isAccessible(method, myPosition, null)) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass != null) { + if (!JavaCompletionUtil.isInExcludedPackage(containingClass) && !StaticImportMethodFix.isExcluded(method)) { + final boolean shouldImport = myStaticImportedClasses.contains(containingClass); + if (!myHintShown && + !shouldImport && + FeatureUsageTracker.getInstance().isToBeShown(JavaCompletionFeatures.IMPORT_STATIC, myProject) && + CompletionService.getCompletionService().getAdvertisementText() == null) { + final String shortcut = CompletionContributor.getActionShortcut("EditorRight"); + if (shortcut != null) { + CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); + } + myHintShown = true; + } + + consumer.consume(createLookupElement(method, containingClass, shouldImport)); + } + + } + } + } + + @NotNull + protected LookupElement createLookupElement(@NotNull PsiMethod method, @NotNull PsiClass containingClass, boolean shouldImport) { + return new JavaGlobalMemberLookupElement(method, containingClass, myQualifiedInsert, myImportInsert, shouldImport); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticallyImportable.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticallyImportable.java new file mode 100644 index 000000000000..801edc49a52b --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticallyImportable.java @@ -0,0 +1,12 @@ +package com.intellij.codeInsight.completion; + +/** + * @author peter + */ +public interface StaticallyImportable { + void setShouldBeImported(boolean shouldImportStatic); + + boolean canBeImported(); + + boolean willBeImported(); +} diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java b/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java index 048986abc4b0..38a6a844c22c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java @@ -218,7 +218,7 @@ public class JavaElementLookupRenderer implements ElementLookupRenderer { return CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_AFTER_COMMA; } - private static boolean isToStrikeout(LookupItem item) { + public static boolean isToStrikeout(LookupItem item) { final List allMethods = item.getUserData(JavaCompletionUtil.ALL_METHODS_ATTRIBUTE); if (allMethods != null){ for (PsiMethod method : allMethods) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java index 498473e25a0d..e76bf12b3857 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source; +import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.lang.StdLanguages; @@ -309,15 +310,16 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava if(rootPackage != null) rootPackage.processDeclarations(processor, state, null, place); } - // todo[dsl] class processing final PsiImportList importList = getImportList(); final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements(); if (importStaticStatements.length > 0) { final StaticImportFilteringProcessor staticImportProcessor = new StaticImportFilteringProcessor(processor, null); + boolean forCompletion = name == null && processor.getHint(JavaCompletionProcessor.NAME_FILTER) != null; + // single member processing for (PsiImportStaticStatement importStaticStatement : importStaticStatements) { - if (!importStaticStatement.isOnDemand()) { + if (!importStaticStatement.isOnDemand() && !forCompletion) { final String referenceName = importStaticStatement.getReferenceName(); final PsiClass targetElement = importStaticStatement.resolveTargetClass(); if (targetElement != null) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index abe06e20675b..282ad8814f1c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -103,7 +103,7 @@ class Bar {{ abcmethod1() }}""" def item = assertOneElement(myFixture.complete(CompletionType.CLASS_NAME)) if (importStatic) { - item.'as'(JavaGlobalMemberLookupElement).shouldImport = true + item.'as'(StaticallyImportable).shouldBeImported = true } myFixture.type('\n') myFixture.checkResult output diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy similarity index 94% rename from java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.java rename to java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index b55a7eb8ec1a..79e8afefae4f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1,20 +1,17 @@ package com.intellij.codeInsight.completion; -import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.CodeInsightSettings; -import com.intellij.codeInsight.lookup.Lookup; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; - -import java.util.Arrays; -import java.util.List; +import com.intellij.JavaTestUtil +import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupManager +import com.intellij.psi.CommonClassNames +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiMethod +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.psi.codeStyle.CodeStyleSettingsManager public class NormalCompletionTest extends LightFixtureCompletionTestCase { @Override @@ -282,11 +279,11 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testMethodWithLeftParTailType() throws Exception { configureByFile("MethodWithLeftParTailType.java"); - selectItem(myItems[0], '('); + type('('); checkResultByFile("MethodWithLeftParTailType_after.java"); configureByFile("MethodWithLeftParTailType2.java"); - selectItem(myItems[0], '('); + type('('); checkResultByFile("MethodWithLeftParTailType2_after.java"); } @@ -296,7 +293,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { try { configureByFile(getTestName(false) + ".java"); - selectItem(myItems[0], '('); + type('('); checkResultByFile(getTestName(false) + "_after.java"); } finally { @@ -371,7 +368,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testFinishWithDot() throws Throwable { configureByFile(getTestName(false) + ".java"); - selectItem(myItems[0], '.'); + type('.'); checkResultByFile(getTestName(false) + "_after.java"); } @@ -652,4 +649,31 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { assertStringItems("myField1", "myField2"); } + public void testSuggestMembersOfStaticallyImportedClasses() throws Exception { + myFixture.addClass("""package foo; + public class Foo { + public static void foo() {} + public static void bar() {} + } + """) + myFixture.configureByText("a.java", """ + import static foo.Foo.foo; + + class Bar {{ + foo(); + ba + }} + """) + complete() + myFixture.checkResult """ + import static foo.Foo.bar; + import static foo.Foo.foo; + + class Bar {{ + foo(); + bar(); + }} + """ + } + } 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 98f400d6174e..edf0b7cab223 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 @@ -361,7 +361,7 @@ 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(); + 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()) { @@ -381,7 +381,7 @@ public class GroovyCompletionContributor extends CompletionContributor { } } } - processor.processStaticMethods(result, position, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER); + processor.processStaticMethodsGlobally(result); } }); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyClassNameCompletionTest.groovy index 1fad921bdb2f..1c049def885d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyClassNameCompletionTest.groovy @@ -15,17 +15,18 @@ */ package org.jetbrains.plugins.groovy; -import com.intellij.codeInsight.CodeInsightSettings; -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.codeInsight.lookup.Lookup; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.TestLookupManager; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; + +import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase +import com.intellij.codeInsight.completion.CompletionType +import com.intellij.codeInsight.completion.StaticallyImportable +import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupManager +import com.intellij.codeInsight.lookup.impl.TestLookupManager +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable import org.jetbrains.plugins.groovy.util.TestUtils -import com.intellij.codeInsight.completion.JavaGlobalMemberLookupElement; /** * @author Maxim.Medvedev @@ -116,7 +117,7 @@ class Foo { }""") myFixture.configureByText("a.groovy", "abcme") def item = myFixture.complete(CompletionType.CLASS_NAME)[0] - ((JavaGlobalMemberLookupElement) item).shouldImport = true + ((StaticallyImportable) item).shouldBeImported = true myFixture.type('\n') myFixture.checkResult """import static Foo.abcmethod1