From b30cd1e7559dac3d83c90567dcf8ab96d6dfbe63 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 22 Sep 2011 20:07:16 +0200 Subject: [PATCH] suggest members of inheritors of expected type (IDEA-74668,IDEA-72992) --- .../intellij/codeInsight/CodeInsightUtil.java | 14 +----- .../BasicExpressionCompletionContributor.java | 6 --- .../completion/JavaCompletionUtil.java | 2 +- .../JavaSmartCompletionContributor.java | 20 ++++++--- .../completion/SmartCompletionDecorator.java | 9 ++-- .../filters/getters/JavaMembersGetter.java | 8 ++-- .../psi/filters/getters/MembersGetter.java | 43 ++++++++++++++++--- .../smartType/InheritorEnumMembers-out.java | 17 ++++++++ .../smartType/InheritorEnumMembers.java | 17 ++++++++ .../smartType/InheritorMembers-out.java | 13 ++++++ .../smartType/InheritorMembers.java | 13 ++++++ .../completion/smartType/NoNewEnum.java | 17 ++++++++ .../completion/SmartTypeCompletionTest.java | 7 +++ .../searches/ClassInheritorsSearch.java | 4 +- .../lang/completion/GroovyMembersGetter.java | 3 +- .../smart/SimpleMethodParameter.groovy | 2 +- 16 files changed, 153 insertions(+), 42 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/NoNewEnum.java diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index 221fbb8c613c..cd343e6a129d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -252,22 +252,10 @@ public class CodeInsightUtil { return CodeInsightUtilBase.preparePsiElementsForWrite(Arrays.asList(elements)); } - public static Set addSubtypes(PsiType psiType, final PsiElement context, - final boolean getRawSubtypes, Condition shortNameCondition) { - final Set result = new HashSet(); - processSubTypes(psiType, context, getRawSubtypes, shortNameCondition, new Consumer() { - @Override - public void consume(PsiType psiType) { - result.add(psiType); - } - }); - return result; - } - public static void processSubTypes(PsiType psiType, final PsiElement context, boolean getRawSubtypes, - Condition shortNameCondition, + @NotNull Condition shortNameCondition, Consumer consumer) { int arrayDim = psiType.getArrayDimensions(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index bb80a1b4a0c5..d3f1663b5f8e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -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)); } 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 60205d07e6e8..c94cce4a3ddb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -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; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 2bf749fde450..4b20892a2569 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -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() { + Consumer noTypeCheck = new Consumer() { 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); + } + } + } } } }); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java index 681e9e700d03..1d7665837910 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java @@ -74,12 +74,15 @@ public class SmartCompletionDecorator extends TailTypeDecorator { Set assignableTyped = new HashSet(); 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()); } } diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java index c6b932ae5016..c2dd4df50d77 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java @@ -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 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 results) { diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java index 515019e516e8..e2b764c28e67 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java @@ -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 results, @Nullable final PsiClass where, final boolean acceptMethods) { if (where == null) return; - + + final List placeClasses = new ArrayList(); + 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 consumer = new Consumer() { + @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 results, final PsiResolveHelper resolveHelper) { final FilterScopeProcessor processor = new FilterScopeProcessor(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; diff --git a/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers-out.java b/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers-out.java new file mode 100644 index 000000000000..5cd194ccb72d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers-out.java @@ -0,0 +1,17 @@ +interface Foo { +} + +enum FooEnum implements Foo { + ONE, TWO; +} + +class Doo { + void doSomething(Foo f) { + } + + void doSomethingElse() { + doSomething(FooEnum.ONE); + } + +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers.java b/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers.java new file mode 100644 index 000000000000..ca1662c3a781 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/InheritorEnumMembers.java @@ -0,0 +1,17 @@ +interface Foo { +} + +enum FooEnum implements Foo { + ONE, TWO; +} + +class Doo { + void doSomething(Foo f) { + } + + void doSomethingElse() { + doSomething(O); + } + +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers-out.java b/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers-out.java new file mode 100644 index 000000000000..e0cc9f8a4cf1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers-out.java @@ -0,0 +1,13 @@ +class Super { +} + +class Sub extends Super { + public static final Super FOO = null; +} + +class Intermediate { + + Super s = Sub.FOO; +} + + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers.java b/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers.java new file mode 100644 index 000000000000..eeff14f5c889 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/InheritorMembers.java @@ -0,0 +1,13 @@ +class Super { +} + +class Sub extends Super { + public static final Super FOO = null; +} + +class Intermediate { + + Super s = F +} + + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoNewEnum.java b/java/java-tests/testData/codeInsight/completion/smartType/NoNewEnum.java new file mode 100644 index 000000000000..ca04da0e7458 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoNewEnum.java @@ -0,0 +1,17 @@ +interface Foo { +} + +enum FooEnum implements Foo { + ONE, TWO; +} + +class Doo { + void doSomething(Foo f) { + } + + void doSomethingElse() { + doSomething(new ); + } + +} + diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 70fa8f17d816..782412884087 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -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(); diff --git a/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java b/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java index 06306f7fad54..8fd17c243324 100644 --- a/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java +++ b/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java @@ -93,7 +93,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory nameCondition) { + boolean includeAnonymous, @NotNull final Condition nameCondition) { myClass = aClass; myScope = scope; myCheckDeep = checkDeep; @@ -107,7 +107,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory getNameCondition() { + @NotNull public Condition getNameCondition() { return myNameCondition; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyMembersGetter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyMembersGetter.java index 850707ba32bb..6c91baddf0a5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyMembersGetter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyMembersGetter.java @@ -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; } diff --git a/plugins/groovy/testdata/groovy/completion/smart/SimpleMethodParameter.groovy b/plugins/groovy/testdata/groovy/completion/smart/SimpleMethodParameter.groovy index 74a5c2daa8f7..0979d493c4fc 100644 --- a/plugins/groovy/testdata/groovy/completion/smart/SimpleMethodParameter.groovy +++ b/plugins/groovy/testdata/groovy/completion/smart/SimpleMethodParameter.groovy @@ -6,4 +6,4 @@ Date d1=new Date() def d2=new Date() String x="ds" -method(d1, x, ) \ No newline at end of file +method(d1, x, d) \ No newline at end of file