IDEA-43317 Complete static members from classes that are already mentioned in import block as static import (groovy)

This commit is contained in:
peter
2010-08-31 12:38:32 +01:00
parent 628df7e2fa
commit 21d9ad4463
6 changed files with 80 additions and 72 deletions
@@ -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<JavaGlobalMemberLookupElement> STATIC_METHOD_INSERT_HANDLER = new InsertHandler<JavaGlobalMemberLookupElement>() {
@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<JavaGlobalMemberLookupElement> QUALIFIED_METHOD_INSERT_HANDLER = new InsertHandler<JavaGlobalMemberLookupElement>() {
@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) {
@@ -21,21 +21,15 @@ import static com.intellij.util.containers.ContainerUtil.addIfNotNull;
/**
* @author peter
*/
public class StaticMemberProcessor {
public abstract class StaticMemberProcessor {
private final Set<PsiClass> myStaticImportedClasses = hashSet();
private final PsiElement myPosition;
private final InsertHandler<JavaGlobalMemberLookupElement> myQualifiedInsert;
private final InsertHandler<JavaGlobalMemberLookupElement> myImportInsert;
private final Project myProject;
private final PsiResolveHelper myResolveHelper;
private boolean myHintShown = false;
public StaticMemberProcessor(final PsiElement position,
final InsertHandler<JavaGlobalMemberLookupElement> qualifiedInsert,
final InsertHandler<JavaGlobalMemberLookupElement> 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);
}
@@ -48,7 +48,7 @@ public abstract class CompletionResultSet {
}
}
public void addAll(@NotNull final Iterable<LookupElement> elements) {
public void addAllElements(@NotNull final Iterable<LookupElement> elements) {
for (LookupElement element : elements) {
addElement(element);
}
@@ -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<PsiMethod, LookupElement> staticMethods = hashMap();
((GrReferenceElement)reference).processVariants(new Consumer<Object>() {
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<LookupElement>() {
@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,
@@ -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> T getHint(Key<T> hintKey) {
return processor.getHint(hintKey);
return isImplicitlyImported(element, expectedName) || super.execute(element, state);
}
};
for (GrImportStatement importStatement : getImportStatements()) {
@@ -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<caret>
""")
myFixture.completeBasic()
myFixture.checkResult """
import static foo.Foo.abcMethod
import static foo.Foo.defMethod
abdMethod()
defMethod()<caret>
"""
}
}