don't suggest expected type members twice when they are statically imported (IDEA-79426)

This commit is contained in:
peter
2011-12-29 16:48:36 +01:00
parent 8484fde96f
commit a48a9f5efe
9 changed files with 81 additions and 27 deletions

View File

@@ -528,7 +528,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) && !BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) &&
!(position.getParent() instanceof PsiLiteralExpression)) { !(position.getParent() instanceof PsiLiteralExpression)) {
for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) {
new JavaMembersGetter(info.getDefaultType(), position).addMembers(position, parameters.getInvocationCount() > 1, new Consumer<LookupElement>() { new JavaMembersGetter(info.getDefaultType(), position).addMembers(parameters, parameters.getInvocationCount() > 1, new Consumer<LookupElement>() {
@Override @Override
public void consume(LookupElement element) { public void consume(LookupElement element) {
result.addElement(element); result.addElement(element);

View File

@@ -356,9 +356,9 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
PsiElement position = params.getPosition(); PsiElement position = params.getPosition();
if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) { if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) {
for (ExpectedTypeInfo info : mergedInfos) { for (ExpectedTypeInfo info : mergedInfos) {
new JavaMembersGetter(info.getType(), position).addMembers(position, !quick, consumer); new JavaMembersGetter(info.getType(), position).addMembers(params, !quick, consumer);
if (!info.getDefaultType().equals(info.getType())) { if (!info.getDefaultType().equals(info.getType())) {
new JavaMembersGetter(info.getDefaultType(), position).addMembers(position, !quick, consumer); new JavaMembersGetter(info.getDefaultType(), position).addMembers(params, !quick, consumer);
} }
} }
} }

View File

@@ -16,10 +16,7 @@
package com.intellij.psi.filters.getters; package com.intellij.psi.filters.getters;
import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.completion.JavaMethodCallElement;
import com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor;
import com.intellij.codeInsight.completion.SmartCompletionDecorator;
import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.codeInsight.lookup.VariableLookupItem;
@@ -47,10 +44,12 @@ public class JavaMembersGetter extends MembersGetter {
myExpectedType = JavaCompletionUtil.originalize(expectedType); myExpectedType = JavaCompletionUtil.originalize(expectedType);
} }
public void addMembers(PsiElement position, boolean searchInheritors, final Consumer<LookupElement> results) { public void addMembers(CompletionParameters parameters, boolean searchInheritors, final Consumer<LookupElement> results) {
final StaticMemberProcessor processor = JavaGlobalMemberNameCompletionContributor.completeStaticMembers(parameters);
final PsiElement position = parameters.getPosition();
if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) { if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) {
addConstantsFromTargetClass(position, results, searchInheritors); addConstantsFromTargetClass(position, results, searchInheritors, processor);
addConstantsFromReferencedClassesInSwitch(position, results); addConstantsFromReferencedClassesInSwitch(position, results, processor);
} }
if (position.getParent().getParent() instanceof PsiSwitchLabelStatement) { if (position.getParent().getParent() instanceof PsiSwitchLabelStatement) {
@@ -58,10 +57,10 @@ public class JavaMembersGetter extends MembersGetter {
} }
final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType); final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType);
processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null, searchInheritors); processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null, searchInheritors, processor);
} }
private void addConstantsFromReferencedClassesInSwitch(PsiElement position, final Consumer<LookupElement> results) { private void addConstantsFromReferencedClassesInSwitch(PsiElement position, final Consumer<LookupElement> results, final StaticMemberProcessor processor) {
final Set<PsiField> fields = ReferenceExpressionCompletionContributor.findConstantsUsedInSwitch(position); final Set<PsiField> fields = ReferenceExpressionCompletionContributor.findConstantsUsedInSwitch(position);
final Set<PsiClass> classes = new HashSet<PsiClass>(); final Set<PsiClass> classes = new HashSet<PsiClass>();
for (PsiField field : fields) { for (PsiField field : fields) {
@@ -76,11 +75,13 @@ public class JavaMembersGetter extends MembersGetter {
results.consume(TailTypeDecorator.withTail(element, TailType.CASE_COLON)); results.consume(TailTypeDecorator.withTail(element, TailType.CASE_COLON));
} }
} }
}, aClass, false, false); }, aClass, false, false, processor);
} }
} }
private void addConstantsFromTargetClass(PsiElement position, Consumer<LookupElement> results, boolean searchInheritors) { private void addConstantsFromTargetClass(PsiElement position,
Consumer<LookupElement> results,
boolean searchInheritors, final StaticMemberProcessor processor) {
PsiElement parent = position.getParent(); PsiElement parent = position.getParent();
if (!(parent instanceof PsiReferenceExpression)) { if (!(parent instanceof PsiReferenceExpression)) {
return; return;
@@ -93,7 +94,8 @@ public class JavaMembersGetter extends MembersGetter {
final IElementType op = binaryExpression.getOperationTokenType(); final IElementType op = binaryExpression.getOperationTokenType();
if (JavaTokenType.EQEQ == op || JavaTokenType.NE == op) { if (JavaTokenType.EQEQ == op || JavaTokenType.NE == op) {
if (prev == binaryExpression.getROperand()) { if (prev == binaryExpression.getROperand()) {
processMembers(position, results, getCalledClass(binaryExpression.getLOperand()), false, searchInheritors); processMembers(position, results, getCalledClass(binaryExpression.getLOperand()), false, searchInheritors,
processor);
} }
return; return;
} }
@@ -101,7 +103,7 @@ public class JavaMembersGetter extends MembersGetter {
parent = parent.getParent(); parent = parent.getParent();
} }
if (parent instanceof PsiExpressionList) { if (parent instanceof PsiExpressionList) {
processMembers(position, results, getCalledClass(parent.getParent()), false, searchInheritors); processMembers(position, results, getCalledClass(parent.getParent()), false, searchInheritors, processor);
} }
} }

View File

@@ -18,6 +18,7 @@ package com.intellij.psi.filters.getters;
import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.completion.StaticMemberProcessor;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Condition;
@@ -28,11 +29,14 @@ import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer; import com.intellij.util.Consumer;
import com.intellij.util.PairConsumer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author ik * @author ik
@@ -40,7 +44,9 @@ import java.util.List;
*/ */
public abstract class MembersGetter { public abstract class MembersGetter {
public void processMembers(@NotNull final PsiElement context, final Consumer<LookupElement> results, @Nullable final PsiClass where, final boolean acceptMethods, boolean searchInheritors) { public void processMembers(@NotNull final PsiElement context, final Consumer<LookupElement> results, @Nullable final PsiClass where,
final boolean acceptMethods, boolean searchInheritors,
StaticMemberProcessor processor) {
if (where == null) return; if (where == null) return;
final List<PsiClass> placeClasses = new ArrayList<PsiClass>(); final List<PsiClass> placeClasses = new ArrayList<PsiClass>();
@@ -51,6 +57,31 @@ public abstract class MembersGetter {
placeClasses.add(current); placeClasses.add(current);
current = PsiTreeUtil.getContextOfType(current, PsiClass.class); current = PsiTreeUtil.getContextOfType(current, PsiClass.class);
} }
final Set<PsiMember> importedStatically = new HashSet<PsiMember>();
processor.processMembersOfRegisteredClasses(null, new PairConsumer<PsiMember, PsiClass>() {
@Override
public void consume(PsiMember member, PsiClass psiClass) {
importedStatically.add(member);
}
});
final Condition<PsiClass> mayProcessMembers = new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
if (psiClass == null) {
return false;
}
psiClass = CompletionUtil.getOriginalOrSelf(psiClass);
for (PsiClass placeClass : placeClasses) {
if (InheritanceUtil.isInheritorOrSelf(placeClass, psiClass, true)) {
return false;
}
}
return true;
}
};
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
@@ -59,14 +90,14 @@ public abstract class MembersGetter {
@Override @Override
public void consume(PsiType psiType) { public void consume(PsiType psiType) {
PsiClass psiClass = PsiUtil.resolveClassInType(psiType); PsiClass psiClass = PsiUtil.resolveClassInType(psiType);
if (psiClass != null) { if (mayProcessMembers.value(psiClass)) {
psiClass = CompletionUtil.getOriginalOrSelf(psiClass); psiClass = CompletionUtil.getOriginalOrSelf(psiClass);
for (PsiClass placeClass : placeClasses) { for (PsiClass placeClass : placeClasses) {
if (InheritanceUtil.isInheritorOrSelf(placeClass, where, true)) { if (InheritanceUtil.isInheritorOrSelf(placeClass, psiClass, true)) {
return; return;
} }
} }
processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper); processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper, importedStatically);
} }
} }
}; };
@@ -79,14 +110,14 @@ public abstract class MembersGetter {
private void processClassDeclaredMembers(PsiClass where, private void processClassDeclaredMembers(PsiClass where,
PsiElement context, PsiElement context,
boolean acceptMethods, boolean acceptMethods,
Consumer<LookupElement> results, final PsiResolveHelper resolveHelper) { Consumer<LookupElement> results, final PsiResolveHelper resolveHelper, final Set<PsiMember> importedStatically) {
final FilterScopeProcessor<PsiElement> processor = new FilterScopeProcessor<PsiElement>(TrueFilter.INSTANCE); final FilterScopeProcessor<PsiElement> processor = new FilterScopeProcessor<PsiElement>(TrueFilter.INSTANCE);
where.processDeclarations(processor, ResolveState.initial(), null, context); where.processDeclarations(processor, ResolveState.initial(), null, context);
for (final PsiElement result : processor.getResults()) { for (final PsiElement result : processor.getResults()) {
if (result instanceof PsiMember && !(result instanceof PsiClass)) { if (result instanceof PsiMember && !(result instanceof PsiClass)) {
final PsiMember member = (PsiMember)result; final PsiMember member = (PsiMember)result;
if (JavaCompletionUtil.isInExcludedPackage(member)) continue; if (JavaCompletionUtil.isInExcludedPackage(member) || importedStatically.contains(member)) continue;
if (member.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(member, context, null)) { if (member.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(member, context, null)) {
if (result instanceof PsiField && !member.hasModifierProperty(PsiModifier.FINAL)) continue; if (result instanceof PsiField && !member.hasModifierProperty(PsiModifier.FINAL)) continue;
if (result instanceof PsiMethod && acceptMethods) continue; if (result instanceof PsiMethod && acceptMethods) continue;

View File

@@ -0,0 +1,12 @@
import static Super.FOO;
class Super {
public static final Super FOO = null;
public static final Super FOX = true;
}
class Intermediate {
Super s = FO<caret>
}

View File

@@ -938,6 +938,11 @@ public class ListUtils {
public void testSuggestExpectedTypeMembersInCall() throws Throwable { doTest('\n') } public void testSuggestExpectedTypeMembersInCall() throws Throwable { doTest('\n') }
public void testExpectedTypesDotSelectsItem() throws Throwable { doTest('.') } public void testExpectedTypesDotSelectsItem() throws Throwable { doTest('.') }
public void testExpectedTypeMembersVersusStaticImports() throws Throwable {
configure()
assertStringItems('FOO', 'FOX')
}
public void testDoubleExpectedTypeFactoryMethod() throws Throwable { public void testDoubleExpectedTypeFactoryMethod() throws Throwable {
configure() configure()
assertStringItems('Key', 'create', 'create') assertStringItems('Key', 'create', 'create')

View File

@@ -552,7 +552,7 @@ public class GroovyCompletionContributor extends CompletionContributor {
} }
} }
private static StaticMemberProcessor completeStaticMembers(CompletionParameters parameters) { static StaticMemberProcessor completeStaticMembers(CompletionParameters parameters) {
final PsiElement position = parameters.getPosition(); final PsiElement position = parameters.getPosition();
final PsiElement originalPosition = parameters.getOriginalPosition(); final PsiElement originalPosition = parameters.getOriginalPosition();
final StaticMemberProcessor processor = new StaticMemberProcessor(position) { final StaticMemberProcessor processor = new StaticMemberProcessor(position) {

View File

@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.plugins.groovy.lang.completion; package org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.*; import com.intellij.psi.*;
@@ -31,14 +32,17 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt
class GroovyMembersGetter extends MembersGetter { class GroovyMembersGetter extends MembersGetter {
private final PsiClassType myExpectedType; private final PsiClassType myExpectedType;
private final GroovyPsiElement myContext; private final GroovyPsiElement myContext;
private final CompletionParameters myParameters;
GroovyMembersGetter(PsiClassType expectedType, PsiElement context) { GroovyMembersGetter(PsiClassType expectedType, PsiElement context, CompletionParameters parameters) {
myParameters = parameters;
myExpectedType = JavaCompletionUtil.originalize(expectedType); myExpectedType = JavaCompletionUtil.originalize(expectedType);
myContext = (GroovyPsiElement)context; myContext = (GroovyPsiElement)context;
} }
public void processMembers(boolean searchInheritors, final Consumer<LookupElement> results) { public void processMembers(boolean searchInheritors, final Consumer<LookupElement> results) {
processMembers(myContext, results, myExpectedType.resolve(), PsiTreeUtil.getParentOfType(myContext, GrAnnotation.class) != null, searchInheritors); processMembers(myContext, results, myExpectedType.resolve(), PsiTreeUtil.getParentOfType(myContext, GrAnnotation.class) != null, searchInheritors,
GroovyCompletionContributor.completeStaticMembers(myParameters));
} }
@Override @Override

View File

@@ -220,10 +220,10 @@ public class GroovySmartCompletionContributor extends CompletionContributor {
PsiType defType = info.getDefaultType(); PsiType defType = info.getDefaultType();
boolean searchInheritors = params.getInvocationCount() > 1; boolean searchInheritors = params.getInvocationCount() > 1;
if (type instanceof PsiClassType) { if (type instanceof PsiClassType) {
new GroovyMembersGetter((PsiClassType)type, reference).processMembers(searchInheritors, consumer); new GroovyMembersGetter((PsiClassType)type, reference, params).processMembers(searchInheritors, consumer);
} }
if (!defType.equals(type) && defType instanceof PsiClassType) { if (!defType.equals(type) && defType instanceof PsiClassType) {
new GroovyMembersGetter((PsiClassType)defType, reference).processMembers(searchInheritors, consumer); new GroovyMembersGetter((PsiClassType)defType, reference, params).processMembers(searchInheritors, consumer);
} }
} }
} }