mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-66792 groovy: bad code green: applicability of annotation is not verified with regard to target element
This commit is contained in:
@@ -101,5 +101,6 @@ public interface PsiAnnotation extends PsiAnnotationMemberValue, PsiMetaOwner {
|
||||
*
|
||||
* @return annotation owner
|
||||
*/
|
||||
@Nullable
|
||||
PsiAnnotationOwner getOwner();
|
||||
}
|
||||
|
||||
+16
-7
@@ -26,6 +26,7 @@ import com.intellij.psi.impl.meta.MetaRegistry;
|
||||
import com.intellij.psi.impl.source.JavaStubPsiElement;
|
||||
import com.intellij.psi.impl.source.tree.ChildRole;
|
||||
import com.intellij.psi.meta.PsiMetaData;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.PairFunction;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -120,6 +121,7 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
|
||||
return MetaRegistry.getMetaBase(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiAnnotationOwner getOwner() {
|
||||
PsiElement parent = getParent();
|
||||
@@ -160,6 +162,14 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
|
||||
return !strict;
|
||||
}
|
||||
PsiClass annotationType = (PsiClass)resolved;
|
||||
return isAnnotationApplicable(strict, annotationType, elementTypeFields, annotation.getManager(), annotation.getResolveScope());
|
||||
}
|
||||
|
||||
public static boolean isAnnotationApplicable(boolean strict,
|
||||
PsiClass annotationType,
|
||||
String[] elementTypeFields,
|
||||
PsiManager manager,
|
||||
GlobalSearchScope resolveScope) {
|
||||
PsiAnnotation target = annotationType.getModifierList().findAnnotation(CommonClassNames.TARGET_ANNOTATION_FQ_NAME);
|
||||
if (target == null) {
|
||||
//todo hack: ambiguity in spec
|
||||
@@ -173,8 +183,7 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
|
||||
PsiAnnotationMemberValue value = attributes[0].getValue();
|
||||
LOG.assertTrue(elementTypeFields.length > 0);
|
||||
|
||||
PsiManager manager = annotation.getManager();
|
||||
PsiClass elementTypeClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.annotation.ElementType", annotation.getResolveScope());
|
||||
PsiClass elementTypeClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.annotation.ElementType", resolveScope);
|
||||
if (elementTypeClass == null) {
|
||||
//todo hack
|
||||
return !strict;
|
||||
@@ -187,19 +196,19 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
|
||||
if (value instanceof PsiArrayInitializerMemberValue) {
|
||||
PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
|
||||
for (PsiAnnotationMemberValue initializer : initializers) {
|
||||
if (initializer instanceof PsiReferenceExpression) {
|
||||
PsiReferenceExpression refExpr = (PsiReferenceExpression)initializer;
|
||||
if (refExpr.isReferenceTo(field)) return true;
|
||||
if (initializer instanceof PsiReference) {
|
||||
if (((PsiReference)initializer).isReferenceTo(field)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value instanceof PsiReferenceExpression) {
|
||||
if (((PsiReferenceExpression)value).isReferenceTo(field)) return true;
|
||||
else if (value instanceof PsiReference) {
|
||||
if (((PsiReference)value).isReferenceTo(field)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String[] getApplicableElementTypeFields(PsiElement owner) {
|
||||
if (owner instanceof PsiClass) {
|
||||
PsiClass aClass = (PsiClass)owner;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.plugins.groovy.annotator;
|
||||
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.AddMethodBodyFix;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
|
||||
@@ -100,6 +101,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDef
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.TypeInferenceHelper;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
|
||||
@@ -162,7 +164,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
|
||||
final PsiElement parent = refElement.getParent();
|
||||
GroovyResolveResult resolveResult = refElement.advancedResolve();
|
||||
highlightAnnotation(myHolder, refElement, resolveResult);
|
||||
if (refElement.getReferenceName() != null) {
|
||||
|
||||
if (parent instanceof GrImportStatement && ((GrImportStatement)parent).isStatic() && refElement.multiResolve(false).length > 0) {
|
||||
@@ -1092,15 +1093,30 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void visitAnnotation(GrAnnotation annotation) {
|
||||
super.visitAnnotation(annotation);
|
||||
final GrCodeReferenceElement ref = annotation.getClassReference();
|
||||
GroovyResolveResult resolveResult = ref.advancedResolve();
|
||||
final PsiElement resolved = ref.resolve();
|
||||
|
||||
assert resolved == null || resolved instanceof PsiClass;
|
||||
if (resolved != null && !((PsiClass)resolved).isAnnotationType()) {
|
||||
highlightAnnotation(myHolder, ref, resolveResult);
|
||||
|
||||
if (resolved == null) return;
|
||||
assert resolved instanceof PsiClass;
|
||||
|
||||
PsiClass anno = (PsiClass) resolved;
|
||||
if (!anno.isAnnotationType()) {
|
||||
myHolder.createErrorAnnotation(ref, GroovyBundle.message("class.is.not.annotation", ((PsiClass)resolved).getQualifiedName()));
|
||||
return;
|
||||
}
|
||||
PsiElement parent = annotation.getParent();
|
||||
PsiElement owner = parent.getParent();
|
||||
String[] elementTypeFields = GrAnnotationImpl.getApplicableElementTypeFields(parent instanceof PsiModifierList ? owner : parent);
|
||||
if (!GrAnnotationImpl.isAnnotationApplicableTo(annotation, false, elementTypeFields)) {
|
||||
String description = JavaErrorMessages
|
||||
.message("annotation.not.applicable", ref.getText(), JavaErrorMessages.message("annotation.target." + elementTypeFields[0]));
|
||||
myHolder.createErrorAnnotation(ref, description);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrLabelImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrListOrMapImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrThrowsClauseImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArgumentListImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArrrayInitializerImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArrayInitializerImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationNameValuePairImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrModifierListImpl;
|
||||
@@ -106,7 +106,7 @@ public class GroovyPsiCreator implements GroovyElementTypes {
|
||||
if (elem == MODIFIERS) return new GrModifierListImpl(node);
|
||||
if (elem == ANNOTATION) return new GrAnnotationImpl(node);
|
||||
if (elem == ANNOTATION_ARGUMENTS) return new GrAnnotationArgumentListImpl(node);
|
||||
if (elem == ANNOTATION_ARRAY_INITIALIZER) return new GrAnnotationArrrayInitializerImpl(node);
|
||||
if (elem == ANNOTATION_ARRAY_INITIALIZER) return new GrAnnotationArrayInitializerImpl(node);
|
||||
if (elem == ANNOTATION_MEMBER_VALUE_PAIR) return new GrAnnotationNameValuePairImpl(node);
|
||||
|
||||
if (elem == DEFAULT_ANNOTATION_VALUE) return new GrDefaultAnnotationValueImpl(node);
|
||||
|
||||
+2
-3
@@ -16,15 +16,14 @@
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation;
|
||||
|
||||
import com.intellij.psi.PsiArrayInitializerMemberValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
|
||||
/**
|
||||
* @author: Dmitry.Krasilschikov
|
||||
* @date: 04.04.2007
|
||||
*/
|
||||
public interface GrAnnotationArrayInitializer extends GrAnnotationMemberValue {
|
||||
|
||||
public interface GrAnnotationArrayInitializer extends GrAnnotationMemberValue, PsiArrayInitializerMemberValue {
|
||||
@NotNull
|
||||
GrAnnotationMemberValue[] getInitializers();
|
||||
}
|
||||
+1
-3
@@ -16,10 +16,8 @@
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation;
|
||||
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrCondition;
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiAnnotationMemberValue;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
|
||||
/**
|
||||
* @author: Dmitry.Krasilschikov
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA;
|
||||
* @author: Dmitry.Krasilschikov
|
||||
* @date: 04.04.2007
|
||||
*/
|
||||
public class GrAnnotationArrrayInitializerImpl extends GroovyPsiElementImpl implements GrAnnotationArrayInitializer {
|
||||
public GrAnnotationArrrayInitializerImpl(@NotNull ASTNode node) {
|
||||
public class GrAnnotationArrayInitializerImpl extends GroovyPsiElementImpl implements GrAnnotationArrayInitializer {
|
||||
public GrAnnotationArrayInitializerImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
+59
@@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
|
||||
import com.intellij.psi.meta.PsiMetaData;
|
||||
import com.intellij.util.PairFunction;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -30,7 +31,14 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrAnnotationStub;
|
||||
|
||||
@@ -118,4 +126,55 @@ public class GrAnnotationImpl extends GrStubElementBase<GrAnnotationStub> implem
|
||||
return (PsiAnnotationOwner)getParent();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String[] getApplicableElementTypeFields(PsiElement owner) {
|
||||
if (owner instanceof PsiClass) {
|
||||
PsiClass aClass = (PsiClass)owner;
|
||||
if (aClass.isAnnotationType()) {
|
||||
return new String[]{"ANNOTATION_TYPE", "TYPE"};
|
||||
}
|
||||
else if (aClass instanceof GrTypeParameter) {
|
||||
return new String[]{"TYPE_PARAMETER"};
|
||||
}
|
||||
else {
|
||||
return new String[]{"TYPE"};
|
||||
}
|
||||
}
|
||||
if (owner instanceof GrMethod) {
|
||||
if (((PsiMethod)owner).isConstructor()) {
|
||||
return new String[]{"CONSTRUCTOR"};
|
||||
}
|
||||
else {
|
||||
return new String[]{"METHOD"};
|
||||
}
|
||||
}
|
||||
if (owner instanceof GrField) {
|
||||
return new String[]{"FIELD"};
|
||||
}
|
||||
if (owner instanceof GrParameter) {
|
||||
return new String[]{"PARAMETER"};
|
||||
}
|
||||
if (owner instanceof GrVariable) {
|
||||
return new String[]{"LOCAL_VARIABLE"};
|
||||
}
|
||||
if (owner instanceof GrPackageDefinition) {
|
||||
return new String[]{"PACKAGE"};
|
||||
}
|
||||
if (owner instanceof GrTypeElement) {
|
||||
return new String[]{"TYPE_USE"};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isAnnotationApplicableTo(GrAnnotation annotation, boolean strict, String... elementTypeFields) {
|
||||
if (elementTypeFields == null) return true;
|
||||
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 !strict;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,4 +738,54 @@ private def handleImplicitBind(arg) {
|
||||
}''')
|
||||
myFixture.testHighlighting(true, false, false)
|
||||
}
|
||||
|
||||
public void testTargetAnnotationInsideGroovy1() {
|
||||
myFixture.addFileToProject('Ann.groovy', '''
|
||||
import java.lang.annotation.Target
|
||||
|
||||
import static java.lang.annotation.ElementType.*
|
||||
|
||||
@Target(FIELD)
|
||||
@interface Ann {}
|
||||
''')
|
||||
|
||||
myFixture.configureByText('_.groovy', '''
|
||||
@<error descr="'@Ann' not applicable to type">Ann</error>
|
||||
class C {
|
||||
@Ann
|
||||
def foo
|
||||
|
||||
def ar() {
|
||||
@Ann
|
||||
def x
|
||||
}
|
||||
}''')
|
||||
|
||||
myFixture.testHighlighting(true, false, false)
|
||||
}
|
||||
|
||||
public void testTargetAnnotationInsideGroovy2() {
|
||||
myFixture.addFileToProject('Ann.groovy', '''
|
||||
import java.lang.annotation.Target
|
||||
|
||||
import static java.lang.annotation.ElementType.*
|
||||
|
||||
@Target(value=[FIELD, TYPE])
|
||||
@interface Ann {}
|
||||
''')
|
||||
|
||||
myFixture.configureByText('_.groovy', '''
|
||||
@Ann
|
||||
class C {
|
||||
@Ann
|
||||
def foo
|
||||
|
||||
def ar() {
|
||||
@Ann
|
||||
def x
|
||||
}
|
||||
}''')
|
||||
myFixture.testHighlighting(true, false, false)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user