diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index a4bd0d23b8d2..d1e14e6d7c36 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -158,9 +158,11 @@ public class AllClassesGetter { }).forEach(new Processor() { public boolean process(PsiClass psiClass) { assert psiClass != null; - if (isSuitable(context, packagePrefix, qnames, psiClass, filterByScope, pkgContext)) { - qnames.add(psiClass.getQualifiedName()); - consumer.consume(psiClass); + if (isAcceptableInContext(context, psiClass, filterByScope, pkgContext)) { + String qName = psiClass.getQualifiedName(); + if (qName != null && qName.startsWith(packagePrefix) && qnames.add(qName)) { + consumer.consume(psiClass); + } } return true; } @@ -181,9 +183,9 @@ public class AllClassesGetter { return j > 0 ? prefix.substring(0, j) : ""; } - private static boolean isSuitable(@NotNull final PsiElement context, final String packagePrefix, final Set qnames, - @NotNull final PsiClass psiClass, - final boolean filterByScope, final boolean pkgContext) { + public static boolean isAcceptableInContext(@NotNull final PsiElement context, + @NotNull final PsiClass psiClass, + final boolean filterByScope, final boolean pkgContext) { ProgressManager.checkCanceled(); if (!context.isValid() || !psiClass.isValid()) return false; @@ -191,9 +193,7 @@ public class AllClassesGetter { if (JavaCompletionUtil.isInExcludedPackage(psiClass, false)) return false; final String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName == null || !qualifiedName.startsWith(packagePrefix)) return false; - - if (qnames.contains(qualifiedName)) return false; + if (qualifiedName == null) return false; if (!filterByScope && !(psiClass instanceof PsiCompiledElement)) return true; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/InheritorsHolder.java b/java/java-impl/src/com/intellij/codeInsight/completion/InheritorsHolder.java index 63d7105dda62..dccdf8b18d76 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/InheritorsHolder.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/InheritorsHolder.java @@ -44,9 +44,7 @@ public class InheritorsHolder implements Consumer { public void consume(LookupElement lookupElement) { final Object object = lookupElement.getObject(); if (object instanceof PsiClass) { - final PsiClass psiClass = (PsiClass)object; - if (JavaCompletionUtil.hasAccessibleInnerClass(psiClass, myPosition)) return; - registerClass(psiClass); + registerClass((PsiClass)object); } myResult.addElement(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(lookupElement)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index 9015b4cb13c6..056b13af0a89 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -19,12 +19,12 @@ import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.LangBundle; -import com.intellij.lang.StdLanguages; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiJavaElementPattern; -import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; @@ -35,15 +35,18 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import java.util.List; + import static com.intellij.patterns.PsiJavaPatterns.psiElement; /** * @author peter */ public class JavaClassNameCompletionContributor extends CompletionContributor { - private static final PsiJavaElementPattern.Capture AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW); + public static final PsiJavaElementPattern.Capture AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW); private static final PsiJavaElementPattern.Capture IN_TYPE_PARAMETER = psiElement().afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.SUPER, "&").withParent( psiElement(PsiReferenceList.class).withParent(PsiTypeParameter.class)); @@ -92,7 +95,8 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; - if (AFTER_NEW.accepts(insertedElement)) { + final boolean afterNew = AFTER_NEW.accepts(insertedElement); + if (afterNew) { final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { final PsiType type = info.getType(); @@ -104,20 +108,34 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { if (!defaultType.equals(type)) { final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); if (defClass != null) { - consumer.consume(createClassLookupItem(defClass, inJavaContext)); + consumer.consume(createClassLookupItem(defClass, true)); } } } } - final boolean lookingForAnnotations = PsiJavaPatterns.psiElement().afterLeaf("@").accepts(insertedElement); + final boolean lookingForAnnotations = psiElement().afterLeaf("@").accepts(insertedElement); + final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { @Override public void consume(PsiClass psiClass) { if (lookingForAnnotations && !psiClass.isAnnotationType()) return; if (filter.isAcceptable(psiClass, insertedElement)) { - consumer.consume(createClassLookupItem(psiClass, inJavaContext)); + if (!inJavaContext) { + consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); + } else { + for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return filter.isAcceptable(psiClass, insertedElement) && + AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext); + } + })) { + consumer.consume(element); + } + } } } }); @@ -128,6 +146,31 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { : AllClassesGetter.TRY_SHORTENING); } + public static List createClassLookupItems(final PsiClass psiClass, + boolean withInners, + InsertHandler insertHandler, + Condition condition) { + List result = new SmartList(); + if (condition.value(psiClass)) { + result.add(AllClassesGetter.createLookupItem(psiClass, insertHandler)); + } + String name = psiClass.getName(); + if (withInners && name != null) { + for (PsiClass inner : psiClass.getInnerClasses()) { + if (inner.hasModifierProperty(PsiModifier.STATIC)) { + for (JavaPsiClassReferenceElement lookupInner : createClassLookupItems(inner, withInners, insertHandler, condition)) { + String forced = lookupInner.getForcedPresentableName(); + lookupInner.setForcedPresentableName(name + "." + (forced != null ? forced : inner.getName())); + result.add(lookupInner); + } + } + } + } + return result; + } + + + @Override public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) { if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; @@ -145,6 +188,6 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters) { return parameters.getCompletionType() == CompletionType.CLASS_NAME && parameters.getInvocationCount() == 1 && - parameters.getOriginalFile().getLanguage() == StdLanguages.JAVA; + parameters.getOriginalFile().getLanguage().isKindOf(JavaLanguage.INSTANCE); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index 0cb4dbe86e39..0a56c5aa0f38 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -32,9 +32,6 @@ import com.intellij.psi.filters.FilterPositionUtil; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.containers.hash.HashSet; - -import java.util.Set; /** * @author peter @@ -91,8 +88,9 @@ class JavaClassNameInsertHandler implements InsertHandler expectedTypes = new HashSet(); for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiExpression)prevElement.getParent(), true)) { - expectedTypes.add(info.getType()); + if (info.getType() instanceof PsiArrayType) { + return false; + } } - return JavaCompletionUtil.isDefinitelyExpected(psiClass, expectedTypes, position); + return true; } return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index f090725bc856..6e0274599cf1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -31,6 +31,7 @@ import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; @@ -282,12 +283,14 @@ public class JavaCompletionContributor extends CompletionContributor { final Set usedWords = new HashSet(); final PsiElement position = parameters.getPosition(); final boolean checkAccess = parameters.getInvocationCount() <= 1; + final boolean isSwitchLabel = SWITCH_LABEL.accepts(position); + final boolean isAfterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position); + final boolean pkgContext = JavaCompletionUtil.inSomePackage(position); LegacyCompletionContributor.processReferences(parameters, result, new PairConsumer() { public void consume(final PsiReference reference, final CompletionResultSet result) { if (reference instanceof PsiJavaReference) { final ElementFilter filter = getReferenceFilter(position); if (filter != null) { - final boolean isSwitchLabel = SWITCH_LABEL.accepts(position); final PsiFile originalFile = parameters.getOriginalFile(); for (LookupElement element : JavaCompletionUtil.processJavaReference(position, (PsiJavaReference)reference, @@ -332,11 +335,17 @@ public class JavaCompletionContributor extends CompletionContributor { result.addElement((LookupElement)completion); } else if (completion instanceof PsiClass) { - if (!inheritors.alreadyProcessed((PsiClass)completion)) { - JavaPsiClassReferenceElement item = JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true); + for (JavaPsiClassReferenceElement item : JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion, isAfterNew, + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return !inheritors.alreadyProcessed(psiClass) && JavaCompletionUtil.isSourceLevelAccessible(position, psiClass, pkgContext); + } + })) { usedWords.add(item.getLookupString()); result.addElement(item); } + } else { LookupElement element = LookupItemUtil.objectToLookupItem(completion); 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 791f298c74a0..cd91b1a1d50f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -69,10 +69,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static com.intellij.patterns.PlatformPatterns.psiElement; @@ -450,8 +447,7 @@ public class JavaCompletionUtil { final Set mentioned = new THashSet(); for (CompletionElement completionElement : processor.getResults()) { - LookupElement item = createLookupElement(completionElement, javaReference); - if (item != null) { + for (LookupElement item : createLookupElements(completionElement, javaReference)) { item.putUserData(QUALIFIER_TYPE_ATTR, qualifierType); final Object o = item.getObject(); if (o instanceof PsiClass && !isSourceLevelAccessible(element, (PsiClass)o, pkgContext)) { @@ -604,25 +600,33 @@ public class JavaCompletionUtil { }), 1); } - private static LookupElement createLookupElement(CompletionElement completionElement, PsiJavaReference reference) { + private static List createLookupElements(CompletionElement completionElement, PsiJavaReference reference) { Object completion = completionElement.getElement(); assert !(completion instanceof LookupElement); - if (completion instanceof PsiMethod && - reference instanceof PsiJavaCodeReferenceElement && - ((PsiJavaCodeReferenceElement)reference).getParent() instanceof PsiImportStaticStatement) { - return JavaLookupElementBuilder.forMethod((PsiMethod)completion, PsiSubstitutor.EMPTY); + if (reference instanceof PsiJavaCodeReferenceElement) { + if (completion instanceof PsiMethod && + ((PsiJavaCodeReferenceElement)reference).getParent() instanceof PsiImportStaticStatement) { + return Arrays.asList(JavaLookupElementBuilder.forMethod((PsiMethod)completion, PsiSubstitutor.EMPTY)); + } + + if (completion instanceof PsiClass) { + return JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion, + JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference), + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, + Condition.TRUE); + } } LookupElement _ret = LookupItemUtil.objectToLookupItem(completion); - if (_ret == null || !(_ret instanceof LookupItem)) return null; + if (_ret == null || !(_ret instanceof LookupItem)) return Collections.emptyList(); final PsiSubstitutor substitutor = completionElement.getSubstitutor(); if (substitutor != null) { ((LookupItem)_ret).setAttribute(LookupItem.SUBSTITUTOR, substitutor); } - return _ret; + return Arrays.asList(_ret); } public static boolean hasAccessibleConstructor(PsiType type) { @@ -878,19 +882,6 @@ public class JavaCompletionUtil { } } - public static boolean hasAccessibleInnerClass(@NotNull PsiClass psiClass, @NotNull PsiElement position) { - final PsiClass[] inners = psiClass.getInnerClasses(); - if (inners.length > 0) { - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(position.getProject()).getResolveHelper(); - for (PsiClass inner : inners) { - if (inner.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(inner, position, null)) { - return true; - } - } - } - return false; - } - public static boolean inSomePackage(PsiElement context) { PsiFile contextFile = context.getContainingFile(); return contextFile instanceof PsiClassOwner && StringUtil.isNotEmpty(((PsiClassOwner)contextFile).getPackageName()); @@ -914,19 +905,6 @@ public class JavaCompletionUtil { return true; } - public static boolean isDefinitelyExpected(PsiClass psiClass, Set expectedTypes, PsiElement position) { - final PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); - for (PsiType expectedType : expectedTypes) { - if (expectedType instanceof PsiArrayType) return false; - } - for (PsiType type : expectedTypes) { - if (type instanceof PsiClassType && ((PsiClassType)type).rawType().isAssignableFrom(classType)) { - return true; - } - } - return !hasAccessibleInnerClass(psiClass, position); - } - public static boolean promptTypeArgs(InsertionContext context, int offset) { if (offset < 0) { return false; 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 4fe52cfc4f73..c4156d3f4d51 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java @@ -31,6 +31,9 @@ import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.Set; + /** * @author peter */ @@ -38,6 +41,7 @@ public class JavaPsiClassReferenceElement extends LookupItem { public static final ClassConditionKey CLASS_CONDITION_KEY = ClassConditionKey.create(JavaPsiClassReferenceElement.class); private final Object myClass; private final String myQualifiedName; + private String myForcedPresentableName; public JavaPsiClassReferenceElement(PsiClass psiClass) { super(psiClass.getName(), psiClass.getName()); @@ -48,6 +52,32 @@ public class JavaPsiClassReferenceElement extends LookupItem { setTailType(TailType.NONE); } + public String getForcedPresentableName() { + return myForcedPresentableName; + } + + @NotNull + @Override + public String getLookupString() { + if (myForcedPresentableName != null) { + return myForcedPresentableName; + } + return super.getLookupString(); + } + + @Override + public Set getAllLookupStrings() { + if (myForcedPresentableName != null) { + return Collections.singleton(myForcedPresentableName); + } + + return super.getAllLookupStrings(); + } + + public void setForcedPresentableName(String forcedPresentableName) { + myForcedPresentableName = forcedPresentableName; + } + @NotNull @Override public PsiClass getObject() { @@ -126,6 +156,13 @@ public class JavaPsiClassReferenceElement extends LookupItem { } private static String getName(final PsiClass psiClass, final LookupItem item, boolean diamond) { + if (item instanceof JavaPsiClassReferenceElement) { + String forced = ((JavaPsiClassReferenceElement)item).getForcedPresentableName(); + if (forced != null) { + return forced; + } + } + String name = PsiUtilCore.getName(psiClass); if (item.getAttribute(LookupItem.FORCE_QUALIFY) != null) { diff --git a/java/java-tests/testData/codeInsight/completion/className/importAfterNew/after2.java b/java/java-tests/testData/codeInsight/completion/className/importAfterNew/after2.java index 95d797874ffc..1c7cb6f6f2dc 100644 --- a/java/java-tests/testData/codeInsight/completion/className/importAfterNew/after2.java +++ b/java/java-tests/testData/codeInsight/completion/className/importAfterNew/after2.java @@ -2,6 +2,6 @@ import pack.WithInnerAClass; public class Test1 { public void foo() { - new WithInnerAClass + new WithInnerAClass() } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInner_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInner_after.java index 607f6135e5fc..1170812a5513 100644 --- a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInner_after.java +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInner_after.java @@ -1,6 +1,11 @@ class Foo { { - Zzoo l = new Zzoo() + Zzoo l = new Zzoo() { + @Override + public void run() { + //To change body of implemented methods use File | Settings | File Templates. + } + } } } diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java index 240707bdbf6d..868142c0653f 100644 --- a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java @@ -2,7 +2,7 @@ public class TestClass { public TestClass create() { final int value = 1; - return new Xxx(value); + return new Xxx(value); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java index 39c4f1b0cda1..3b52a10ed130 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java @@ -64,6 +64,7 @@ public class ClassNameCompletionTest extends CompletionTestCase { checkResultByFile(path + "/after1.java"); configureByFile(path + "/before2.java"); + selectItem(myItems[0]); checkResultByFile(path + "/after2.java"); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 5272c49a0e1b..cc56df142398 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -24,7 +24,6 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation import com.intellij.codeInsight.lookup.LookupManager import com.intellij.lang.java.JavaLanguage import com.intellij.openapi.actionSystem.IdeActions -import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.fileTypes.StdFileTypes import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.codeStyle.CommonCodeStyleSettings @@ -695,21 +694,15 @@ public class ListUtils { public void _testClassBeforeCast() throws Throwable { doTest '\n' } public void testNoAllClassesOnQualifiedReference() throws Throwable { - configureByFile(getTestName(false) + ".java"); - assertEmpty(myItems); - checkResultByFile(getTestName(false) + ".java"); + doAntiTest() } public void testFinishClassNameWithDot() throws Throwable { - configureByFile(getTestName(false) + ".java"); - type('.'); - checkResult() + doTest('.') } public void testFinishClassNameWithLParen() throws Throwable { - configureByFile(getTestName(false) + ".java"); - type('('); - checkResult() + doTest('(') } public void testSelectNoParameterSignature() throws Throwable { @@ -722,12 +715,7 @@ public class ListUtils { public void testCompletionInsideClassLiteral() throws Throwable { configureByFile(getTestName(false) + ".java"); - new WriteCommandAction.Simple(getProject(), new PsiFile[0]) { - @Override - protected void run() throws Throwable { - getLookup().finishLookup(Lookup.NORMAL_SELECT_CHAR); - } - }.execute().throwException(); + type('\n') checkResult() } @@ -797,18 +785,19 @@ public class ListUtils { } public void testClassNameGenerics() throws Throwable { - configure() - type '\n' - checkResult(); + doTest('\n') } public void testClassNameAnonymous() throws Throwable { - configure() - type '\n' - checkResult(); + doTest('\n') } - public void testClassNameWithInner() throws Throwable { doTest() } + public void testClassNameWithInner() throws Throwable { + configure() + assertStringItems 'Zzoo', 'Zzoo.Impl' + type '\n' + checkResult() + } public void testClassNameWithInner2() throws Throwable { doTest() } public void testClassNameWithInstanceInner() throws Throwable { doTest('\n') } @@ -987,7 +976,7 @@ public class ListUtils { public void testPrimitiveMethodParameter() throws Throwable { doTest(); } - public void testNewExpectedClassParens() throws Throwable { doTest(); } + public void testNewExpectedClassParens() throws Throwable { doTest('\n'); } public void testQualifyInnerMembers() throws Throwable { doTest('\n') } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java index bd7753874d63..a067f7a45b44 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java @@ -145,7 +145,7 @@ public class AutoPopupController implements Disposable { myAlarm.cancelAllRequests(); } - public void autoPopupParameterInfo(final Editor editor, final PsiElement highlightedMethod){ + public void autoPopupParameterInfo(final Editor editor, @Nullable final PsiElement highlightedMethod){ if (ApplicationManager.getApplication().isUnitTestMode()) return; if (DumbService.isDumb(myProject)) return; @@ -168,7 +168,7 @@ public class AutoPopupController implements Disposable { documentManager.commitAllDocuments(); int lbraceOffset = editor.getCaretModel().getOffset() - 1; try { - new ShowParameterInfoHandler().invoke(myProject, editor, file1, lbraceOffset, highlightedMethod); + ShowParameterInfoHandler.invoke(myProject, editor, file1, lbraceOffset, highlightedMethod); } catch (IndexNotReadyException ignored) { //anything can happen on alarm } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java index bb8ee2be533a..c13b8aecec70 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java @@ -18,11 +18,9 @@ package org.jetbrains.plugins.groovy.lang.completion; import com.intellij.codeInsight.completion.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -62,7 +60,7 @@ public class GroovyClassNameInsertHandler implements InsertHandler() { - @Override - public void consume(PsiClass psiClass) { - if (!inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position)) { - consumer.consume(GroovyCompletionUtil.createClassLookupItem(psiClass)); - } - } - }); + final boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position); + AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() <= 1, new Consumer() { + @Override + public void consume(PsiClass psiClass) { + for (JavaPsiClassReferenceElement element : JavaClassNameCompletionContributor + .createClassLookupItems(psiClass, afterNew, new GroovyClassNameInsertHandler(), new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return !inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position); + } + })) { + consumer.consume(element); + } + } + }); } private static ElementFilter getClassFilter(PsiElement position) { @@ -451,52 +458,62 @@ public class GroovyCompletionContributor extends CompletionContributor { final ElementFilter classFilter = getClassFilter(position); + final boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position); final List items = arrayList(); reference.processVariants(matcher, parameters, new Consumer() { public void consume(Object element) { - if (element instanceof PsiClass && inheritorsHolder.alreadyProcessed((PsiClass)element)) { - return; - } - if (element instanceof LookupElement && inheritorsHolder.alreadyProcessed((LookupElement)element)) { - return; - } - - if (element instanceof LookupElement && ((LookupElement)element).getObject() instanceof PsiClass) { - element = ((LookupElement)element).getObject(); - } - - LookupElement lookupElement = element instanceof PsiClass - ? GroovyCompletionUtil.createClassLookupItem(CompletionUtil.getOriginalOrSelf((PsiClass)element)) - : GroovyCompletionUtil.getLookupElement(element); - Object object = lookupElement.getObject(); - if (object instanceof GroovyResolveResult) { - object = ((GroovyResolveResult)object).getElement(); - } - - if (object instanceof GrReferenceExpression && unresolvedProps.contains(((GrReferenceExpression)object).getName())) { - return; - } - - if (object instanceof PsiMember && JavaCompletionUtil.isInExcludedPackage((PsiMember)object, true)) { - return; - } - - int priority = assignPriority(lookupElement, qualifierType); - lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType, - PrioritizedLookupElement.withPriority(lookupElement, priority), object); - - if ((object instanceof PsiMethod || object instanceof PsiField) && - ((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) { - if (lookupElement.getLookupString().equals(((PsiMember)object).getName())) { - staticMembers.put((PsiModifierListOwner)object, lookupElement); + List lookupElements; + if (element instanceof PsiClass) { + if (!matcher.prefixMatches(((PsiClass)element).getName())) { return; } - } - if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) { - return; + + lookupElements = JavaClassNameCompletionContributor + .createClassLookupItems((PsiClass)element, afterNew, new GroovyClassNameInsertHandler(), Condition.TRUE); + } else { + lookupElements = Arrays.asList(GroovyCompletionUtil.getLookupElement(element)); } - items.add(lookupElement); + for (LookupElement lookupElement : lookupElements) { + if (!matcher.prefixMatches(lookupElement)) { + continue; + } + + Object object = lookupElement.getObject(); + if (object instanceof GroovyResolveResult) { + object = ((GroovyResolveResult)object).getElement(); + } + + if (object instanceof PsiClass && inheritorsHolder.alreadyProcessed((PsiClass)object) || + object instanceof LookupElement && inheritorsHolder.alreadyProcessed((LookupElement)object)) { + continue; + } + + if (object instanceof GrReferenceExpression && unresolvedProps.contains(((GrReferenceExpression)object).getName())) { + continue; + } + + if (object instanceof PsiMember && JavaCompletionUtil.isInExcludedPackage((PsiMember)object, true)) { + continue; + } + + int priority = assignPriority(lookupElement, qualifierType); + lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType, + PrioritizedLookupElement.withPriority(lookupElement, priority), object); + + if ((object instanceof PsiMethod || object instanceof PsiField) && + ((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) { + if (lookupElement.getLookupString().equals(((PsiMember)object).getName())) { + staticMembers.put((PsiModifierListOwner)object, lookupElement); + continue; + } + } + if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) { + continue; + } + + items.add(lookupElement); + } } }); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index 288f33e0077f..e09237e7e88a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -216,7 +216,12 @@ public class GroovyCompletionUtil { public static List getCompletionVariants(GroovyResolveResult[] candidates) { List result = CollectionFactory.arrayList(); for (GroovyResolveResult candidate : candidates) { - result.add(createCompletionVariant(candidate)); + if (candidate.getElement() instanceof PsiClass) { + result.add(candidate); + } else { + result.add(createCompletionVariant(candidate)); + } + ProgressManager.checkCanceled(); } @@ -249,9 +254,6 @@ public class GroovyCompletionUtil { else if (element instanceof PsiMethod) { return setupLookupBuilder(element, candidate.getSubstitutor(), LookupElementBuilder.create(candidate, ((PsiMethod)element).getName())); } - if (element instanceof PsiClass) { - return createClassLookupItem((PsiClass)element); - } if (element instanceof PsiNamedElement) { return setupLookupBuilder(element, candidate.getSubstitutor(), diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 1e29d0de3136..95988ee2fb87 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -628,6 +628,7 @@ class A { }""" configure "Zzoo l = new Zz" myFixture.completeBasic() + myFixture.type '\n' myFixture.checkResult "Zzoo l = new Zzoo()" } @@ -738,6 +739,8 @@ format()""" myFixture.addClass "class Fooooo { interface Bar {} }" myFixture.configureByText "a.groovy", "Fooooo f = new Foo" myFixture.completeBasic() + assert myFixture.lookupElementStrings == ['Fooooo', 'Fooooo.Bar'] + myFixture.type '\n' myFixture.checkResult "Fooooo f = new Fooooo()" } @@ -745,7 +748,9 @@ format()""" myFixture.addClass "class Fooooo { interface Bar {} }" myFixture.configureByText "a.groovy", "Fooooo.Bar f = new Foo" myFixture.completeBasic() - myFixture.checkResult "Fooooo.Bar f = new Fooooo" + assert myFixture.lookupElementStrings == ['Fooooo', 'Fooooo.Bar'] + myFixture.type '\n' + myFixture.checkResult "Fooooo.Bar f = new Fooooo()" } public void testOnlyExceptionsInCatch() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.groovy index a8c0e23cb23d..668a28b5619d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.groovy @@ -60,7 +60,7 @@ abstract public class GroovyCompletionTestBase extends LightCodeInsightFixtureTe public void checkSingleItemCompletion(String before, String after) { myFixture.configureByText("a.groovy", before); - myFixture.completeBasic(); + assert !myFixture.completeBasic(); myFixture.checkResult(after); }