From 42eebc6127b28d78d91b173cfa7729e86ee5a899 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 24 Jul 2012 10:31:15 +0200 Subject: [PATCH] IDEA-84963 Disprefer annotations in autocomplete at places where they cannot be used --- .../completion/PreferByKindWeigher.java | 53 ++- .../source/tree/java/PsiAnnotationImpl.java | 26 +- .../PreferApplicableAnnotations.java | 12 + .../NormalCompletionOrderingTest.groovy | 4 + .../completion/weighers/GrKindWeigher.java | 369 +++++++++--------- .../annotation/GrAnnotationImpl.java | 2 +- .../completion/GroovyCompletionTest.groovy | 18 + 7 files changed, 287 insertions(+), 197 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normalSorting/PreferApplicableAnnotations.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java index 7e9c4d7a920e..1465616183b2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java @@ -18,16 +18,17 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.openapi.util.Condition; import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.getters.MembersGetter; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -55,26 +56,60 @@ public class PreferByKindWeigher extends LookupElementWeigher { private final CompletionType myCompletionType; private final PsiElement myPosition; private final Set myNonInitializedFields; - @Nullable private final String myRequiredSuper; + @NotNull private final Condition myRequiredSuper; - public PreferByKindWeigher(CompletionType completionType, PsiElement position) { + public PreferByKindWeigher(CompletionType completionType, final PsiElement position) { super("local"); myCompletionType = completionType; myPosition = position; myNonInitializedFields = JavaCompletionProcessor.getNonInitializedFields(position); + myRequiredSuper = createSuitabilityCondition(position); + } + private static Condition createSuitabilityCondition(final PsiElement position) { if (IN_CATCH_TYPE.accepts(position) || IN_MULTI_CATCH_TYPE.accepts(position) || JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(position) || INSIDE_METHOD_THROWS_CLAUSE.accepts(position)) { - myRequiredSuper = CommonClassNames.JAVA_LANG_THROWABLE; + return new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return InheritanceUtil.isInheritor(psiClass, CommonClassNames.JAVA_LANG_THROWABLE); + } + }; } - else if (IN_RESOURCE_TYPE.accepts(position)) { - myRequiredSuper = CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE; + + if (IN_RESOURCE_TYPE.accepts(position)) { + return new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return InheritanceUtil.isInheritor(psiClass, CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE); + } + }; } - else { - myRequiredSuper = null; + + if (psiElement().withParents(PsiJavaCodeReferenceElement.class, PsiAnnotation.class).accepts(position)) { + final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(position, PsiAnnotation.class); + assert annotation != null; + PsiAnnotationOwner owner = annotation.getOwner(); + if (owner instanceof PsiModifierList || owner instanceof PsiTypeElement || + owner instanceof PsiMethodReceiver || owner instanceof PsiTypeParameter) { + PsiElement member = ((PsiElement)owner).getParent(); + final String[] elementTypeFields = PsiAnnotationImpl + .getApplicableElementTypeFields(owner instanceof PsiModifierList ? member : (PsiElement)owner); + return new Condition() { + @Override + public boolean value(PsiClass psiClass) { + if (!psiClass.isAnnotationType()) { + return false; + } + return PsiAnnotationImpl.isAnnotationApplicable(false, psiClass, elementTypeFields, position.getResolveScope()); + } + }; + } } + //noinspection unchecked + return Condition.FALSE; } enum MyResult { @@ -156,7 +191,7 @@ public class PreferByKindWeigher extends LookupElementWeigher { } if (object instanceof PsiClass) { - if (myRequiredSuper != null && InheritanceUtil.isInheritor((PsiClass)object, myRequiredSuper)) { + if (myRequiredSuper.value((PsiClass)object)) { return MyResult.suitableClass; } return MyResult.classNameOrGlobalStatic; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationImpl.java index b6fe75031c4e..047e0182facf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationImpl.java @@ -162,14 +162,17 @@ public class PsiAnnotationImpl extends JavaStubPsiElement imp return !strict; } PsiClass annotationType = (PsiClass)resolved; - return isAnnotationApplicable(strict, annotationType, elementTypeFields, annotation.getManager(), annotation.getResolveScope()); + return isAnnotationApplicable(strict, annotationType, elementTypeFields, annotation.getResolveScope()); } public static boolean isAnnotationApplicable(boolean strict, - PsiClass annotationType, - String[] elementTypeFields, - PsiManager manager, + @NotNull PsiClass annotationType, + @Nullable String[] elementTypeFields, GlobalSearchScope resolveScope) { + if (elementTypeFields == null) { + return !strict; + } + PsiAnnotation target = annotationType.getModifierList().findAnnotation(CommonClassNames.TARGET_ANNOTATION_FQ_NAME); if (target == null) { //todo hack: ambiguity in spec @@ -183,7 +186,8 @@ public class PsiAnnotationImpl extends JavaStubPsiElement imp PsiAnnotationMemberValue value = attributes[0].getValue(); LOG.assertTrue(elementTypeFields.length > 0); - PsiClass elementTypeClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.annotation.ElementType", resolveScope); + PsiClass elementTypeClass = + JavaPsiFacade.getInstance(annotationType.getProject()).findClass("java.lang.annotation.ElementType", resolveScope); if (elementTypeClass == null) { //todo hack return !strict; @@ -192,17 +196,23 @@ public class PsiAnnotationImpl extends JavaStubPsiElement imp for (String fieldName : elementTypeFields) { PsiField field = elementTypeClass.findFieldByName(fieldName, false); - if (field == null) continue; + if (field == null) { + continue; + } if (value instanceof PsiArrayInitializerMemberValue) { PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers(); for (PsiAnnotationMemberValue initializer : initializers) { if (initializer instanceof PsiReference) { - if (((PsiReference)initializer).isReferenceTo(field)) return true; + if (((PsiReference)initializer).isReferenceTo(field)) { + return true; + } } } } else if (value instanceof PsiReference) { - if (((PsiReference)value).isReferenceTo(field)) return true; + if (((PsiReference)value).isReferenceTo(field)) { + return true; + } } } return false; diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferApplicableAnnotations.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferApplicableAnnotations.java new file mode 100644 index 000000000000..75ba46a656f5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferApplicableAnnotations.java @@ -0,0 +1,12 @@ +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Z +@interface Foo { +} + +@Target({ElementType.ANNOTATION_TYPE}) +@interface ZMetaAnno {} + +@Target({ElementType.LOCAL_VARIABLE}) +@interface ZLocalAnno {} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy index a5797213a6c9..aa532f06acb5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -342,6 +342,10 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { checkPreferredItems 0, 'serial', 'superExpressionInIllegalContext' } + public void testPreferApplicableAnnotations() throws Throwable { + checkPreferredItems 0, 'ZMetaAnno', 'ZLocalAnno' + } + public void testJComponentAddNewWithStats() throws Throwable { final LookupImpl lookup = invokeCompletion("/../smartTypeSorting/JComponentAddNew.java"); assertPreferredItems(0, "FooBean3", "JComponent", "Component"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java index 60fb62fa6cbb..36e6063a6ea0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java @@ -1,179 +1,190 @@ -/* - * Copyright 2000-2010 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.weighers; - -import com.intellij.codeInsight.completion.CompletionLocation; -import com.intellij.codeInsight.completion.CompletionWeigher; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -import com.intellij.psi.*; -import com.intellij.psi.impl.light.LightElement; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.containers.CollectionFactory; -import com.intellij.util.containers.hash.HashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor; -import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionContributor; -import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrPropertyForCompletion; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; - -import java.util.Set; - -/** - * @author Maxim.Medvedev - */ -public class GrKindWeigher extends CompletionWeigher { - private static final Set TRASH_CLASSES = new HashSet(10); - private static final Set PRIORITY_KEYWORDS = CollectionFactory.hashSet( - PsiKeyword.RETURN, PsiKeyword.INSTANCEOF, "in", - PsiKeyword.PRIVATE, PsiKeyword.PROTECTED, PsiKeyword.PUBLIC, PsiKeyword.STATIC, "def", - PsiKeyword.TRUE, PsiKeyword.FALSE, PsiKeyword.NULL); - - static { - TRASH_CLASSES.add(CommonClassNames.JAVA_LANG_CLASS); - TRASH_CLASSES.add(CommonClassNames.JAVA_LANG_OBJECT); - TRASH_CLASSES.add(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT); - } - - @Override - public Comparable weigh(@NotNull LookupElement element, @NotNull CompletionLocation location) { - final PsiElement position = location.getCompletionParameters().getPosition(); - if (!(position.getContainingFile() instanceof GroovyFileBase)) return null; - - Object o = element.getObject(); - if (o instanceof ResolveResult) { - o = ((ResolveResult)o).getElement(); - } - - final PsiElement parent = position.getParent(); - final PsiElement qualifier = parent instanceof GrReferenceElement ? ((GrReferenceElement)parent).getQualifier() : null; - if (qualifier == null) { - if (o instanceof NamedArgumentDescriptor) { - switch (((NamedArgumentDescriptor)o).getPriority()) { - case ALWAYS_ON_TOP: - return NotQualifiedKind.onTop; - case AS_LOCAL_VARIABLE: - return NotQualifiedKind.local; - default: - return NotQualifiedKind.unknown; - } - } - if (o instanceof PsiVariable && !(o instanceof PsiField)) { - return NotQualifiedKind.local; - } - - PsiTypeLookupItem item = element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); - if (item != null && item.getBracketsCount() > 0) { - return NotQualifiedKind.arrayType; - } - - if (isPriorityKeyword(o)) return NotQualifiedKind.local; - if (isLightElement(o)) return NotQualifiedKind.unknown; - if (o instanceof PsiClass) { - if (((PsiClass)o).isAnnotationType() && GroovyCompletionContributor.AFTER_AT.accepts(position)) { - return NotQualifiedKind.restrictedClass; - } - if (GroovyCompletionContributor.IN_CATCH_TYPE.accepts(position) && - InheritanceUtil.isInheritor((PsiClass)o, CommonClassNames.JAVA_LANG_THROWABLE)) { - return NotQualifiedKind.restrictedClass; - } - } - if (o instanceof PsiMember) { - final PsiClass containingClass = ((PsiMember)o).getContainingClass(); - if (isAccessor((PsiMember)o)) return NotQualifiedKind.accessor; - if (o instanceof PsiClass && ((PsiClass)o).getContainingClass() == null || o instanceof PsiPackage) return NotQualifiedKind.unknown; - if (o instanceof PsiClass) return NotQualifiedKind.innerClass; - if (PsiTreeUtil.isContextAncestor(containingClass, position, false)) return NotQualifiedKind.currentClassMember; - return NotQualifiedKind.member; - } - return NotQualifiedKind.unknown; - } - else { - if (o instanceof PsiEnumConstant) return QualifiedKind.enumConstant; - - if (isLightElement(o)) return QualifiedKind.unknown; - if (o instanceof PsiMember) { - if (isTrashMethod((PsiMember)o)) return QualifiedKind.unknown; - if (isAccessor((PsiMember)o)) return QualifiedKind.accessor; - if (isQualifierClassMember((PsiMember)o, qualifier)) { - return QualifiedKind.currentClassMember; - } - if (o instanceof PsiClass && ((PsiClass)o).getContainingClass() == null || o instanceof PsiPackage) return QualifiedKind.unknown; - if (o instanceof PsiClass) return QualifiedKind.innerClass; - return QualifiedKind.member; - } - return QualifiedKind.unknown; - } - } - - private static boolean isPriorityKeyword(Object o) { - //noinspection SuspiciousMethodCalls - return PRIORITY_KEYWORDS.contains(o); - } - - private static boolean isLightElement(Object o) { - return o instanceof LightElement && !(o instanceof GrPropertyForCompletion) && !(o instanceof GrAccessorMethod); - } - - private static boolean isTrashMethod(PsiMember o) { - final PsiClass containingClass = o.getContainingClass(); - return containingClass != null && TRASH_CLASSES.contains(containingClass.getQualifiedName()); - } - - private static boolean isAccessor(PsiMember member) { - return member instanceof PsiMethod && (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)member) || "setProperty".equals(((PsiMethod)member).getName())); - } - - - private static boolean isQualifierClassMember(PsiMember member, PsiElement qualifier) { - if (!(qualifier instanceof GrExpression)) return false; - - final PsiType type = ((GrExpression)qualifier).getType(); - if (!(type instanceof PsiClassType)) return false; - - final PsiClass psiClass = ((PsiClassType)type).resolve(); - if (psiClass == null) return false; - - return qualifier.getManager().areElementsEquivalent(member.getContainingClass(), psiClass); - } - - private enum NotQualifiedKind { - arrayType, - innerClass, - unknown, - accessor, - member, - currentClassMember, - restrictedClass, - local, - onTop - } - - private enum QualifiedKind { - innerClass, - unknown, - accessor, - member, - currentClassMember, - enumConstant, - } -} +/* + * Copyright 2000-2010 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.weighers; + +import com.intellij.codeInsight.completion.CompletionLocation; +import com.intellij.codeInsight.completion.CompletionWeigher; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightElement; +import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.CollectionFactory; +import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor; +import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionContributor; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrPropertyForCompletion; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; + +import java.util.Set; + +/** + * @author Maxim.Medvedev + */ +public class GrKindWeigher extends CompletionWeigher { + private static final Set TRASH_CLASSES = new HashSet(10); + private static final Set PRIORITY_KEYWORDS = CollectionFactory.hashSet( + PsiKeyword.RETURN, PsiKeyword.INSTANCEOF, "in", + PsiKeyword.PRIVATE, PsiKeyword.PROTECTED, PsiKeyword.PUBLIC, PsiKeyword.STATIC, "def", + PsiKeyword.TRUE, PsiKeyword.FALSE, PsiKeyword.NULL); + + static { + TRASH_CLASSES.add(CommonClassNames.JAVA_LANG_CLASS); + TRASH_CLASSES.add(CommonClassNames.JAVA_LANG_OBJECT); + TRASH_CLASSES.add(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT); + } + + @Override + public Comparable weigh(@NotNull LookupElement element, @NotNull CompletionLocation location) { + final PsiElement position = location.getCompletionParameters().getPosition(); + if (!(position.getContainingFile() instanceof GroovyFileBase)) return null; + + Object o = element.getObject(); + if (o instanceof ResolveResult) { + o = ((ResolveResult)o).getElement(); + } + + final PsiElement parent = position.getParent(); + final PsiElement qualifier = parent instanceof GrReferenceElement ? ((GrReferenceElement)parent).getQualifier() : null; + if (qualifier == null) { + if (o instanceof NamedArgumentDescriptor) { + switch (((NamedArgumentDescriptor)o).getPriority()) { + case ALWAYS_ON_TOP: + return NotQualifiedKind.onTop; + case AS_LOCAL_VARIABLE: + return NotQualifiedKind.local; + default: + return NotQualifiedKind.unknown; + } + } + if (o instanceof PsiVariable && !(o instanceof PsiField)) { + return NotQualifiedKind.local; + } + + PsiTypeLookupItem item = element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); + if (item != null && item.getBracketsCount() > 0) { + return NotQualifiedKind.arrayType; + } + + if (isPriorityKeyword(o)) return NotQualifiedKind.local; + if (isLightElement(o)) return NotQualifiedKind.unknown; + if (o instanceof PsiClass) { + if (((PsiClass)o).isAnnotationType() && GroovyCompletionContributor.AFTER_AT.accepts(position)) { + final GrAnnotation annotation = PsiTreeUtil.getParentOfType(position, GrAnnotation.class); + if (annotation != null) { + PsiElement annoParent = annotation.getParent(); + PsiElement owner = annoParent.getParent(); + String[] elementTypeFields = GrAnnotationImpl.getApplicableElementTypeFields(annoParent instanceof PsiModifierList ? owner : annoParent); + if (PsiAnnotationImpl.isAnnotationApplicable(false, (PsiClass)o, elementTypeFields, position.getResolveScope())) { + return NotQualifiedKind.restrictedClass; + } + } + } + if (GroovyCompletionContributor.IN_CATCH_TYPE.accepts(position) && + InheritanceUtil.isInheritor((PsiClass)o, CommonClassNames.JAVA_LANG_THROWABLE)) { + return NotQualifiedKind.restrictedClass; + } + } + if (o instanceof PsiMember) { + final PsiClass containingClass = ((PsiMember)o).getContainingClass(); + if (isAccessor((PsiMember)o)) return NotQualifiedKind.accessor; + if (o instanceof PsiClass && ((PsiClass)o).getContainingClass() == null || o instanceof PsiPackage) return NotQualifiedKind.unknown; + if (o instanceof PsiClass) return NotQualifiedKind.innerClass; + if (PsiTreeUtil.isContextAncestor(containingClass, position, false)) return NotQualifiedKind.currentClassMember; + return NotQualifiedKind.member; + } + return NotQualifiedKind.unknown; + } + else { + if (o instanceof PsiEnumConstant) return QualifiedKind.enumConstant; + + if (isLightElement(o)) return QualifiedKind.unknown; + if (o instanceof PsiMember) { + if (isTrashMethod((PsiMember)o)) return QualifiedKind.unknown; + if (isAccessor((PsiMember)o)) return QualifiedKind.accessor; + if (isQualifierClassMember((PsiMember)o, qualifier)) { + return QualifiedKind.currentClassMember; + } + if (o instanceof PsiClass && ((PsiClass)o).getContainingClass() == null || o instanceof PsiPackage) return QualifiedKind.unknown; + if (o instanceof PsiClass) return QualifiedKind.innerClass; + return QualifiedKind.member; + } + return QualifiedKind.unknown; + } + } + + private static boolean isPriorityKeyword(Object o) { + //noinspection SuspiciousMethodCalls + return PRIORITY_KEYWORDS.contains(o); + } + + private static boolean isLightElement(Object o) { + return o instanceof LightElement && !(o instanceof GrPropertyForCompletion) && !(o instanceof GrAccessorMethod); + } + + private static boolean isTrashMethod(PsiMember o) { + final PsiClass containingClass = o.getContainingClass(); + return containingClass != null && TRASH_CLASSES.contains(containingClass.getQualifiedName()); + } + + private static boolean isAccessor(PsiMember member) { + return member instanceof PsiMethod && (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)member) || "setProperty".equals(((PsiMethod)member).getName())); + } + + + private static boolean isQualifierClassMember(PsiMember member, PsiElement qualifier) { + if (!(qualifier instanceof GrExpression)) return false; + + final PsiType type = ((GrExpression)qualifier).getType(); + if (!(type instanceof PsiClassType)) return false; + + final PsiClass psiClass = ((PsiClassType)type).resolve(); + if (psiClass == null) return false; + + return qualifier.getManager().areElementsEquivalent(member.getContainingClass(), psiClass); + } + + private enum NotQualifiedKind { + arrayType, + innerClass, + unknown, + accessor, + member, + currentClassMember, + restrictedClass, + local, + onTop + } + + private enum QualifiedKind { + innerClass, + unknown, + accessor, + member, + currentClassMember, + enumConstant, + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/annotation/GrAnnotationImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/annotation/GrAnnotationImpl.java index fb954985066d..ddb032dfb9ef 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/annotation/GrAnnotationImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/annotation/GrAnnotationImpl.java @@ -179,7 +179,7 @@ public class GrAnnotationImpl extends GrStubElementBase implem GrCodeReferenceElement nameRef = annotation.getClassReference(); PsiElement resolved = nameRef.resolve(); if (resolved instanceof PsiClass && ((PsiClass)resolved).isAnnotationType()) { - return PsiAnnotationImpl.isAnnotationApplicable(strict, (PsiClass)resolved, elementTypeFields, annotation.getManager(),annotation.getResolveScope()); + return PsiAnnotationImpl.isAnnotationApplicable(strict, (PsiClass)resolved, elementTypeFields, annotation.getResolveScope()); } return !strict; } 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 57b3a07e1a30..4b2c458e6d94 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -1398,4 +1398,22 @@ def bar(){}''') assertOrderedEquals(myFixture.lookupElementStrings, ['fooo', 'fooo1']) } + public void testPreferApplicableAnnotations() { + configure(''' +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Z +@interface Foo { +} + +@Target(ElementType.ANNOTATION_TYPE) +@interface ZMetaAnno {} + +@Target(ElementType.LOCAL_VARIABLE) +@interface ZLocalAnno {}''') + myFixture.completeBasic() + myFixture.assertPreferredCompletionItems 0, 'ZMetaAnno', 'ZLocalAnno' + } + } \ No newline at end of file