IDEA-66792 groovy: bad code green: applicability of annotation is not verified with regard to target element

This commit is contained in:
Maxim.Medvedev
2012-04-06 12:04:27 +04:00
parent ec24c9d921
commit ddbc9d9b69
9 changed files with 153 additions and 21 deletions
@@ -101,5 +101,6 @@ public interface PsiAnnotation extends PsiAnnotationMemberValue, PsiMetaOwner {
*
* @return annotation owner
*/
@Nullable
PsiAnnotationOwner getOwner();
}
@@ -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);
@@ -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();
}
@@ -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
@@ -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);
}
@@ -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)
}
}