From c54741df76181a1436405fa877cb55508b4f0c56 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 28 Jun 2012 18:16:03 +0200 Subject: [PATCH] test 2nd basic instead of class name completion: groovy --- ...GlobalMemberNameCompletionContributor.java | 8 +- .../completion/StaticMemberProcessor.java | 10 +-- plugins/groovy/src/META-INF/plugin.xml | 2 +- .../GroovyCompletionContributor.java | 81 ++++++++++++----- .../lang/completion/GroovyInsertHandler.java | 4 +- .../GroovyClassNameCompletionTest.groovy | 88 ++++++++++--------- 6 files changed, 116 insertions(+), 77 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java index 968199205071..cad821ea1fde 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java @@ -5,6 +5,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -34,7 +35,12 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return; } - completeStaticMembers(parameters).processStaticMethodsGlobally(result); + completeStaticMembers(parameters).processStaticMethodsGlobally(result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }); } public static StaticMemberProcessor completeStaticMembers(CompletionParameters parameters) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index 212561c4bc7b..6be9e9da6e98 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -46,17 +46,9 @@ public abstract class StaticMemberProcessor { addIfNotNull(myStaticImportedClasses, psiClass); } - public void processStaticMethodsGlobally(final CompletionResultSet resultSet) { + public void processStaticMethodsGlobally(PrefixMatcher matcher, Consumer consumer) { FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.GLOBAL_MEMBER_NAME); - final Consumer consumer = new Consumer() { - @Override - public void consume(LookupElement element) { - resultSet.addElement(element); - } - }; - - final PrefixMatcher matcher = resultSet.getPrefixMatcher(); final GlobalSearchScope scope = myPosition.getResolveScope(); final PsiShortNamesCache namesCache = PsiShortNamesCache.getInstance(myProject); for (final String methodName : namesCache.getAllMethodNames()) { diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 84ec2b08e529..b85b2acd403d 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -292,7 +292,7 @@ + id="groovyBasic" order="before javaClassName"/> () { @Override @@ -313,6 +312,10 @@ public class GroovyCompletionContributor extends CompletionContributor { GrReferenceElement reference = findGroovyReference(position); if (reference == null) { + if (parameters.getInvocationCount() >= 2) { + result.stopHere(); + addAllClasses(parameters, result.withPrefixMatcher(CompletionUtil.findJavaIdentifierPrefix(parameters)), new InheritorsHolder(parameters.getPosition(), result)); + } return; } @@ -331,6 +334,7 @@ public class GroovyCompletionContributor extends CompletionContributor { GroovySmartCompletionContributor.addExpectedClassMembers(parameters, result); if (isClassNamePossible(position) && JavaCompletionContributor.mayStartClassName(result)) { + result.stopHere(); if (JavaCompletionContributor.mayShowAllClasses(parameters)) { addAllClasses(parameters, result, inheritors); } else { @@ -467,14 +471,16 @@ public class GroovyCompletionContributor extends CompletionContributor { return; } - int priority = assignPriority(lookupElement, qualifierType); - lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType, - PrioritizedLookupElement.withPriority(lookupElement, priority), object); + if (!(object instanceof PsiClass)) { + 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); + staticMembers.put(CompletionUtil.getOriginalOrSelf((PsiModifierListOwner)object), lookupElement); return; } } @@ -487,22 +493,7 @@ public class GroovyCompletionContributor extends CompletionContributor { }); if (qualifier == null) { - completeStaticMembers(parameters).processMembersOfRegisteredClasses(PrefixMatcher.ALWAYS_TRUE, new PairConsumer() { - @Override - public void consume(PsiMember member, PsiClass psiClass) { - if (member instanceof GrAccessorMethod) { - member = ((GrAccessorMethod)member).getProperty(); - } - final String name = member.getName(); - if (name == null || !matcher.prefixMatches(name)) { - staticMembers.remove(member); - return; - } - staticMembers.put(member, createGlobalMemberElement(member, psiClass, true)); - - } - }); - + addStaticMembers(parameters, matcher, staticMembers); } items.addAll(staticMembers.values()); @@ -519,6 +510,47 @@ public class GroovyCompletionContributor extends CompletionContributor { return result; } + private static void addStaticMembers(CompletionParameters parameters, + final PrefixMatcher matcher, + final Map staticMembers) { + StaticMemberProcessor processor = completeStaticMembers(parameters); + if (parameters.getInvocationCount() < 2) { + processor.processMembersOfRegisteredClasses(matcher, new PairConsumer() { + @Override + public void consume(PsiMember member, PsiClass psiClass) { + if (member instanceof GrAccessorMethod) { + member = ((GrAccessorMethod)member).getProperty(); + } + member = CompletionUtil.getOriginalOrSelf(member); + if (staticMembers.containsKey(member)) { + return; + } + final String name = member.getName(); + if (name == null || !matcher.prefixMatches(name)) { + staticMembers.remove(member); + return; + } + staticMembers.put(member, createGlobalMemberElement(member, psiClass, true)); + } + }); + } else if (StringUtil.isNotEmpty(matcher.getPrefix())) { + processor.processStaticMethodsGlobally(matcher, new Consumer() { + @Override + public void consume(LookupElement element) { + PsiMember member = (PsiMember)element.getObject(); + if (member instanceof GrAccessorMethod) { + member = ((GrAccessorMethod)member).getProperty(); + } + member = CompletionUtil.getOriginalOrSelf(member); + if (staticMembers.containsKey(member)) { + return; + } + staticMembers.put(member, element); + } + }); + } + } + private static void showInfo() { if (StringUtil.isEmpty(CompletionService.getCompletionService().getAdvertisementText())) { CompletionService.getCompletionService() @@ -786,7 +818,12 @@ public class GroovyCompletionContributor extends CompletionContributor { if (StringUtil.isEmpty(result.getPrefixMatcher().getPrefix())) return; - completeStaticMembers(parameters).processStaticMethodsGlobally(result); + completeStaticMembers(parameters).processStaticMethodsGlobally(result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }); } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java index 87cc16c0c0b2..8afb57d8c321 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java @@ -66,8 +66,8 @@ public class GroovyInsertHandler implements InsertHandler { } CaretModel caretModel = editor.getCaretModel(); - int offset = context.getStartOffset() + method.getName().length(); - PsiFile file = PsiDocumentManager.getInstance(method.getProject()).getPsiFile(document); + int offset = context.getTailOffset(); + PsiFile file = context.getFile(); assert file != null; PsiElement elementAt = file.findElementAt(context.getStartOffset()); assert elementAt != null; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index 1c6d3b9987ad..39d54e89a519 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -17,18 +17,15 @@ package org.jetbrains.plugins.groovy.completion; import com.intellij.codeInsight.CodeInsightSettings -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.completion.StaticallyImportable -import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementPresentation import com.intellij.codeInsight.lookup.LookupManager -import com.intellij.openapi.command.CommandProcessor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable import org.jetbrains.plugins.groovy.util.TestUtils -import com.intellij.codeInsight.lookup.LookupElementPresentation -import com.intellij.codeInsight.lookup.LookupElement /** * @author Maxim.Medvedev @@ -54,47 +51,47 @@ public class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCa super.tearDown(); } - public void doTest(boolean force) throws Exception { + private void doTest() throws Exception { addClassToProject("a", "FooBar"); myFixture.configureByFile(getTestName(false) + ".groovy"); - CommandProcessor.getInstance().executeCommand(new Runnable(){ - @Override - void run() { - myFixture.complete(CompletionType.CLASS_NAME); - if (force) forceCompletion(); - } - },"xxx", this); + myFixture.complete(CompletionType.CLASS_NAME) myFixture.checkResultByFile(getTestName(false) + "_after.groovy"); } - private void forceCompletion() { - CodeCompletionHandlerBase handler = new CodeCompletionHandlerBase(CompletionType.CLASS_NAME); - handler.invokeCompletion(myFixture.getProject(), myFixture.getEditor()); - final LookupManager instance = LookupManager.getInstance(myFixture.getProject()); - if(instance.getActiveLookup() != null) - instance.forceSelection(Lookup.NORMAL_SELECT_CHAR, 1); - } - private void addClassToProject(@Nullable String packageName, @NotNull String name) throws IOException { myFixture.addClass("package $packageName; public class $name {}"); } - public void testInFieldDeclaration() throws Exception {doTest(false);} - public void testInParameter() throws Exception {doTest(false);} - public void testInImport() throws Exception {doTest(false);} - public void testWhenClassExistsInSamePackage() throws Exception {doTest(true);} - public void testInComment() throws Exception {doTest(false);} - public void testInTypeElementPlace() throws Exception {doTest(false);} - public void testWhenImportExists() throws Exception{doTest(false);} + public void testInFieldDeclaration() throws Exception {doTest();} + public void testInParameter() throws Exception {doTest();} + public void testInImport() throws Exception {doTest();} + + public void testWhenClassExistsInSamePackage() throws Exception { + addClassToProject("a", "FooBar") + myFixture.configureByFile(getTestName(false) + ".groovy") + myFixture.complete(CompletionType.CLASS_NAME) + def lookup = LookupManager.getActiveLookup(myFixture.editor) + lookup.currentItem = lookup.items[1] + myFixture.type('\n') + myFixture.checkResultByFile(getTestName(false) + "_after.groovy"); + } + + public void testInComment() throws Exception {doTest();} + public void testInTypeElementPlace() throws Exception {doTest();} + public void testWhenImportExists() throws Exception{doTest();} public void testFinishByDot() throws Exception{ addClassToProject("a", "FooBar"); myFixture.configureByText("a.groovy", "FBa") - myFixture.complete(CompletionType.CLASS_NAME) + complete() myFixture.type '.'.charAt(0) myFixture.checkResult "a.FooBar.a" } - + + private LookupElement[] complete() { + myFixture.complete(CompletionType.BASIC, 2) + } + public void testDelegateBasicToClassName() throws Exception{ addClassToProject("a", "FooBarGooDoo"); myFixture.configureByText("a.groovy", "FBGDa") @@ -119,7 +116,7 @@ class Foo { myFixture.configureByText("a.groovy", """def foo() { abcme }""") - def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + def item = complete()[0] LookupElementPresentation presentation = renderElement(item) assert "Foo.abcmethod1" == presentation.itemText @@ -144,7 +141,7 @@ class Foo { myFixture.configureByText("a.groovy", """def foo() { abcfi }""") - def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + def item = complete()[0] ((StaticallyImportable) item).shouldBeImported = true myFixture.type('\n') myFixture.checkResult """import static Foo.abcfield1 @@ -164,7 +161,7 @@ interface Foo { myFixture.configureByText("a.groovy", """def foo() { abcfi }""") - def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + def item = complete()[0] ((StaticallyImportable) item).shouldBeImported = true myFixture.type('\n') myFixture.checkResult """import static Foo.abcfield1 @@ -183,7 +180,7 @@ class Foo { myFixture.configureByText("a.groovy", """def foo() { abcme }""") - myFixture.complete(CompletionType.CLASS_NAME) + complete() myFixture.checkResult """import foo.Foo def foo() { @@ -203,7 +200,7 @@ import static foo.Foo.anotherMethod anotherMethod() abcmex""") - def element = assertOneElement(myFixture.complete(CompletionType.CLASS_NAME)[0]) + def element = assertOneElement(complete()[0]) LookupElementPresentation presentation = renderElement(element) assert "abcMethod" == presentation.itemText @@ -220,9 +217,7 @@ abcMethod()""" } private LookupElementPresentation renderElement(LookupElement element) { - def presentation = new LookupElementPresentation() - element.renderElement(presentation) - return presentation + return LookupElementPresentation.renderElement(element) } public void testNewClassName() { @@ -244,20 +239,20 @@ new Fxoo()\n""" public void testOnlyAnnotationsAfterAt() { myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}" myFixture.configureByText "a.groovy", "@Abcd" - myFixture.complete(CompletionType.CLASS_NAME) + complete() myFixture.checkResult "@AbcdAnno" } public void testOnlyExceptionsInCatch() { myFixture.addClass "class AbcdClass {}; class AbcdException extends Throwable {}" myFixture.configureByText "a.groovy", "try {} catch (Abcd" - myFixture.complete(CompletionType.CLASS_NAME) + complete() myFixture.checkResult "try {} catch (AbcdException" } public void testClassNameInMultilineString() { myFixture.configureByText "a.groovy", 'def s = """a\nAIOOBE\na"""' - myFixture.complete(CompletionType.CLASS_NAME) + complete() myFixture.checkResult 'def s = """a\njava.lang.ArrayIndexOutOfBoundsException\na"""' } @@ -268,6 +263,13 @@ Zoooox""") assertOneElement(myFixture.completeBasic()) } + public void testClassOnlyOnce() { + myFixture.addClass('class FooBarGoo {}') + myFixture.configureByText('a.groovy', 'FoBaGo') + assert !complete() + myFixture.checkResult('''FooBarGoo''') + } + public void testMethodFromTheSameClass() { myFixture.configureByText("a.groovy", """ class A { @@ -278,7 +280,9 @@ class A { } } """) - assert 'foo' == renderElement(myFixture.complete(CompletionType.CLASS_NAME)[0]).itemText + def items = complete() + def fooItem = items.find { renderElement(it).itemText == 'foo' } + LookupManager.getActiveLookup(myFixture.editor).currentItem = fooItem myFixture.type '\n' myFixture.checkResult ''' class A {