diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index 087332254ec8..91f27452f355 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -26,6 +26,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.tree.IElementType; @@ -326,10 +327,12 @@ public class CodeInsightUtil { if (baseClass.hasModifierProperty(PsiModifier.FINAL)) return; + Set imported = processImportedInheritors(context, baseClass, inheritorsProcessor); + if (matcher.getPrefix().length() > 2) { JBTreeTraverser traverser = JBTreeTraverser.of(PsiClass::getInnerClasses); AllClassesGetter.processJavaClasses(matcher, context.getProject(), scope, psiClass -> { - Iterable inheritors = traverser.withRoot(psiClass).filter(c -> c.isInheritor(baseClass, true)); + Iterable inheritors = traverser.withRoot(psiClass).filter(c -> c.isInheritor(baseClass, true) && !imported.contains(c)); return ContainerUtil.process(inheritors, inheritorsProcessor); }); } @@ -337,11 +340,28 @@ public class CodeInsightUtil { Query baseQuery = ClassInheritorsSearch.search(baseClass, scope, true, true, false); Query query = new FilteredQuery<>(baseQuery, psiClass -> !(psiClass instanceof PsiTypeParameter) && - ContainerUtil.exists(JavaCompletionUtil.getAllLookupStrings(psiClass), matcher::prefixMatches)); + ContainerUtil.exists(JavaCompletionUtil.getAllLookupStrings(psiClass), matcher::prefixMatches) && + !imported.contains(psiClass)); query.forEach(inheritorsProcessor); } } + @NotNull + private static Set processImportedInheritors(PsiElement context, PsiClass baseClass, Processor inheritorsProcessor) { + Set visited = new HashSet<>(); + + context.getContainingFile().getOriginalFile().processDeclarations(new PsiScopeProcessor() { + @Override + public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { + if (element instanceof PsiClass && ((PsiClass)element).isInheritor(baseClass, true) && visited.add((PsiClass)element)) { + return inheritorsProcessor.process((PsiClass)element); + } + return true; + } + }, ResolveState.initial(), null, context); + return visited; + } + private static void addContextTypeArguments(PsiElement context, PsiClassType baseType, Processor inheritorsProcessor) { Set usedNames = ContainerUtil.newHashSet(); PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject()); diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralLookupElement.java b/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralLookupElement.java index 65a0bd9da3b1..04927aa2ac05 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralLookupElement.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralLookupElement.java @@ -32,13 +32,17 @@ import org.jetbrains.annotations.Nullable; /** * @author peter */ -public class ClassLiteralLookupElement extends LookupElement implements TypedLookupItem { +class ClassLiteralLookupElement extends LookupElement implements TypedLookupItem { @NonNls private static final String DOT_CLASS = ".class"; + @Nullable private final SmartPsiElementPointer myClass; private final PsiExpression myExpr; private final String myPresentableText; private final String myCanonicalText; - public ClassLiteralLookupElement(PsiClassType type, PsiElement context) { + ClassLiteralLookupElement(PsiClassType type, PsiElement context) { + PsiClass psiClass = PsiUtil.resolveClassInType(type); + myClass = psiClass == null ? null : SmartPointerManager.createPointer(psiClass); + myCanonicalText = type.getCanonicalText(); myPresentableText = type.getPresentableText(); myExpr = JavaPsiFacade.getInstance(context.getProject()).getElementFactory().createExpressionFromText(myCanonicalText + DOT_CLASS, context); @@ -63,7 +67,7 @@ public class ClassLiteralLookupElement extends LookupElement implements TypedLoo @Nullable @Override public PsiElement getPsiElement() { - return PsiUtil.resolveClassInType(getType()); + return myClass == null ? null : myClass.getElement(); } @NotNull diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ConsiderClassProximityForClassLiterals.java b/java/java-tests/testData/codeInsight/completion/smartType/ConsiderClassProximityForClassLiterals.java new file mode 100644 index 000000000000..5d67d66d1504 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/ConsiderClassProximityForClassLiterals.java @@ -0,0 +1,11 @@ +class X { + + void foo(Class c) { + + } + + { + foo(Str) + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java index 8c7df94b7bd1..c40fae768d8c 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java @@ -275,4 +275,8 @@ public void testConvertToObjectStream() { myFixture.assertPreferredCompletionItems(2, "SortedMap", "NavigableMap", "TreeMap", "ConcurrentNavigableMap", "ConcurrentSkipListMap"); } + public void testConsiderClassProximityForClassLiterals() { + configureByTestName(); + myFixture.assertPreferredCompletionItems(0, "String.class"); + } }