Wed, 18 Jun 2014 10:44:16 +0200
8046916: Type parameter annotations don't work with multiple type parameters
Summary: When reading type variable's annotations out of the owner's type annotations, use the type variable's index in owner to exclude annotations belonging to other type variables.
Reviewed-by: jfranck, emc
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jun 19 12:22:39 2014 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Jun 18 10:44:16 2014 +0200 1.3 @@ -779,42 +779,41 @@ 1.4 1.5 @Override 1.6 public List<Attribute.Compound> getAnnotationMirrors() { 1.7 - return onlyTypeVariableAnnotations(owner.getRawTypeAttributes()); 1.8 - } 1.9 - 1.10 - private List<Attribute.Compound> onlyTypeVariableAnnotations( 1.11 - List<Attribute.TypeCompound> candidates) { 1.12 - // Declaration annotations on TypeParameters are stored in type attributes 1.13 + // Declaration annotations on type variables are stored in type attributes 1.14 + // on the owner of the TypeVariableSymbol 1.15 + List<Attribute.TypeCompound> candidates = owner.getRawTypeAttributes(); 1.16 + int index = owner.getTypeParameters().indexOf(this); 1.17 List<Attribute.Compound> res = List.nil(); 1.18 for (Attribute.TypeCompound a : candidates) { 1.19 - if (a.position.type == TargetType.CLASS_TYPE_PARAMETER || 1.20 - a.position.type == TargetType.METHOD_TYPE_PARAMETER) 1.21 + if (isCurrentSymbolsAnnotation(a, index)) 1.22 res = res.prepend(a); 1.23 } 1.24 1.25 - return res = res.reverse(); 1.26 + return res.reverse(); 1.27 } 1.28 1.29 - 1.30 - 1.31 // Helper to getAnnotation[s] 1.32 @Override 1.33 public <A extends Annotation> Attribute.Compound getAttribute(Class<A> annoType) { 1.34 - 1.35 String name = annoType.getName(); 1.36 1.37 // Declaration annotations on type variables are stored in type attributes 1.38 // on the owner of the TypeVariableSymbol 1.39 List<Attribute.TypeCompound> candidates = owner.getRawTypeAttributes(); 1.40 + int index = owner.getTypeParameters().indexOf(this); 1.41 for (Attribute.TypeCompound anno : candidates) 1.42 - if (anno.position.type == TargetType.CLASS_TYPE_PARAMETER || 1.43 - anno.position.type == TargetType.METHOD_TYPE_PARAMETER) 1.44 - if (name.contentEquals(anno.type.tsym.flatName())) 1.45 - return anno; 1.46 + if (isCurrentSymbolsAnnotation(anno, index) && 1.47 + name.contentEquals(anno.type.tsym.flatName())) 1.48 + return anno; 1.49 1.50 return null; 1.51 } 1.52 - 1.53 + //where: 1.54 + boolean isCurrentSymbolsAnnotation(Attribute.TypeCompound anno, int index) { 1.55 + return (anno.position.type == TargetType.CLASS_TYPE_PARAMETER || 1.56 + anno.position.type == TargetType.METHOD_TYPE_PARAMETER) && 1.57 + anno.position.parameter_index == index; 1.58 + } 1.59 1.60 1.61 @Override
2.1 --- a/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java Thu Jun 19 12:22:39 2014 +0100 2.2 +++ b/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java Wed Jun 18 10:44:16 2014 +0200 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -23,7 +23,7 @@ 2.11 2.12 /* 2.13 * @test 2.14 - * @bug 8011027 2.15 + * @bug 8011027 8046916 2.16 * @library /tools/javac/lib 2.17 * @build JavacTestingAbstractProcessor TestTypeParameterAnnotations 2.18 * @compile -processor TestTypeParameterAnnotations -proc:only TestTypeParameterAnnotations.java 2.19 @@ -33,10 +33,16 @@ 2.20 import java.lang.annotation.*; 2.21 import javax.annotation.processing.*; 2.22 import javax.lang.model.element.*; 2.23 -import javax.lang.model.util.*; 2.24 import javax.tools.*; 2.25 2.26 -public class TestTypeParameterAnnotations<@Foo @Bar @Baz T> extends JavacTestingAbstractProcessor { 2.27 +@ExpectedTypeParameterAnnotations(typeParameterName="T1", 2.28 + annotations={"Foo1", "Bar1", "Baz1"}) 2.29 +@ExpectedTypeParameterAnnotations(typeParameterName="T2", annotations={}) 2.30 +@ExpectedTypeParameterAnnotations(typeParameterName="T3", 2.31 + annotations={"Foo2", "Bar2", "Baz2"}) 2.32 +@ExpectedTypeParameterAnnotations(typeParameterName="T4", annotations={}) 2.33 +public class TestTypeParameterAnnotations<@Foo1 @Bar1 @Baz1 T1, T2, @Foo2 @Bar2 @Baz2 T3, T4> extends 2.34 + JavacTestingAbstractProcessor { 2.35 int round = 0; 2.36 2.37 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 2.38 @@ -74,82 +80,69 @@ 2.39 int check(Element e, List<? extends TypeParameterElement> typarams) { 2.40 if (typarams.isEmpty()) 2.41 return 0; 2.42 - if (typarams.size() != 1) 2.43 - return 0; 2.44 2.45 - for (TypeParameterElement tpe: typarams) { 2.46 - boolean b1 = checkAnnotationMirrors(tpe, tpe.getAnnotationMirrors()); 2.47 - boolean b2 = checkAnnotationMirrors(tpe, elements.getAllAnnotationMirrors(tpe)); 2.48 - boolean b3 = checkGetAnnotation(tpe); 2.49 - boolean b4 = checkGetAnnotations(tpe); 2.50 - return b1 && b2 && b3 && b4 ? 1 : 0; 2.51 + for (TypeParameterElement tpe : typarams) { 2.52 + ExpectedTypeParameterAnnotations expected = null; 2.53 + for (ExpectedTypeParameterAnnotations a : e.getAnnotationsByType(ExpectedTypeParameterAnnotations.class)) { 2.54 + if (tpe.getSimpleName().contentEquals(a.typeParameterName())) { 2.55 + expected = a; 2.56 + break; 2.57 + } 2.58 + } 2.59 + if (expected == null) { 2.60 + throw new IllegalStateException("Does not have expected values annotation."); 2.61 + } 2.62 + checkAnnotationMirrors(tpe, tpe.getAnnotationMirrors(), expected); 2.63 + checkAnnotationMirrors(tpe, elements.getAllAnnotationMirrors(tpe), expected); 2.64 + checkGetAnnotation(tpe, expected); 2.65 + checkGetAnnotations(tpe, expected); 2.66 } 2.67 - return 0; 2.68 + 2.69 + return typarams.size(); 2.70 } 2.71 2.72 - boolean checkAnnotationMirrors(TypeParameterElement tpe, List<? extends AnnotationMirror> l) { 2.73 - if (l.size() != 3) { 2.74 - error("To few annotations, got " + l.size() + 2.75 - ", should be 3", tpe); 2.76 - return false; 2.77 + void checkAnnotationMirrors(TypeParameterElement tpe, List<? extends AnnotationMirror> l, ExpectedTypeParameterAnnotations expected) { 2.78 + String[] expectedAnnotations = expected.annotations(); 2.79 + 2.80 + if (l.size() != expectedAnnotations.length) { 2.81 + error("Incorrect number of annotations, got " + l.size() + 2.82 + ", should be " + expectedAnnotations.length, tpe); 2.83 + return ; 2.84 } 2.85 2.86 - AnnotationMirror m = l.get(0); 2.87 - if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Foo"))) { 2.88 - error("Wrong type of annotation, was expecting @Foo", m.getAnnotationType().asElement()); 2.89 - return false; 2.90 + for (int i = 0; i < expectedAnnotations.length; i++) { 2.91 + AnnotationMirror m = l.get(i); 2.92 + if (!m.getAnnotationType().asElement().equals(elements.getTypeElement(expectedAnnotations[i]))) { 2.93 + error("Wrong type of annotation, was expecting @Foo", m.getAnnotationType().asElement()); 2.94 + return ; 2.95 + } 2.96 } 2.97 - m = l.get(1); 2.98 - if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Bar"))) { 2.99 - error("Wrong type of annotation, was expecting @Bar", m.getAnnotationType().asElement()); 2.100 - return false; 2.101 - } 2.102 - m = l.get(2); 2.103 - if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Baz"))) { 2.104 - error("Wrong type of annotation, was expecting @Baz", m.getAnnotationType().asElement()); 2.105 - return false; 2.106 - } 2.107 - return true; 2.108 } 2.109 2.110 - boolean checkGetAnnotation(TypeParameterElement tpe) { 2.111 - Foo f = tpe.getAnnotation(Foo.class); 2.112 - if (f == null) 2.113 - error("Expecting @Foo to be present in getAnnotation()", tpe); 2.114 + void checkGetAnnotation(TypeParameterElement tpe, ExpectedTypeParameterAnnotations expected) { 2.115 + List<String> expectedAnnotations = Arrays.asList(expected.annotations()); 2.116 2.117 - Bar b = tpe.getAnnotation(Bar.class); 2.118 - if (b == null) 2.119 - error("Expecting @Bar to be present in getAnnotation()", tpe); 2.120 + for (Class<? extends Annotation> c : ALL_ANNOTATIONS) { 2.121 + Object a = tpe.getAnnotation(c); 2.122 2.123 - Baz z = tpe.getAnnotation(Baz.class); 2.124 - if (z == null) 2.125 - error("Expecting @Baz to be present in getAnnotation()", tpe); 2.126 - 2.127 - return f != null && 2.128 - b != null && 2.129 - z != null; 2.130 + if (a != null ^ expectedAnnotations.indexOf(c.getName()) != (-1)) { 2.131 + error("Unexpected behavior for " + c.getName(), tpe); 2.132 + return ; 2.133 + } 2.134 + } 2.135 } 2.136 2.137 - boolean checkGetAnnotations(TypeParameterElement tpe) { 2.138 - Foo[] f = tpe.getAnnotationsByType(Foo.class); 2.139 - if (f.length != 1) { 2.140 - error("Expecting 1 @Foo to be present in getAnnotationsByType()", tpe); 2.141 - return false; 2.142 + void checkGetAnnotations(TypeParameterElement tpe, ExpectedTypeParameterAnnotations expected) { 2.143 + List<String> expectedAnnotations = Arrays.asList(expected.annotations()); 2.144 + 2.145 + for (Class<? extends Annotation> c : ALL_ANNOTATIONS) { 2.146 + Object[] a = tpe.getAnnotationsByType(c); 2.147 + 2.148 + if (a.length > 0 ^ expectedAnnotations.indexOf(c.getName()) != (-1)) { 2.149 + error("Unexpected behavior for " + c.getName(), tpe); 2.150 + return ; 2.151 + } 2.152 } 2.153 - 2.154 - Bar[] b = tpe.getAnnotationsByType(Bar.class); 2.155 - if (b.length != 1) { 2.156 - error("Expecting 1 @Bar to be present in getAnnotationsByType()", tpe); 2.157 - return false; 2.158 - } 2.159 - 2.160 - Baz[] z = tpe.getAnnotationsByType(Baz.class); 2.161 - if (z.length != 1) { 2.162 - error("Expecting 1 @Baz to be present in getAnnotationsByType()", tpe); 2.163 - return false; 2.164 - } 2.165 - 2.166 - return true; 2.167 } 2.168 2.169 void note(String msg) { 2.170 @@ -168,23 +161,71 @@ 2.171 messager.printMessage(Diagnostic.Kind.ERROR, msg); 2.172 } 2.173 2.174 + Class<? extends Annotation>[] ALL_ANNOTATIONS = new Class[] { 2.175 + Foo1.class, Bar1.class, Baz1.class, 2.176 + Foo2.class, Bar2.class, Baz2.class, 2.177 + }; 2.178 + 2.179 // additional generic elements to test 2.180 - <@Foo @Bar @Baz X> X m(X x) { return x; } 2.181 + @ExpectedTypeParameterAnnotations(typeParameterName="W", 2.182 + annotations={"Foo1", "Bar1", "Baz1"}) 2.183 + @ExpectedTypeParameterAnnotations(typeParameterName="X", annotations={}) 2.184 + @ExpectedTypeParameterAnnotations(typeParameterName="Y", 2.185 + annotations={"Foo2", "Bar2", "Baz2"}) 2.186 + @ExpectedTypeParameterAnnotations(typeParameterName="Z", annotations={}) 2.187 + <@Foo1 @Bar1 @Baz1 W, X, @Foo2 @Bar2 @Baz2 Y, Z> X m(X x) { return x; } 2.188 2.189 - interface Intf<@Foo @Bar @Baz X> { X m() ; } 2.190 + @ExpectedTypeParameterAnnotations(typeParameterName="W", 2.191 + annotations={"Foo1", "Bar1", "Baz1"}) 2.192 + @ExpectedTypeParameterAnnotations(typeParameterName="X", annotations={}) 2.193 + @ExpectedTypeParameterAnnotations(typeParameterName="Y", 2.194 + annotations={"Foo2", "Bar2", "Baz2"}) 2.195 + @ExpectedTypeParameterAnnotations(typeParameterName="Z", annotations={}) 2.196 + interface Intf<@Foo1 @Bar1 @Baz1 W, X, @Foo2 @Bar2 @Baz2 Y, Z> { X m() ; } 2.197 2.198 - class Class<@Foo @Bar @Baz X> { 2.199 - <@Foo @Bar @Baz Y> Class() { } 2.200 + @ExpectedTypeParameterAnnotations(typeParameterName="W", 2.201 + annotations={"Foo1", "Bar1", "Baz1"}) 2.202 + @ExpectedTypeParameterAnnotations(typeParameterName="X", annotations={}) 2.203 + @ExpectedTypeParameterAnnotations(typeParameterName="Y", 2.204 + annotations={"Foo2", "Bar2", "Baz2"}) 2.205 + @ExpectedTypeParameterAnnotations(typeParameterName="Z", annotations={}) 2.206 + class Clazz<@Foo1 @Bar1 @Baz1 W, X, @Foo2 @Bar2 @Baz2 Y, Z> { 2.207 + @ExpectedTypeParameterAnnotations(typeParameterName="W", 2.208 + annotations={"Foo1", "Bar1", "Baz1"}) 2.209 + @ExpectedTypeParameterAnnotations(typeParameterName="X", annotations={}) 2.210 + @ExpectedTypeParameterAnnotations(typeParameterName="Y", 2.211 + annotations={"Foo2", "Bar2", "Baz2"}) 2.212 + @ExpectedTypeParameterAnnotations(typeParameterName="Z", annotations={}) 2.213 + <@Foo1 @Bar1 @Baz1 W, X, @Foo2 @Bar2 @Baz2 Y, Z> Clazz() { } 2.214 } 2.215 2.216 - final int expect = 5; // top level class, plus preceding examples 2.217 + final int expect = 5 * 4; // top level class, plus preceding examples, 4 type variables each 2.218 } 2.219 2.220 @Target(ElementType.TYPE_PARAMETER) 2.221 -@interface Foo {} 2.222 +@interface Foo1 {} 2.223 2.224 @Target(ElementType.TYPE_PARAMETER) 2.225 -@interface Bar {} 2.226 +@interface Bar1 {} 2.227 2.228 @Target(ElementType.TYPE_PARAMETER) 2.229 -@interface Baz {} 2.230 +@interface Baz1 {} 2.231 + 2.232 +@Target(ElementType.TYPE_PARAMETER) 2.233 +@interface Foo2 {} 2.234 + 2.235 +@Target(ElementType.TYPE_PARAMETER) 2.236 +@interface Bar2 {} 2.237 + 2.238 +@Target(ElementType.TYPE_PARAMETER) 2.239 +@interface Baz2 {} 2.240 + 2.241 +@Repeatable(ExpectedTypeParameterAnnotationsCollection.class) 2.242 +@interface ExpectedTypeParameterAnnotations { 2.243 + public String typeParameterName(); 2.244 + public String[] annotations(); 2.245 +} 2.246 + 2.247 +@interface ExpectedTypeParameterAnnotationsCollection { 2.248 + public ExpectedTypeParameterAnnotations[] value(); 2.249 +}