From 4ca9fb51977da5609f54965f7531e588012f2185 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Sep 2016 15:44:48 +0200 Subject: [PATCH] java completion: include outer classes into display name and lookup string after new (IDEA-160509) --- .../intellij/codeInsight/CodeInsightUtil.java | 17 +++++----- .../completion/JavaCompletionUtil.java | 4 +-- .../JavaPsiClassReferenceElement.java | 10 +++--- .../codeInsight/lookup/PsiTypeLookupItem.java | 31 +++++++++---------- .../smartType/OuterAfterNew-out.java | 15 +++++++++ .../completion/smartType/OuterAfterNew.java | 15 +++++++++ .../completion/SmartTypeCompletionTest.java | 1 + .../impl/LiftShorterItemsClassifier.java | 11 +++---- 8 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew.java diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index d4f6b17a1b8b..be0920c9ea97 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -21,13 +21,11 @@ import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.lang.Language; import com.intellij.lang.StdLanguages; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -41,6 +39,7 @@ import com.intellij.util.FilteredQuery; import com.intellij.util.Processor; import com.intellij.util.Query; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.JBTreeTraverser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -293,19 +292,17 @@ public class CodeInsightUtil { if (baseClass.hasModifierProperty(PsiModifier.FINAL)) return; if (matcher.getPrefix().length() > 2) { + JBTreeTraverser traverser = new JBTreeTraverser<>(c -> Arrays.asList(c.getInnerClasses())); AllClassesGetter.processJavaClasses(matcher, context.getProject(), scope, psiClass -> { - if (psiClass.isInheritor(baseClass, true)) { - return inheritorsProcessor.process(psiClass); - } - return true; + Iterable inheritors = traverser.withRoot(psiClass).filter(c -> c.isInheritor(baseClass, true)); + return ContainerUtil.process(inheritors, inheritorsProcessor); }); } else { Query baseQuery = ClassInheritorsSearch.search(baseClass, scope, true, true, false); - Query query = new FilteredQuery<>(baseQuery, psiClass -> { - String name = ApplicationManager.getApplication().runReadAction((Computable)psiClass::getName); - return !(psiClass instanceof PsiTypeParameter) && name != null && matcher.prefixMatches(name); - }); + Query query = new FilteredQuery<>(baseQuery, psiClass -> + !(psiClass instanceof PsiTypeParameter) && + ContainerUtil.exists(JavaCompletionUtil.getAllLookupStrings(psiClass), matcher::prefixMatches)); query.forEach(inheritorsProcessor); } } 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 c78cbde20d9e..0f59acc1b9fa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -569,8 +569,8 @@ public class JavaCompletionUtil { return !(constructor instanceof PsiCompiledElement) || !constructor.hasModifierProperty(PsiModifier.PRIVATE); } - public static Set getAllLookupStrings(@NotNull PsiMember member) { - Set allLookupStrings = ContainerUtil.newLinkedHashSet(); + public static LinkedHashSet getAllLookupStrings(@NotNull PsiMember member) { + LinkedHashSet allLookupStrings = ContainerUtil.newLinkedHashSet(); String name = member.getName(); allLookupStrings.add(name); PsiClass containingClass = member.getContainingClass(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java index 74177b08e43a..e5d33f66b920 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java @@ -165,11 +165,11 @@ public class JavaPsiClassReferenceElement extends LookupItem implements } private static String getName(final PsiClass psiClass, final LookupElement item, boolean diamond, @NotNull PsiSubstitutor substitutor) { - if (item instanceof JavaPsiClassReferenceElement) { - String forced = ((JavaPsiClassReferenceElement)item).getForcedPresentableName(); - if (forced != null) { - return forced; - } + String forced = item instanceof JavaPsiClassReferenceElement ? ((JavaPsiClassReferenceElement)item).getForcedPresentableName() : + item instanceof PsiTypeLookupItem ? ((PsiTypeLookupItem)item).getForcedPresentableName() : + null; + if (forced != null) { + return forced; } String name = PsiUtilCore.getName(psiClass); diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index bc10f7eab150..d4d9d1104fc6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -16,8 +16,8 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.completion.*; -import com.intellij.diagnostic.LogMessageEx; import com.intellij.diagnostic.AttachmentFactory; +import com.intellij.diagnostic.LogMessageEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; @@ -35,9 +35,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; /** * @author peter @@ -61,6 +59,7 @@ public class PsiTypeLookupItem extends LookupItem implements TypedLookupItem { @NotNull private final PsiSubstitutor mySubstitutor; private boolean myAddArrayInitializer; private String myLocationString = ""; + private final String myForcedPresentableName; private PsiTypeLookupItem(Object o, @NotNull @NonNls String lookupString, boolean diamond, int bracketsCount, InsertHandler fixer, @NotNull PsiSubstitutor substitutor) { @@ -69,6 +68,7 @@ public class PsiTypeLookupItem extends LookupItem implements TypedLookupItem { myBracketsCount = bracketsCount; myImportFixer = fixer; mySubstitutor = substitutor; + myForcedPresentableName = o instanceof PsiClass && !lookupString.equals(((PsiClass)o).getName()) ? lookupString : null; } @NotNull @@ -84,6 +84,10 @@ public class PsiTypeLookupItem extends LookupItem implements TypedLookupItem { return type; } + @Nullable + public String getForcedPresentableName() { + return myForcedPresentableName; + } public void setIndicateAnonymous(boolean indicateAnonymous) { myIndicateAnonymous = indicateAnonymous; @@ -223,24 +227,19 @@ public class PsiTypeLookupItem extends LookupItem implements TypedLookupItem { if (psiClass != null) { String name = psiClass.getName(); if (name != null) { - final PsiSubstitutor substitutor = classResolveResult.getSubstitutor(); - PsiClass resolved = JavaPsiFacade.getInstance(psiClass.getProject()).getResolveHelper().resolveReferencedClass(name, context); - - Set allStrings = new HashSet<>(); - allStrings.add(name); + String[] allStrings; if (!psiClass.getManager().areElementsEquivalent(resolved, psiClass) && !PsiUtil.isInnerClass(psiClass)) { // inner class name should be shown qualified if its not accessible by single name - PsiClass aClass = psiClass.getContainingClass(); - while (aClass != null && !PsiUtil.isInnerClass(aClass) && aClass.getName() != null) { - name = aClass.getName() + '.' + name; - allStrings.add(name); - aClass = aClass.getContainingClass(); - } + allStrings = ArrayUtil.toStringArray(JavaCompletionUtil.getAllLookupStrings(psiClass)); + } else { + allStrings = new String[]{name}; } + String lookupString = allStrings[allStrings.length - 1]; - PsiTypeLookupItem item = new PsiTypeLookupItem(psiClass, name, diamond, bracketsCount, importFixer, substitutor); - item.addLookupStrings(ArrayUtil.toStringArray(allStrings)); + PsiTypeLookupItem item = new PsiTypeLookupItem(psiClass, lookupString, diamond, bracketsCount, importFixer, + classResolveResult.getSubstitutor()); + item.addLookupStrings(allStrings); return item; } } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew-out.java b/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew-out.java new file mode 100644 index 000000000000..5a7e354e9058 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew-out.java @@ -0,0 +1,15 @@ +public class Test { + + { + new Foo().method(new Outer.Inner()); + } + + static class Outer { + static class Inner implements Intf {} + } + + class Foo { + public void method(Intf inner) {} + } + interface Intf {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew.java b/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew.java new file mode 100644 index 000000000000..6235a6d67d05 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/OuterAfterNew.java @@ -0,0 +1,15 @@ +public class Test { + + { + new Foo().method(new Ou); + } + + static class Outer { + static class Inner implements Intf {} + } + + class Foo { + public void method(Intf inner) {} + } + interface Intf {} +} \ No newline at end of file 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 3aaaeba526f9..80e61f4dd3d1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -1093,6 +1093,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testArrayInitializerBeforeVarargs() throws Throwable { doTest(); } public void testDuplicateMembersFromSuperClass() throws Throwable { doTest(); } public void testInnerAfterNew() throws Throwable { doTest(); } + public void testOuterAfterNew() { doTest(); } public void testEverythingInStringConcatenation() throws Throwable { doTest(); } public void testGetClassWhenClassExpected() { doTest(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java index 2a1c9c061620..09425567705a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java @@ -18,20 +18,19 @@ package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.codeInsight.lookup.Classifier; import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; -import com.intellij.util.Function; import com.intellij.util.ProcessingContext; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FilteringIterator; +import com.intellij.util.containers.FlatteningIterator; +import com.intellij.util.containers.MultiMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import static com.intellij.util.containers.ContainerUtil.newIdentityHashMap; -import static com.intellij.util.containers.ContainerUtil.newIdentityTroveSet; -import static com.intellij.util.containers.ContainerUtil.newTroveMap; +import static com.intellij.util.containers.ContainerUtil.*; /** * @author peter