mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-84963 Disprefer annotations in autocomplete at places where they cannot be used
This commit is contained in:
@@ -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<PsiField> myNonInitializedFields;
|
||||
@Nullable private final String myRequiredSuper;
|
||||
@NotNull private final Condition<PsiClass> 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<PsiClass> 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<PsiClass>() {
|
||||
@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<PsiClass>() {
|
||||
@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<PsiClass>() {
|
||||
@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;
|
||||
|
||||
+18
-8
@@ -162,14 +162,17 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> 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<PsiAnnotationStub> 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<PsiAnnotationStub> 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;
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Z<caret>
|
||||
@interface Foo {
|
||||
}
|
||||
|
||||
@Target({ElementType.ANNOTATION_TYPE})
|
||||
@interface ZMetaAnno {}
|
||||
|
||||
@Target({ElementType.LOCAL_VARIABLE})
|
||||
@interface ZLocalAnno {}
|
||||
+4
@@ -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");
|
||||
|
||||
+190
-179
@@ -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<String> TRASH_CLASSES = new HashSet<String>(10);
|
||||
private static final Set<String> 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<String> TRASH_CLASSES = new HashSet<String>(10);
|
||||
private static final Set<String> 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,
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ public class GrAnnotationImpl extends GrStubElementBase<GrAnnotationStub> 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;
|
||||
}
|
||||
|
||||
+18
@@ -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<caret>
|
||||
@interface Foo {
|
||||
}
|
||||
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@interface ZMetaAnno {}
|
||||
|
||||
@Target(ElementType.LOCAL_VARIABLE)
|
||||
@interface ZLocalAnno {}''')
|
||||
myFixture.completeBasic()
|
||||
myFixture.assertPreferredCompletionItems 0, 'ZMetaAnno', 'ZLocalAnno'
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user