suggest members of inheritors of expected type (IDEA-74668,IDEA-72992)

This commit is contained in:
peter
2011-09-23 16:14:26 +02:00
parent 7015caaa54
commit b30cd1e755
16 changed files with 153 additions and 42 deletions
@@ -252,22 +252,10 @@ public class CodeInsightUtil {
return CodeInsightUtilBase.preparePsiElementsForWrite(Arrays.asList(elements));
}
public static Set<PsiType> addSubtypes(PsiType psiType, final PsiElement context,
final boolean getRawSubtypes, Condition<String> shortNameCondition) {
final Set<PsiType> result = new HashSet<PsiType>();
processSubTypes(psiType, context, getRawSubtypes, shortNameCondition, new Consumer<PsiType>() {
@Override
public void consume(PsiType psiType) {
result.add(psiType);
}
});
return result;
}
public static void processSubTypes(PsiType psiType,
final PsiElement context,
boolean getRawSubtypes,
Condition<String> shortNameCondition,
@NotNull Condition<String> shortNameCondition,
Consumer<PsiType> consumer) {
int arrayDim = psiType.getArrayDimensions();
@@ -23,7 +23,6 @@ import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.ClassLiteralGetter;
import com.intellij.psi.filters.getters.JavaMembersGetter;
import com.intellij.psi.filters.getters.ThisGetter;
import com.intellij.psi.scope.BaseScopeProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
@@ -85,11 +84,6 @@ public class BasicExpressionCompletionContributor {
final PsiElement parent = position.getParent();
if (parent != null && !(parent.getParent() instanceof PsiSwitchLabelStatement)) {
new JavaMembersGetter(expectedType).addMembers(parameters.getPosition(), result);
if (!parameters.getDefaultType().equals(expectedType)) {
new JavaMembersGetter(parameters.getDefaultType()).addMembers(parameters.getPosition(), result);
}
for (final PsiExpression expression : ThisGetter.getThisExpressionVariants(position)) {
result.consume(new ExpressionLookupItem(expression));
}
@@ -601,7 +601,7 @@ public class JavaCompletionUtil {
if (type instanceof PsiArrayType) return true;
final PsiClass psiClass = PsiUtil.resolveClassInType(type);
if (psiClass == null) return false;
if (psiClass == null || psiClass.isEnum() || psiClass.isAnnotationType()) return false;
if (!(psiClass instanceof PsiCompiledElement)) return true;
@@ -26,10 +26,7 @@ import com.intellij.psi.filters.ElementExtractorFilter;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.filters.GeneratorFilter;
import com.intellij.psi.filters.OrFilter;
import com.intellij.psi.filters.getters.CastTypeGetter;
import com.intellij.psi.filters.getters.ExpectedTypesGetter;
import com.intellij.psi.filters.getters.InstanceOfLeftPartTypeGetter;
import com.intellij.psi.filters.getters.ThrowsListGetter;
import com.intellij.psi.filters.getters.*;
import com.intellij.psi.filters.types.AssignableFromFilter;
import com.intellij.psi.filters.types.AssignableGroupFilter;
import com.intellij.psi.filters.types.AssignableToFilter;
@@ -209,12 +206,23 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
}
}
}, result.getPrefixMatcher());
ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, new Consumer<LookupElement>() {
Consumer<LookupElement> noTypeCheck = new Consumer<LookupElement>() {
public void consume(final LookupElement lookupElement) {
result.addElement(decorate(lookupElement, _infos));
}
});
};
ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, noTypeCheck);
PsiElement position = parameters.getPosition();
if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) {
final PsiElement parent = position.getParent();
if (parent != null && !(parent.getParent() instanceof PsiSwitchLabelStatement)) {
new JavaMembersGetter(type).addMembers(position, noTypeCheck);
if (!parameters.getDefaultType().equals(type)) {
new JavaMembersGetter(parameters.getDefaultType()).addMembers(position, noTypeCheck);
}
}
}
}
}
});
@@ -74,12 +74,15 @@ public class SmartCompletionDecorator extends TailTypeDecorator<LookupElement> {
Set<TailType> assignableTyped = new HashSet<TailType>();
for (ExpectedTypeInfo info : myExpectedTypeInfos) {
final PsiType infoType = info.getType();
final PsiType originalInfoType = JavaCompletionUtil.originalize(infoType);
if (PsiType.VOID.equals(infoType)) {
voidTyped.add(info.getTailType());
} else if (infoType.equals(type)) {
} else if (infoType.equals(type) || originalInfoType.equals(type)) {
sameTyped.add(info.getTailType());
} else if ((infoType.isAssignableFrom(type) && info.getKind() == ExpectedTypeInfo.TYPE_OR_SUBTYPE) ||
(type.isAssignableFrom(infoType) && info.getKind() == ExpectedTypeInfo.TYPE_OR_SUPERTYPE)) {
} else if ((info.getKind() == ExpectedTypeInfo.TYPE_OR_SUBTYPE &&
(infoType.isAssignableFrom(type) || originalInfoType.isAssignableFrom(type))) ||
(info.getKind() == ExpectedTypeInfo.TYPE_OR_SUPERTYPE &&
(type.isAssignableFrom(infoType) || type.isAssignableFrom(originalInfoType)))) {
assignableTyped.add(info.getTailType());
}
}
@@ -35,16 +35,16 @@ public class JavaMembersGetter extends MembersGetter {
private final PsiType myExpectedType;
public JavaMembersGetter(@NotNull PsiType expectedType) {
myExpectedType = expectedType;
myExpectedType = JavaCompletionUtil.originalize(expectedType);
}
public void addMembers(PsiElement position, Consumer<LookupElement> results) {
final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType);
processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null);
if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) {
addConstantsFromTargetClass(position, results);
}
final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType);
processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null);
}
private void addConstantsFromTargetClass(PsiElement position, Consumer<LookupElement> results) {
@@ -15,18 +15,24 @@
*/
package com.intellij.psi.filters.getters;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.filters.TrueFilter;
import com.intellij.psi.scope.processor.FilterScopeProcessor;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author ik
* @author peter
@@ -35,20 +41,47 @@ public abstract class MembersGetter {
public void processMembers(@NotNull final PsiElement context, final Consumer<LookupElement> results, @Nullable final PsiClass where, final boolean acceptMethods) {
if (where == null) return;
final List<PsiClass> placeClasses = new ArrayList<PsiClass>();
PsiClass current = PsiTreeUtil.getContextOfType(context, PsiClass.class);
while (current != null) {
current = CompletionUtil.getOriginalOrSelf(current);
if (InheritanceUtil.isInheritorOrSelf(current, where, true)) {
return;
}
placeClasses.add(current);
current = PsiTreeUtil.getContextOfType(current, PsiClass.class);
}
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
PsiClassType baseType = JavaPsiFacade.getElementFactory(where.getProject()).createType(where);
Consumer<PsiType> consumer = new Consumer<PsiType>() {
@Override
public void consume(PsiType psiType) {
PsiClass psiClass = PsiUtil.resolveClassInType(psiType);
if (psiClass != null) {
psiClass = CompletionUtil.getOriginalOrSelf(psiClass);
for (PsiClass placeClass : placeClasses) {
if (InheritanceUtil.isInheritorOrSelf(placeClass, where, true)) {
return;
}
}
processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper);
}
}
};
consumer.consume(baseType);
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(where.getQualifiedName())) {
CodeInsightUtil.processSubTypes(baseType, context, true, Condition.TRUE, consumer);
}
}
private void processClassDeclaredMembers(PsiClass where,
PsiElement context,
boolean acceptMethods,
Consumer<LookupElement> results, final PsiResolveHelper resolveHelper) {
final FilterScopeProcessor<PsiElement> processor = new FilterScopeProcessor<PsiElement>(TrueFilter.INSTANCE);
where.processDeclarations(processor, ResolveState.initial(), null, context);
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
for (final PsiElement result : processor.getResults()) {
if (result instanceof PsiMember && !(result instanceof PsiClass)) {
final PsiMember member = (PsiMember)result;
@@ -0,0 +1,17 @@
interface Foo {
}
enum FooEnum implements Foo {
ONE, TWO;
}
class Doo {
void doSomething(Foo f) {
}
void doSomethingElse() {
doSomething(FooEnum.ONE);<caret>
}
}
@@ -0,0 +1,17 @@
interface Foo {
}
enum FooEnum implements Foo {
ONE, TWO;
}
class Doo {
void doSomething(Foo f) {
}
void doSomethingElse() {
doSomething(O<caret>);
}
}
@@ -0,0 +1,13 @@
class Super {
}
class Sub extends Super {
public static final Super FOO = null;
}
class Intermediate {
Super s = Sub.FOO;<caret>
}
@@ -0,0 +1,13 @@
class Super {
}
class Sub extends Super {
public static final Super FOO = null;
}
class Intermediate {
Super s = F<caret>
}
@@ -0,0 +1,17 @@
interface Foo {
}
enum FooEnum implements Foo {
ONE, TWO;
}
class Doo {
void doSomething(Foo f) {
}
void doSomethingElse() {
doSomething(new <caret>);
}
}
@@ -1010,8 +1010,15 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
doItemTest();
}
public void testInheritorMembers() throws Throwable { doTest(); }
public void testInheritorEnumMembers() throws Throwable { doTest(); }
public void testDuplicateMembersFromSuperClass() throws Throwable { doTest(); }
public void testNoNewEnum() throws Throwable {
configureByTestName();
assertStringItems("Foo");
}
public void testDuplicateMembersFromSuperClassInAnotherFile() throws Throwable {
myFixture.addClass("class Super { public static final Super FOO = null; }");
doTest();
@@ -93,7 +93,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
}
public SearchParameters(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance,
boolean includeAnonymous, final Condition<String> nameCondition) {
boolean includeAnonymous, @NotNull final Condition<String> nameCondition) {
myClass = aClass;
myScope = scope;
myCheckDeep = checkDeep;
@@ -107,7 +107,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
return myClass;
}
public Condition<String> getNameCondition() {
@NotNull public Condition<String> getNameCondition() {
return myNameCondition;
}
@@ -15,6 +15,7 @@
*/
package org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.MembersGetter;
@@ -32,7 +33,7 @@ class GroovyMembersGetter extends MembersGetter {
private final GroovyPsiElement myContext;
GroovyMembersGetter(PsiClassType expectedType, PsiElement context) {
myExpectedType = expectedType;
myExpectedType = JavaCompletionUtil.originalize(expectedType);
myContext = (GroovyPsiElement)context;
}
@@ -6,4 +6,4 @@ Date d1=new Date()
def d2=new Date()
String x="ds"
method(d1, x, <caret>)
method(d1, x, d<caret>)