Tue, 14 May 2013 15:04:06 -0700
8013852: update reference impl for type-annotations
Reviewed-by: jjg
Contributed-by: wdietl@gmail.com, steve.sides@oracle.com, joel.franck@oracle.com, alex.buckley@oracle.com
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
24 /*
25 * @test
26 * @bug 1234567
27 * @summary Annotations on types
28 * @library /tools/javac/lib
29 * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests
30 * @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java
31 */
33 import java.io.PrintWriter;
34 import java.lang.annotation.Annotation;
35 import java.lang.annotation.ElementType;
36 import java.lang.annotation.Target;
37 import java.util.Map;
38 import java.util.Set;
40 import javax.annotation.processing.ProcessingEnvironment;
41 import javax.annotation.processing.RoundEnvironment;
42 import javax.lang.model.AnnotatedConstruct;
43 import javax.lang.model.element.AnnotationMirror;
44 import javax.lang.model.element.AnnotationValue;
45 import javax.lang.model.element.Element;
46 import javax.lang.model.element.ExecutableElement;
47 import javax.lang.model.element.TypeElement;
48 import javax.lang.model.type.ArrayType;
49 import javax.lang.model.type.ExecutableType;
50 import javax.lang.model.type.TypeMirror;
51 import javax.lang.model.type.TypeVariable;
52 import javax.lang.model.type.WildcardType;
53 import javax.tools.Diagnostic.Kind;
55 import com.sun.tools.javac.code.Symbol;
56 import com.sun.tools.javac.code.Type;
57 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
59 /**
60 * The test scans this file looking for test cases annotated with @Test.
61 */
62 public class BasicAnnoTests extends JavacTestingAbstractProcessor {
63 DPrinter dprinter;
64 PrintWriter out;
65 boolean verbose = true;
67 @Override
68 public void init(ProcessingEnvironment pEnv) {
69 super.init(pEnv);
70 dprinter = new DPrinter(((JavacProcessingEnvironment) pEnv).getContext());
71 out = dprinter.out;
72 }
74 @Override
75 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
76 TestElementScanner s = new TestElementScanner();
77 for (Element e: roundEnv.getRootElements()) {
78 s.scan(e);
79 }
80 return true;
81 }
83 void error(Element e, String msg) {
84 messager.printMessage(Kind.ERROR, msg, e);
85 errors++;
86 }
88 int errors;
90 /**
91 * Scan an element looking for declarations annotated with @Test.
92 * Run a TestTypeScanner on the annotations that are found.
93 */
94 class TestElementScanner extends ElementScanner<Void,Void> {
95 public Void scan(Element elem, Void ignore) {
96 AnnotationMirror test = getAnnotation(elem, Test.class.getName().replace('$', '.'));
97 if (test != null) {
98 out.println("Test: " + elem + " " + test);
99 TestTypeScanner s = new TestTypeScanner(elem, test);
100 s.scan(elem.asType(), null);
101 if (getPosn(test) >= s.count)
102 error(elem, "position " + getPosn(test) + " not found");
103 if (!s.found) {
104 dprinter.printSymbol("element", (Symbol) elem);
105 dprinter.printType("type", (Type) elem.asType());
106 }
107 out.println();
108 }
109 return super.scan(elem, ignore);
110 }
111 }
113 /**
114 * Scan the type of an element, looking for an annotation
115 * to match the expected annotation specified in the @Test annotation.
116 */
117 class TestTypeScanner extends TypeScanner<Void, Void> {
118 Element elem;
119 AnnotationMirror test;
120 int count = 0;
121 boolean found = false;
123 TestTypeScanner(Element elem, AnnotationMirror test) {
124 this.elem = elem;
125 this.test = test;
126 }
128 @Override
129 Void scan(TypeMirror t, Void ignore) {
130 if (t == null)
131 return DEFAULT_VALUE;
132 if (verbose)
133 out.println("scan " + count + ": " + t);
134 if (count == getPosn(test)) {
135 String annoType = getAnnoType(test);
136 AnnotationMirror anno = getAnnotation(t, annoType);
137 if (anno == null) {
138 error(elem, "annotation not found on " + count + ": " + t);
139 } else {
140 String v = getValue(anno, "value").toString();
141 if (v.equals(getExpect(test))) {
142 out.println("found " + anno + " as expected");
143 found = true;
144 } else {
145 error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
146 }
147 }
148 }
149 count++;
150 return super.scan(t, ignore);
151 }
152 }
154 /** Get the position value from an @Test annotation mirror. */
155 static int getPosn(AnnotationMirror test) {
156 AnnotationValue v = getValue(test, "posn");
157 return (Integer) v.getValue();
158 }
160 /** Get the expect value from an @Test annotation mirror. */
161 static String getExpect(AnnotationMirror test) {
162 AnnotationValue v = getValue(test, "expect");
163 return (String) v.getValue();
164 }
166 /** Get the annoType value from an @Test annotation mirror. */
167 static String getAnnoType(AnnotationMirror test) {
168 AnnotationValue v = getValue(test, "annoType");
169 TypeMirror m = (TypeMirror) v.getValue();
170 return m.toString();
171 }
173 /**
174 * Get a specific annotation mirror from an annotated construct.
175 */
176 static AnnotationMirror getAnnotation(AnnotatedConstruct e, String name) {
177 for (AnnotationMirror m: e.getAnnotationMirrors()) {
178 TypeElement te = (TypeElement) m.getAnnotationType().asElement();
179 if (te.getQualifiedName().contentEquals(name)) {
180 return m;
181 }
182 }
183 return null;
184 }
186 /**
187 * Get a specific value from an annotation mirror.
188 */
189 static AnnotationValue getValue(AnnotationMirror anno, String name) {
190 Map<? extends ExecutableElement, ? extends AnnotationValue> map = anno.getElementValues();
191 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e: map.entrySet()) {
192 if (e.getKey().getSimpleName().contentEquals(name)) {
193 return e.getValue();
194 }
195 }
196 return null;
197 }
199 /**
200 * The Language Model API does not provide a type scanner, so provide
201 * one sufficient for our needs.
202 */
203 static class TypeScanner<R, P> extends SimpleTypeVisitor<R, P> {
204 @Override
205 public R visitArray(ArrayType t, P p) {
206 scan(t.getComponentType(), p);
207 return super.visitArray(t, p);
208 }
210 @Override
211 public R visitExecutable(ExecutableType t, P p) {
212 scan(t.getReceiverType());
213 //out.println(" params: " + t.getParameterTypes());
214 scan(t.getParameterTypes(), p);
215 //out.println(" return: " + t.getReturnType());
216 scan(t.getReturnType(), p);
217 //out.println(" throws: " + t.getThrownTypes());
218 scan(t.getThrownTypes(), p);
219 return super.visitExecutable(t, p);
220 }
222 @Override
223 public R visitTypeVariable(TypeVariable t, P p) {
224 scan(t.getLowerBound(), p);
225 scan(t.getUpperBound(), p);
226 return super.visitTypeVariable(t, p);
227 }
229 @Override
230 public R visitWildcard(WildcardType t, P p) {
231 scan(t.getExtendsBound(), p);
232 scan(t.getSuperBound(), p);
233 return super.visitWildcard(t, p);
234 }
236 R scan(TypeMirror t) {
237 return scan(t, null);
238 }
240 R scan(TypeMirror t, P p) {
241 return (t == null) ? DEFAULT_VALUE : t.accept(this, p);
242 }
244 R scan(Iterable<? extends TypeMirror> iter, P p) {
245 if (iter == null)
246 return DEFAULT_VALUE;
247 R result = DEFAULT_VALUE;
248 for (TypeMirror t: iter)
249 result = scan(t, p);
250 return result;
251 }
252 }
254 /** Annotation to identify test cases. */
255 @interface Test {
256 /** Where to look for the annotation, expressed as a scan index. */
257 int posn();
258 /** The annotation to look for. */
259 Class<? extends Annotation> annoType();
260 /** The string representation of the annotation's value. */
261 String expect();
262 }
264 /** Type annotation to use in test cases. */
265 @Target(ElementType.TYPE_USE)
266 public @interface TA {
267 int value();
268 }
270 @Test(posn=0, annoType=TA.class, expect="1")
271 public @TA(1) int f1;
273 @Test(posn=0, annoType=TA.class, expect="2")
274 public int @TA(2) [] f2;
276 @Test(posn=1, annoType=TA.class, expect="3")
277 public @TA(3) int [] f3;
279 @Test(posn=1, annoType=TA.class, expect="4")
280 public int m1(@TA(4) float a) throws Exception { return 0; }
282 @Test(posn=2, annoType=TA.class, expect="5")
283 public @TA(5) int m2(float a) throws Exception { return 0; }
285 @Test(posn=3, annoType=TA.class, expect="6")
286 public int m3(float a) throws @TA(6) Exception { return 0; }
287 }