IDEA-100100 Groovy 2.1: applicability of annotation aliases is not checked if annotations are passed to @AnnotationCollector as a list

This commit is contained in:
Max Medvedev
2013-02-23 11:22:50 +04:00
parent ed7abec75e
commit fd80f6c26d
6 changed files with 96 additions and 77 deletions
@@ -21,12 +21,9 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrAnnotationCollector;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
@@ -39,32 +36,20 @@ import java.util.Set;
* @author Max Medvedev
*/
public class GrAliasAnnotationChecker extends CustomAnnotationChecker {
@Nullable
private static GrTypeDefinition resolveAlias(@NotNull GrAnnotation annotation) {
final GrCodeReferenceElement ref = annotation.getClassReference();
final PsiElement resolved = ref.resolve();
if (GrAnnotationCollector.findAnnotationCollector(resolved) != null) {
assert resolved instanceof GrTypeDefinition;
return ((GrTypeDefinition)(resolved));
}
return null;
}
@Override
public boolean checkApplicability(@NotNull AnnotationHolder holder, @NotNull GrAnnotation annotation) {
final GrTypeDefinition alias = resolveAlias(annotation);
if (alias == null) {
final GrAnnotation annotationCollector = GrAnnotationCollector.findAnnotationCollector(annotation);
if (annotationCollector == null) {
return false;
}
final GrCodeReferenceElement ref = annotation.getClassReference();
final GrModifierList list = alias.getModifierList();
assert list != null;
for (GrAnnotation anno : list.getRawAnnotations()) {
final ArrayList<GrAnnotation> aliasedAnnotations = ContainerUtil.newArrayList();
GrAnnotationCollector.collectAnnotations(aliasedAnnotations, annotation, annotationCollector);
for (GrAnnotation anno : aliasedAnnotations) {
if (GroovyCommonClassNames.GROOVY_TRANSFORM_ANNOTATION_COLLECTOR.equals(anno.getQualifiedName())) continue;
final String description = CustomAnnotationChecker.isAnnotationApplicable(anno, annotation.getParent());
if (description != null) {
@@ -77,14 +62,12 @@ public class GrAliasAnnotationChecker extends CustomAnnotationChecker {
@Override
public boolean checkArgumentList(@NotNull AnnotationHolder holder, @NotNull GrAnnotation annotation) {
final GrTypeDefinition alias = resolveAlias(annotation);
if (alias == null) {
final GrAnnotation annotationCollector = GrAnnotationCollector.findAnnotationCollector(annotation);
if (annotationCollector == null) {
return false;
}
final ArrayList<GrAnnotation> annotations = ContainerUtil.newArrayList();
final GrAnnotation annotationCollector = GrAnnotationCollector.findAnnotationCollector(alias);
assert annotationCollector != null;
final Set<String> usedAttributes = GrAnnotationCollector.collectAnnotations(annotations, annotation, annotationCollector);
final GrCodeReferenceElement ref = annotation.getClassReference();
@@ -799,7 +799,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement resolved = refElement.resolve();
if (resolved instanceof PsiClass &&
(((PsiClass)resolved).isAnnotationType() ||
GrAnnotationCollector.findAnnotationCollector(resolved) != null &&
GrAnnotationCollector.findAnnotationCollector((PsiClass)resolved) != null &&
refElement.getParent() instanceof GrAnnotation)) {
myHolder.createInfoAnnotation(refElement, null).setTextAttributes(ANNOTATION);
}
@@ -178,13 +178,15 @@ public class GrAnnotationNameValuePairImpl extends GroovyPsiElementImpl implemen
String declaredName = getName();
String name = declaredName == null ? PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME : declaredName;
final GrAnnotation collector = GrAnnotationCollector.findAnnotationCollector(resolved);
if (collector != null) {
return multiResolveFromAlias(annotation, name, collector);
}
if (resolved instanceof PsiClass) {
final GrAnnotation collector = GrAnnotationCollector.findAnnotationCollector((PsiClass)resolved);
if (collector != null) {
return multiResolveFromAlias(annotation, name, collector);
}
if (resolved instanceof PsiClass && ((PsiClass)resolved).isAnnotationType()) {
return multiResolveFromAnnotationType((PsiClass)resolved, name);
if (((PsiClass)resolved).isAnnotationType()) {
return multiResolveFromAnnotationType((PsiClass)resolved, name);
}
}
}
return GroovyResolveResult.EMPTY_ARRAY;
@@ -26,6 +26,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
@@ -42,8 +43,7 @@ public class GrAnnotationCollector {
List<GrAnnotation> result = ContainerUtil.newArrayList();
for (GrAnnotation annotation : rawAnnotations) {
final PsiElement resolved = annotation.getClassReference().resolve();
final GrAnnotation annotationCollector = findAnnotationCollector(resolved);
final GrAnnotation annotationCollector = findAnnotationCollector(annotation);
if (annotationCollector != null) {
collectAnnotations(result, annotation, annotationCollector);
}
@@ -58,8 +58,7 @@ public class GrAnnotationCollector {
private static boolean hasAliases(GrAnnotation[] rawAnnotations) {
for (GrAnnotation annotation : rawAnnotations) {
final PsiElement resolved = annotation.getClassReference().resolve();
final GrAnnotation annotationCollector = findAnnotationCollector(resolved);
final GrAnnotation annotationCollector = findAnnotationCollector(annotation);
if (annotationCollector != null) {
return true;
}
@@ -164,7 +163,7 @@ public class GrAnnotationCollector {
}
@Nullable
public static GrAnnotation findAnnotationCollector(PsiElement clazz) {
public static GrAnnotation findAnnotationCollector(PsiClass clazz) {
if (clazz instanceof GrTypeDefinition) {
final GrModifierList modifierList = ((GrTypeDefinition)clazz).getModifierList();
if (modifierList != null) {
@@ -178,4 +177,18 @@ public class GrAnnotationCollector {
return null;
}
@Nullable
public static GrAnnotation findAnnotationCollector(@NotNull GrAnnotation annotation) {
final GrCodeReferenceElement ref = annotation.getClassReference();
final PsiElement resolved = ref.resolve();
if (resolved instanceof PsiClass) {
return findAnnotationCollector((PsiClass)resolved);
}
else {
return null;
}
}
}
@@ -81,7 +81,7 @@ import groovy.transform.*
@AnnotationCollector([EqualsAndHashCode, Immutable])
@interface Alias {}
@<error descr="'@ToString' not applicable to local variable">Alias</error>(excludes = ['a'])
@<error descr="'@groovy.transform.EqualsAndHashCode' not applicable to local variable"><error descr="'@groovy.transform.Immutable' not applicable to local variable"><error descr="'@groovy.transform.ToString' not applicable to local variable">Alias</error></error></error>(excludes = ['a'])
int foo
''')
}
@@ -137,6 +137,66 @@ import groovy.transform.*
class Foo {
Integer a, b
}
''')
}
public void testAnnotationCollectorInterfaceWithAttrs() {
testHighlighting('''\
@interface Foo {
int foo()
}
@groovy.transform.AnnotationCollector
@Foo
@interface <error descr="Annotation type annotated with @AnnotationCollector cannot have attributes">A</error> {
int bar()
}
@A(foo = 2)
class X{}
''')
}
public void testAnnotationCollectorClass() {
testHighlighting('''
@interface Foo {
int foo()
}
@groovy.transform.AnnotationCollector
@Foo
class A {
int bar() {}
}
class B{}
@A(foo = 2)
@<error descr="'B' is not an annotation">B</error>
class X {}
''')
}
void testInapplicableAlias2() {
testHighlighting('''\
import groovy.transform.AnnotationCollector
import groovy.transform.Immutable
import groovy.transform.ToString
@AnnotationCollector([Immutable, ToString])
@interface Alias4 {}
@Immutable
@ToString
@AnnotationCollector
@interface Alias5 {}
@<error descr="'@groovy.transform.Immutable' not applicable to method"><error descr="'@groovy.transform.ToString' not applicable to method">Alias4</error></error>
def aaa() {}
@<error descr="'@groovy.transform.Immutable' not applicable to method"><error descr="'@groovy.transform.ToString' not applicable to method">Alias5</error></error>
def bbb() {}
''')
}
}
@@ -1120,43 +1120,4 @@ print(<error descr="Collection literal contains named and expression arguments a
''')
}
public void testAnnotationCollectorInterfaceWithAttrs() {
testHighlighting('''\
@interface Foo {
int foo()
}
@groovy.transform.AnnotationCollector
@Foo
@interface <error descr="Annotation type annotated with @AnnotationCollector cannot have attributes">A</error> {
int bar()
}
@A(foo = 2)
class X{}
''')
}
public void testAnnotationCollectorClass() {
testHighlighting('''
@interface Foo {
int foo()
}
@groovy.transform.AnnotationCollector
@Foo
class A {
int bar() {}
}
class B{}
@A(foo = 2)
@<error descr="'B' is not an annotation">B</error>
class X {}
''')
}
}