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 499a309000ed..da527247e91f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -60,6 +60,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.NullableFunction; import com.intellij.util.PairConsumer; import com.intellij.util.PairFunction; +import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.HashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; @@ -668,29 +669,34 @@ public class JavaCompletionUtil { public static LookupItem qualify(final LookupItem ret) { if (!(ret instanceof JavaMethodCallElement)) { - final PsiMember completionElement = (PsiMember)ret.getObject(); - String prefix = ""; - PsiClass containingClass = completionElement.getContainingClass(); - while (containingClass != null) { - final String className = containingClass.getName(); - if (className == null) { - break; - } - - prefix = className + "." + prefix; - final PsiElement parent = containingClass.getParent(); - if (!(parent instanceof PsiClass)) { - break; - } - containingClass = (PsiClass)parent; - } - if (StringUtil.isNotEmpty(prefix)) { - ret.setLookupString(prefix + ret.getLookupString()); + for (String s : getAllLookupStrings((PsiMember)ret.getObject())) { + ret.setLookupString(s); } } return ret.forceQualify(); } + public static Set getAllLookupStrings(@NotNull PsiMember member) { + Set allLookupStrings = CollectionFactory.linkedHashSet(); + String name = member.getName(); + allLookupStrings.add(name); + PsiClass containingClass = member.getContainingClass(); + while (containingClass != null) { + final String className = containingClass.getName(); + if (className == null) { + break; + } + name = className + "." + name; + allLookupStrings.add(name); + final PsiElement parent = containingClass.getParent(); + if (!(parent instanceof PsiClass)) { + break; + } + containingClass = (PsiClass)parent; + } + return allLookupStrings; + } + public static LookupItem setShowFQN(final LookupItem ret) { final PsiClass psiClass = (PsiClass)ret.getObject(); @NonNls String packageName = PsiFormatUtil.getPackageDisplayName(psiClass); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java index 2cc6240c91c0..aaa79fdaf40e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java @@ -10,6 +10,7 @@ import com.intellij.psi.PsiSubstitutor; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Set; import static com.intellij.util.ObjectUtils.assertNotNull; @@ -56,6 +57,11 @@ public class JavaGlobalMemberLookupElement extends LookupElement implements Stat return assertNotNull(getObject().getName()); } + @Override + public Set getAllLookupStrings() { + return JavaCompletionUtil.getAllLookupStrings(getObject()); + } + @Override public void renderElement(LookupElementPresentation presentation) { presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index a6146234abc5..7afa0f12b04b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -448,7 +448,7 @@ public class GroovyCompletionContributor extends CompletionContributor { staticMembers.remove(member); return; } - staticMembers.put(member, new JavaGlobalMemberLookupElement(member, psiClass, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER, true)); + staticMembers.put(member, createGlobalMemberElement(member, psiClass, true)); } }); @@ -482,8 +482,7 @@ public class GroovyCompletionContributor extends CompletionContributor { @NotNull @Override protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull PsiClass containingClass, boolean shouldImport) { - return new JavaGlobalMemberLookupElement(member, containingClass, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER, - shouldImport); + return createGlobalMemberElement(member, containingClass, shouldImport); } @Override @@ -528,6 +527,11 @@ public class GroovyCompletionContributor extends CompletionContributor { return processor; } + static JavaGlobalMemberLookupElement createGlobalMemberElement(PsiMember member, PsiClass containingClass, boolean shouldImport) { + return new JavaGlobalMemberLookupElement(member, containingClass, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER, + shouldImport); + } + public void beforeCompletion(@NotNull final CompletionInitializationContext context) { if (context.getCompletionType() == CompletionType.BASIC && context.getFile() instanceof GroovyFile) { if (semicolonNeeded(context)) { 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 new file mode 100644 index 000000000000..850707ba32bb --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyMembersGetter.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.completion; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.*; +import com.intellij.psi.filters.getters.MembersGetter; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +/** +* @author peter +*/ +class GroovyMembersGetter extends MembersGetter { + private final PsiClassType myExpectedType; + private final GroovyPsiElement myContext; + + GroovyMembersGetter(PsiClassType expectedType, PsiElement context) { + myExpectedType = expectedType; + myContext = (GroovyPsiElement)context; + } + + public void processMembers(final Consumer results) { + processMembers(myContext, results, myExpectedType.resolve(), PsiTreeUtil.getParentOfType(myContext, GrAnnotation.class) != null); + } + + @Override + protected LookupElement createFieldElement(PsiField field) { + if (!TypesUtil.isAssignable(myExpectedType, field.getType(), myContext)) { + return null; + } + + return GroovyCompletionContributor.createGlobalMemberElement(field, field.getContainingClass(), false); + } + + @Override + protected LookupElement createMethodElement(PsiMethod method) { + PsiType type = method.getReturnType(); + if (type == null || !TypesUtil.isAssignable(myExpectedType, type, myContext)) { + return null; + } + + return GroovyCompletionContributor.createGlobalMemberElement(method, method.getContainingClass(), false); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java index dcf4db00f55a..15d5b14fb59f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java @@ -41,6 +41,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.completion.handlers.AfterNewClassInsertHandler; import org.jetbrains.plugins.groovy.lang.completion.handlers.ArrayInsertHandler; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; @@ -137,6 +138,25 @@ public class GroovySmartCompletionContributor extends CompletionContributor { } }); } + + for (TypeConstraint info : infos) { + Consumer consumer = new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }; + PsiType type = info.getType(); + PsiType defType = info.getDefaultType(); + if (type instanceof PsiClassType) { + new GroovyMembersGetter((PsiClassType)type, reference).processMembers(consumer); + } + if (!defType.equals(type) && defType instanceof PsiClassType) { + new GroovyMembersGetter((PsiClassType)defType, reference).processMembers(consumer); + } + } + + } }); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java index 37fedaaa0fc3..b1395b7ef8f0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java @@ -46,6 +46,6 @@ abstract public class GroovyCompletionTestBase extends LightCodeInsightFixtureTe myFixture.complete(CompletionType.SMART); final List list = myFixture.getLookupElementStrings(); assertNotNull(list); - UsefulTestCase.assertSameElements(list, variants); + UsefulTestCase.assertOrderedEquals(list, variants); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy index cbdded09bbcd..17f1f0c22189 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovySmartCompletionTest.groovy @@ -86,6 +86,9 @@ public class GroovySmartCompletionTest extends GroovyCompletionTestBase { public void testDontCompletePrivateMembers() {doSmartCompletion "foo1", "foo2"} + public void testEnumMembersInAssignment() {doSmartCompletion "IN_STOCK", "NOWHERE", "ORDERED" } + public void testEnumMembersInAssignmentInsideEnum() {doSmartCompletion "IN_STOCK", "NOWHERE", "ORDERED", "next", "previous" } + def getFileText(PsiFile file) { return PsiDocumentManager.getInstance(project).getDocument(file).text } diff --git a/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignment.groovy b/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignment.groovy new file mode 100644 index 000000000000..45d662c922ce --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignment.groovy @@ -0,0 +1,15 @@ +public enum ItemStatus { + ORDERED, IN_STOCK, NOWHERE +} + +class Item { + ItemStatus status + + static constraints = { + status nullable: false + } + + def test() { + status = IS + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignmentInsideEnum.groovy b/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignmentInsideEnum.groovy new file mode 100644 index 000000000000..dbe5466a7ef7 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/smart/EnumMembersInAssignmentInsideEnum.groovy @@ -0,0 +1,7 @@ +public enum ItemStatus { + ORDERED, IN_STOCK, NOWHERE; + + def foo() { + ItemStatus status = + } +} \ No newline at end of file