Tue, 15 Oct 2013 15:57:13 -0700
8026564: import changes from type-annotations forest
Reviewed-by: jjg
Contributed-by: wdietl@gmail.com, steve.sides@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 * @ignore
30 * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests
31 * @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java
32 */
34 import java.io.PrintWriter;
35 import java.lang.annotation.Annotation;
36 import java.lang.annotation.ElementType;
37 import java.lang.annotation.Target;
38 import java.util.Map;
39 import java.util.Set;
41 import javax.annotation.processing.ProcessingEnvironment;
42 import javax.annotation.processing.RoundEnvironment;
43 import javax.lang.model.AnnotatedConstruct;
44 import javax.lang.model.element.AnnotationMirror;
45 import javax.lang.model.element.AnnotationValue;
46 import javax.lang.model.element.Element;
47 import javax.lang.model.element.ExecutableElement;
48 import javax.lang.model.element.TypeElement;
49 import javax.lang.model.type.ArrayType;
50 import javax.lang.model.type.ExecutableType;
51 import javax.lang.model.type.TypeMirror;
52 import javax.lang.model.type.TypeVariable;
53 import javax.lang.model.type.WildcardType;
54 import javax.tools.Diagnostic.Kind;
56 import com.sun.tools.javac.code.Symbol;
57 import com.sun.tools.javac.code.Type;
58 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
60 /**
61 * The test scans this file looking for test cases annotated with @Test.
62 */
63 public class BasicAnnoTests extends JavacTestingAbstractProcessor {
64 DPrinter dprinter;
65 PrintWriter out;
66 boolean verbose = true;
68 @Override
69 public void init(ProcessingEnvironment pEnv) {
70 super.init(pEnv);
71 dprinter = new DPrinter(((JavacProcessingEnvironment) pEnv).getContext());
72 out = dprinter.out;
73 }
75 @Override
76 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
77 TestElementScanner s = new TestElementScanner();
78 for (Element e: roundEnv.getRootElements()) {
79 s.scan(e);
80 }
81 return true;
82 }
84 void error(Element e, String msg) {
85 messager.printMessage(Kind.ERROR, msg, e);
86 errors++;
87 }
89 int errors;
91 /**
92 * Scan an element looking for declarations annotated with @Test.
93 * Run a TestTypeScanner on the annotations that are found.
94 */
95 class TestElementScanner extends ElementScanner<Void,Void> {
96 public Void scan(Element elem, Void ignore) {
97 AnnotationMirror test = getAnnotation(elem, Test.class.getName().replace('$', '.'));
98 if (test != null) {
99 out.println("Test: " + elem + " " + test);
100 TestTypeScanner s = new TestTypeScanner(elem, test);
101 s.scan(elem.asType(), null);
102 if (getPosn(test) >= s.count)
103 error(elem, "position " + getPosn(test) + " not found");
104 if (!s.found) {
105 dprinter.printSymbol("element", (Symbol) elem);
106 dprinter.printType("type", (Type) elem.asType());
107 }
108 out.println();
109 }
110 return super.scan(elem, ignore);
111 }
112 }
114 /**
115 * Scan the type of an element, looking for an annotation
116 * to match the expected annotation specified in the @Test annotation.
117 */
118 class TestTypeScanner extends TypeScanner<Void, Void> {
119 Element elem;
120 AnnotationMirror test;
121 int count = 0;
122 boolean found = false;
124 TestTypeScanner(Element elem, AnnotationMirror test) {
125 this.elem = elem;
126 this.test = test;
127 }
129 @Override
130 Void scan(TypeMirror t, Void ignore) {
131 if (t == null)
132 return DEFAULT_VALUE;
133 if (verbose)
134 out.println("scan " + count + ": " + t);
135 if (count == getPosn(test)) {
136 String annoType = getAnnoType(test);
137 AnnotationMirror anno = getAnnotation(t, annoType);
138 if (anno == null) {
139 error(elem, "annotation not found on " + count + ": " + t);
140 } else {
141 String v = getValue(anno, "value").toString();
142 if (v.equals(getExpect(test))) {
143 out.println("found " + anno + " as expected");
144 found = true;
145 } else {
146 error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
147 }
148 }
149 }
150 count++;
151 return super.scan(t, ignore);
152 }
153 }
155 /** Get the position value from an @Test annotation mirror. */
156 static int getPosn(AnnotationMirror test) {
157 AnnotationValue v = getValue(test, "posn");
158 return (Integer) v.getValue();
159 }
161 /** Get the expect value from an @Test annotation mirror. */
162 static String getExpect(AnnotationMirror test) {
163 AnnotationValue v = getValue(test, "expect");
164 return (String) v.getValue();
165 }
167 /** Get the annoType value from an @Test annotation mirror. */
168 static String getAnnoType(AnnotationMirror test) {
169 AnnotationValue v = getValue(test, "annoType");
170 TypeMirror m = (TypeMirror) v.getValue();
171 return m.toString();
172 }
174 /**
175 * Get a specific annotation mirror from an annotated construct.
176 */
177 static AnnotationMirror getAnnotation(AnnotatedConstruct e, String name) {
178 for (AnnotationMirror m: e.getAnnotationMirrors()) {
179 TypeElement te = (TypeElement) m.getAnnotationType().asElement();
180 if (te.getQualifiedName().contentEquals(name)) {
181 return m;
182 }
183 }
184 return null;
185 }
187 /**
188 * Get a specific value from an annotation mirror.
189 */
190 static AnnotationValue getValue(AnnotationMirror anno, String name) {
191 Map<? extends ExecutableElement, ? extends AnnotationValue> map = anno.getElementValues();
192 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e: map.entrySet()) {
193 if (e.getKey().getSimpleName().contentEquals(name)) {
194 return e.getValue();
195 }
196 }
197 return null;
198 }
200 /**
201 * The Language Model API does not provide a type scanner, so provide
202 * one sufficient for our needs.
203 */
204 static class TypeScanner<R, P> extends SimpleTypeVisitor<R, P> {
205 @Override
206 public R visitArray(ArrayType t, P p) {
207 scan(t.getComponentType(), p);
208 return super.visitArray(t, p);
209 }
211 @Override
212 public R visitExecutable(ExecutableType t, P p) {
213 scan(t.getReceiverType());
214 //out.println(" params: " + t.getParameterTypes());
215 scan(t.getParameterTypes(), p);
216 //out.println(" return: " + t.getReturnType());
217 scan(t.getReturnType(), p);
218 //out.println(" throws: " + t.getThrownTypes());
219 scan(t.getThrownTypes(), p);
220 return super.visitExecutable(t, p);
221 }
223 @Override
224 public R visitTypeVariable(TypeVariable t, P p) {
225 scan(t.getLowerBound(), p);
226 scan(t.getUpperBound(), p);
227 return super.visitTypeVariable(t, p);
228 }
230 @Override
231 public R visitWildcard(WildcardType t, P p) {
232 scan(t.getExtendsBound(), p);
233 scan(t.getSuperBound(), p);
234 return super.visitWildcard(t, p);
235 }
237 R scan(TypeMirror t) {
238 return scan(t, null);
239 }
241 R scan(TypeMirror t, P p) {
242 return (t == null) ? DEFAULT_VALUE : t.accept(this, p);
243 }
245 R scan(Iterable<? extends TypeMirror> iter, P p) {
246 if (iter == null)
247 return DEFAULT_VALUE;
248 R result = DEFAULT_VALUE;
249 for (TypeMirror t: iter)
250 result = scan(t, p);
251 return result;
252 }
253 }
255 /** Annotation to identify test cases. */
256 @interface Test {
257 /** Where to look for the annotation, expressed as a scan index. */
258 int posn();
259 /** The annotation to look for. */
260 Class<? extends Annotation> annoType();
261 /** The string representation of the annotation's value. */
262 String expect();
263 }
265 /** Type annotation to use in test cases. */
266 @Target(ElementType.TYPE_USE)
267 public @interface TA {
268 int value();
269 }
271 @Test(posn=0, annoType=TA.class, expect="1")
272 public @TA(1) int f1;
274 @Test(posn=0, annoType=TA.class, expect="2")
275 public int @TA(2) [] f2;
277 @Test(posn=1, annoType=TA.class, expect="3")
278 public @TA(3) int [] f3;
280 @Test(posn=1, annoType=TA.class, expect="4")
281 public int m1(@TA(4) float a) throws Exception { return 0; }
283 @Test(posn=2, annoType=TA.class, expect="5")
284 public @TA(5) int m2(float a) throws Exception { return 0; }
286 @Test(posn=3, annoType=TA.class, expect="6")
287 public int m3(float a) throws @TA(6) Exception { return 0; }
288 }