BasicAnnoTests.java revision 2628:8df25ec8c930
143561Skato/* 243561Skato * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 343561Skato * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 443561Skato * 543561Skato * This code is free software; you can redistribute it and/or modify it 643561Skato * under the terms of the GNU General Public License version 2 only, as 743561Skato * published by the Free Software Foundation. 843561Skato * 943561Skato * This code is distributed in the hope that it will be useful, but WITHOUT 1043561Skato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1143561Skato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1243561Skato * version 2 for more details (a copy is included in the LICENSE file that 1343561Skato * accompanied this code). 1443561Skato * 1543561Skato * You should have received a copy of the GNU General Public License version 1643561Skato * 2 along with this work; if not, write to the Free Software Foundation, 1750477Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1843561Skato * 1943561Skato * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2043561Skato * or visit www.oracle.com if you need additional information or have any 2143561Skato * questions. 2243561Skato */ 2343561Skato 24229501Sjhb/* 2543561Skato * @test 2643561Skato * @bug 8013852 2743561Skato * @summary Annotations on types 2843561Skato * @library /tools/javac/lib 2943561Skato * @ignore 8057688 type annotations in type argument position are lost 3043561Skato * @ignore 8031744 Annotations on many Language Model elements are not returned 3143561Skato * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests 3243561Skato * @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java 3343561Skato */ 3443561Skato 3543561Skatoimport java.io.PrintWriter; 3643561Skatoimport java.lang.annotation.Annotation; 3743561Skatoimport java.lang.annotation.ElementType; 3843561Skatoimport java.lang.annotation.Target; 3943561Skatoimport java.util.Map; 4043561Skatoimport java.util.Set; 4143561Skato 4243561Skatoimport javax.annotation.processing.ProcessingEnvironment; 4343561Skatoimport javax.annotation.processing.RoundEnvironment; 4443561Skatoimport javax.lang.model.AnnotatedConstruct; 4543561Skatoimport javax.lang.model.element.AnnotationMirror; 4643561Skatoimport javax.lang.model.element.AnnotationValue; 4743561Skatoimport javax.lang.model.element.Element; 4843561Skatoimport javax.lang.model.element.ExecutableElement; 4943561Skatoimport javax.lang.model.element.TypeElement; 5043561Skatoimport javax.lang.model.type.ArrayType; 5143561Skatoimport javax.lang.model.type.ExecutableType; 5243561Skatoimport javax.lang.model.type.TypeMirror; 5343561Skatoimport javax.lang.model.type.TypeVariable; 5443561Skatoimport javax.lang.model.type.WildcardType; 5543561Skatoimport javax.tools.Diagnostic.Kind; 5643561Skato 5743561Skatoimport com.sun.tools.javac.code.Symbol; 5843561Skatoimport com.sun.tools.javac.code.Type; 5943561Skatoimport com.sun.tools.javac.processing.JavacProcessingEnvironment; 6043561Skato 61229501Sjhb/** 62229501Sjhb * The test scans this file looking for test cases annotated with @Test. 63229501Sjhb */ 6443561Skatopublic class BasicAnnoTests extends JavacTestingAbstractProcessor { 6543561Skato DPrinter dprinter; 6643561Skato PrintWriter out; 6743561Skato boolean verbose = true; 68 69 @Override 70 public void init(ProcessingEnvironment pEnv) { 71 super.init(pEnv); 72 dprinter = new DPrinter(((JavacProcessingEnvironment) pEnv).getContext()); 73 out = dprinter.out; 74 } 75 76 @Override 77 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 78 TestElementScanner s = new TestElementScanner(); 79 for (Element e: roundEnv.getRootElements()) { 80 s.scan(e); 81 } 82 return true; 83 } 84 85 void error(Element e, String msg) { 86 messager.printMessage(Kind.ERROR, msg, e); 87 errors++; 88 } 89 90 int errors; 91 92 /** 93 * Scan an element looking for declarations annotated with @Test. 94 * Run a TestTypeScanner on the annotations that are found. 95 */ 96 class TestElementScanner extends ElementScanner<Void,Void> { 97 public Void scan(Element elem, Void ignore) { 98 AnnotationMirror test = getAnnotation(elem, Test.class.getName().replace('$', '.')); 99 if (test != null) { 100 out.println("Test: " + elem + " " + test); 101 TestTypeScanner s = new TestTypeScanner(elem, test); 102 s.scan(elem.asType(), null); 103 if (getPosn(test) >= s.count) 104 error(elem, "position " + getPosn(test) + " not found"); 105 if (!s.found) { 106 dprinter.printSymbol("element", (Symbol) elem); 107 dprinter.printType("type", (Type) elem.asType()); 108 } 109 out.println(); 110 } 111 return super.scan(elem, ignore); 112 } 113 } 114 115 /** 116 * Scan the type of an element, looking for an annotation 117 * to match the expected annotation specified in the @Test annotation. 118 */ 119 class TestTypeScanner extends TypeScanner<Void, Void> { 120 Element elem; 121 AnnotationMirror test; 122 int count = 0; 123 boolean found = false; 124 125 TestTypeScanner(Element elem, AnnotationMirror test) { 126 this.elem = elem; 127 this.test = test; 128 } 129 130 @Override 131 Void scan(TypeMirror t, Void ignore) { 132 if (t == null) 133 return DEFAULT_VALUE; 134 if (verbose) 135 out.println("scan " + count + ": " + t); 136 if (count == getPosn(test)) { 137 String annoType = getAnnoType(test); 138 AnnotationMirror anno = getAnnotation(t, annoType); 139 if (anno == null) { 140 error(elem, "annotation not found on " + count + ": " + t); 141 } else { 142 String v = getValue(anno, "value").toString(); 143 if (v.equals(getExpect(test))) { 144 out.println("found " + anno + " as expected"); 145 found = true; 146 } else { 147 error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test)); 148 } 149 } 150 } 151 count++; 152 return super.scan(t, ignore); 153 } 154 } 155 156 /** Get the position value from an @Test annotation mirror. */ 157 static int getPosn(AnnotationMirror test) { 158 AnnotationValue v = getValue(test, "posn"); 159 return (Integer) v.getValue(); 160 } 161 162 /** Get the expect value from an @Test annotation mirror. */ 163 static String getExpect(AnnotationMirror test) { 164 AnnotationValue v = getValue(test, "expect"); 165 return (String) v.getValue(); 166 } 167 168 /** Get the annoType value from an @Test annotation mirror. */ 169 static String getAnnoType(AnnotationMirror test) { 170 AnnotationValue v = getValue(test, "annoType"); 171 TypeMirror m = (TypeMirror) v.getValue(); 172 return m.toString(); 173 } 174 175 /** 176 * Get a specific annotation mirror from an annotated construct. 177 */ 178 static AnnotationMirror getAnnotation(AnnotatedConstruct e, String name) { 179 for (AnnotationMirror m: e.getAnnotationMirrors()) { 180 TypeElement te = (TypeElement) m.getAnnotationType().asElement(); 181 if (te.getQualifiedName().contentEquals(name)) { 182 return m; 183 } 184 } 185 return null; 186 } 187 188 /** 189 * Get a specific value from an annotation mirror. 190 */ 191 static AnnotationValue getValue(AnnotationMirror anno, String name) { 192 Map<? extends ExecutableElement, ? extends AnnotationValue> map = anno.getElementValues(); 193 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e: map.entrySet()) { 194 if (e.getKey().getSimpleName().contentEquals(name)) { 195 return e.getValue(); 196 } 197 } 198 return null; 199 } 200 201 /** 202 * The Language Model API does not provide a type scanner, so provide 203 * one sufficient for our needs. 204 */ 205 static class TypeScanner<R, P> extends SimpleTypeVisitor<R, P> { 206 @Override 207 public R visitArray(ArrayType t, P p) { 208 scan(t.getComponentType(), p); 209 return super.visitArray(t, p); 210 } 211 212 @Override 213 public R visitExecutable(ExecutableType t, P p) { 214 scan(t.getReceiverType()); 215 //out.println(" params: " + t.getParameterTypes()); 216 scan(t.getParameterTypes(), p); 217 //out.println(" return: " + t.getReturnType()); 218 scan(t.getReturnType(), p); 219 //out.println(" throws: " + t.getThrownTypes()); 220 scan(t.getThrownTypes(), p); 221 return super.visitExecutable(t, p); 222 } 223 224 @Override 225 public R visitTypeVariable(TypeVariable t, P p) { 226 scan(t.getLowerBound(), p); 227 scan(t.getUpperBound(), p); 228 return super.visitTypeVariable(t, p); 229 } 230 231 @Override 232 public R visitWildcard(WildcardType t, P p) { 233 scan(t.getExtendsBound(), p); 234 scan(t.getSuperBound(), p); 235 return super.visitWildcard(t, p); 236 } 237 238 R scan(TypeMirror t) { 239 return scan(t, null); 240 } 241 242 R scan(TypeMirror t, P p) { 243 return (t == null) ? DEFAULT_VALUE : t.accept(this, p); 244 } 245 246 R scan(Iterable<? extends TypeMirror> iter, P p) { 247 if (iter == null) 248 return DEFAULT_VALUE; 249 R result = DEFAULT_VALUE; 250 for (TypeMirror t: iter) 251 result = scan(t, p); 252 return result; 253 } 254 } 255 256 /** Annotation to identify test cases. */ 257 @interface Test { 258 /** Where to look for the annotation, expressed as a scan index. */ 259 int posn(); 260 /** The annotation to look for. */ 261 Class<? extends Annotation> annoType(); 262 /** The string representation of the annotation's value. */ 263 String expect(); 264 } 265 266 /** Type annotation to use in test cases. */ 267 @Target(ElementType.TYPE_USE) 268 public @interface TA { 269 int value(); 270 } 271 272 @Test(posn=0, annoType=TA.class, expect="1") 273 public @TA(1) int f1; 274 275 @Test(posn=0, annoType=TA.class, expect="2") 276 public int @TA(2) [] f2; 277 278 @Test(posn=1, annoType=TA.class, expect="3") 279 public @TA(3) int [] f3; 280 281 @Test(posn=1, annoType=TA.class, expect="4") 282 public int m1(@TA(4) float a) throws Exception { return 0; } 283 284 @Test(posn=2, annoType=TA.class, expect="5") 285 public @TA(5) int m2(float a) throws Exception { return 0; } 286 287 @Test(posn=3, annoType=TA.class, expect="6") 288 public int m3(float a) throws @TA(6) Exception { return 0; } 289} 290