8011027: Type parameter annotations not passed through to javax.lang.model
Reviewed-by: jjg, darcy
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Fri Apr 19 11:10:40 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Apr 22 10:24:19 2013 +0200
@@ -465,19 +465,12 @@
* This is the implementation for {@code
* javax.lang.model.element.Element.getAnnotationMirrors()}.
*/
- public final List<? extends AnnotationMirror> getAnnotationMirrors() {
+ @Override
+ public List<Attribute.Compound> getAnnotationMirrors() {
return getRawAttributes();
}
/**
- * TODO: Should there be a {@code
- * javax.lang.model.element.Element.getTypeAnnotationMirrors()}.
- */
- public final List<Attribute.TypeCompound> getTypeAnnotationMirrors() {
- return getRawTypeAttributes();
- }
-
- /**
* @deprecated this method should never be used by javac internally.
*/
@Deprecated
@@ -657,6 +650,24 @@
}
@Override
+ public List<Attribute.Compound> getAnnotationMirrors() {
+ return onlyTypeVariableAnnotations(owner.getRawTypeAttributes());
+ }
+
+ private List<Attribute.Compound> onlyTypeVariableAnnotations(
+ List<Attribute.TypeCompound> candidates) {
+ // Declaration annotations on TypeParameters are stored in type attributes
+ List<Attribute.Compound> res = List.nil();
+ for (Attribute.TypeCompound a : candidates) {
+ if (a.position.type == TargetType.CLASS_TYPE_PARAMETER ||
+ a.position.type == TargetType.METHOD_TYPE_PARAMETER)
+ res = res.prepend(a);
+ }
+
+ return res = res.reverse();
+ }
+
+ @Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitTypeParameter(this, p);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Fri Apr 19 11:10:40 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Apr 22 10:24:19 2013 +0200
@@ -206,7 +206,7 @@
sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
// Make sure all type annotations from the symbol are also
// on the owner.
- sym.owner.annotations.appendUniqueTypes(sym.getTypeAnnotationMirrors());
+ sym.owner.annotations.appendUniqueTypes(sym.getRawTypeAttributes());
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java Fri Apr 19 11:10:40 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java Mon Apr 22 10:24:19 2013 +0200
@@ -33,10 +33,13 @@
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.TypeVariableSymbol;
+import com.sun.tools.javac.code.TargetType;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.AnnotatedType;
import com.sun.tools.javac.util.ListBuffer;
import static com.sun.tools.javac.code.TypeTag.CLASS;
+import com.sun.tools.javac.util.List;
/**
* Utility methods for operating on annotated constructs.
@@ -61,8 +64,12 @@
throw new IllegalArgumentException("Not an annotation type: "
+ annoType);
Attribute.Compound c;
- if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) {
+ if (annotated.kind == Kinds.TYP &&
+ annotated instanceof ClassSymbol) {
c = getAttributeOnClass((ClassSymbol)annotated, annoType);
+ } else if (annotated.kind == Kinds.TYP &&
+ annotated instanceof TypeVariableSymbol) {
+ c = getAttributeOnTypeVariable((TypeVariableSymbol)annotated, annoType);
} else {
c = getAttribute(annotated, annoType);
}
@@ -83,6 +90,24 @@
}
// Helper to getAnnotation[s]
+ private static <A extends Annotation> Attribute.Compound
+ getAttributeOnTypeVariable(TypeVariableSymbol annotated, Class<A> annoType) {
+ String name = annoType.getName();
+
+ // Declaration annotations on type variables are stored in type attributes
+ // on the owner of the TypeVariableSymbol
+ List<Attribute.Compound> res = List.nil();
+ List<Attribute.TypeCompound> candidates = annotated.owner.getRawTypeAttributes();
+ for (Attribute.TypeCompound anno : candidates)
+ if (anno.position.type == TargetType.CLASS_TYPE_PARAMETER ||
+ anno.position.type == TargetType.METHOD_TYPE_PARAMETER)
+ if (name.equals(anno.type.tsym.flatName().toString()))
+ return anno;
+
+ return null;
+ }
+
+ // Helper to getAnnotation[s]
private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated,
Class<A> annoType) {
boolean inherited = annoType.isAnnotationPresent(Inherited.class);
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java Fri Apr 19 11:10:40 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Apr 22 10:24:19 2013 +0200
@@ -402,9 +402,10 @@
* @param e the element being examined
* @return all annotations of the element
*/
+ @Override
public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
Symbol sym = cast(Symbol.class, e);
- List<Attribute.Compound> annos = sym.getRawAttributes();
+ List<Attribute.Compound> annos = sym.getAnnotationMirrors();
while (sym.getKind() == ElementKind.CLASS) {
Type sup = ((ClassSymbol) sym).getSuperclass();
if (!sup.hasTag(CLASS) || sup.isErroneous() ||
@@ -413,7 +414,7 @@
}
sym = sup.tsym;
List<Attribute.Compound> oldAnnos = annos;
- List<Attribute.Compound> newAnnos = sym.getRawAttributes();
+ List<Attribute.Compound> newAnnos = sym.getAnnotationMirrors();
for (Attribute.Compound anno : newAnnos) {
if (isInherited(anno.type) &&
!containsAnnoOfType(oldAnnos, anno.type)) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java Mon Apr 22 10:24:19 2013 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8011027
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor TestTypeParameterAnnotations
+ * @compile -processor TestTypeParameterAnnotations -proc:only TestTypeParameterAnnotations.java
+ */
+
+import java.util.*;
+import java.lang.annotation.*;
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import javax.tools.*;
+
+public class TestTypeParameterAnnotations<@Foo @Bar @Baz T> extends JavacTestingAbstractProcessor {
+ int round = 0;
+
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (++round == 1) {
+ int found = (new Scanner()).scan(roundEnv.getRootElements(), null);
+ if (found == expect) {
+ ; //nop
+ } else {
+ error("unexpected number of results: expected " + expect
+ + ", found " + found);
+ }
+
+ }
+ return true;
+ }
+
+ class Scanner extends JavacTestingAbstractProcessor.ElementScanner<Integer,Void> {
+ @Override
+ public Integer visitExecutable(ExecutableElement e, Void p) {
+ super.visitExecutable(e, p);
+ found += check(e, e.getTypeParameters());
+ return found;
+ }
+
+ @Override
+ public Integer visitType(TypeElement e, Void p) {
+ super.visitType(e, p);
+ found += check(e, e.getTypeParameters());
+ return found;
+ }
+
+ int found;
+ }
+
+ int check(Element e, List<? extends TypeParameterElement> typarams) {
+ if (typarams.isEmpty())
+ return 0;
+ if (typarams.size() != 1)
+ return 0;
+
+ for (TypeParameterElement tpe: typarams) {
+ boolean b1 = checkAnnotationMirrors(tpe, tpe.getAnnotationMirrors());
+ boolean b2 = checkAnnotationMirrors(tpe, elements.getAllAnnotationMirrors(tpe));
+ boolean b3 = checkGetAnnotation(tpe);
+ boolean b4 = checkGetAnnotations(tpe);
+ return b1 && b2 && b3 && b4 ? 1 : 0;
+ }
+ return 0;
+ }
+
+ boolean checkAnnotationMirrors(TypeParameterElement tpe, List<? extends AnnotationMirror> l) {
+ if (l.size() != 3) {
+ error("To few annotations, got " + l.size() +
+ ", should be 3", tpe);
+ return false;
+ }
+
+ AnnotationMirror m = l.get(0);
+ if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Foo"))) {
+ error("Wrong type of annotation, was expecting @Foo", m.getAnnotationType().asElement());
+ return false;
+ }
+ m = l.get(1);
+ if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Bar"))) {
+ error("Wrong type of annotation, was expecting @Bar", m.getAnnotationType().asElement());
+ return false;
+ }
+ m = l.get(2);
+ if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Baz"))) {
+ error("Wrong type of annotation, was expecting @Baz", m.getAnnotationType().asElement());
+ return false;
+ }
+ return true;
+ }
+
+ boolean checkGetAnnotation(TypeParameterElement tpe) {
+ Foo f = tpe.getAnnotation(Foo.class);
+ if (f == null)
+ error("Expecting @Foo to be present in getAnnotation()", tpe);
+
+ Bar b = tpe.getAnnotation(Bar.class);
+ if (b == null)
+ error("Expecting @Bar to be present in getAnnotation()", tpe);
+
+ Baz z = tpe.getAnnotation(Baz.class);
+ if (z == null)
+ error("Expecting @Baz to be present in getAnnotation()", tpe);
+
+ return f != null &&
+ b != null &&
+ z != null;
+ }
+
+ boolean checkGetAnnotations(TypeParameterElement tpe) {
+ Foo[] f = tpe.getAnnotationsByType(Foo.class);
+ if (f.length != 1) {
+ error("Expecting 1 @Foo to be present in getAnnotationsByType()", tpe);
+ return false;
+ }
+
+ Bar[] b = tpe.getAnnotationsByType(Bar.class);
+ if (b.length != 1) {
+ error("Expecting 1 @Bar to be present in getAnnotationsByType()", tpe);
+ return false;
+ }
+
+ Baz[] z = tpe.getAnnotationsByType(Baz.class);
+ if (z.length != 1) {
+ error("Expecting 1 @Baz to be present in getAnnotationsByType()", tpe);
+ return false;
+ }
+
+ return true;
+ }
+
+ void note(String msg) {
+ messager.printMessage(Diagnostic.Kind.NOTE, msg);
+ }
+
+ void note(String msg, Element e) {
+ messager.printMessage(Diagnostic.Kind.NOTE, msg, e);
+ }
+
+ void error(String msg, Element e) {
+ messager.printMessage(Diagnostic.Kind.ERROR, msg, e);
+ }
+
+ void error(String msg) {
+ messager.printMessage(Diagnostic.Kind.ERROR, msg);
+ }
+
+ // additional generic elements to test
+ <@Foo @Bar @Baz X> X m(X x) { return x; }
+
+ interface Intf<@Foo @Bar @Baz X> { X m() ; }
+
+ class Class<@Foo @Bar @Baz X> {
+ <@Foo @Bar @Baz Y> Class() { }
+ }
+
+ final int expect = 5; // top level class, plus preceding examples
+}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Foo {}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Bar {}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Baz {}