1 /******************************************************************************* 2 * Copyright (c) 2007, 2015 BEA Systems, Inc. and others 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * wharley@bea.com - initial API and implementation 13 * akurtakov@gmail.com - fix compilation with Java 7 14 * 15 *******************************************************************************/ 16 17 package org.eclipse.jdt.compiler.apt.tests.processors.elements; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.Collection; 22 import java.util.HashMap; 23 import java.util.Iterator; 24 import java.util.LinkedHashMap; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.Map.Entry; 28 import java.util.Set; 29 import java.util.stream.Collectors; 30 import java.util.stream.Stream; 31 32 import javax.annotation.processing.RoundEnvironment; 33 import javax.annotation.processing.SupportedAnnotationTypes; 34 import javax.annotation.processing.SupportedSourceVersion; 35 import javax.lang.model.SourceVersion; 36 import javax.lang.model.element.AnnotationMirror; 37 import javax.lang.model.element.AnnotationValue; 38 import javax.lang.model.element.Element; 39 import javax.lang.model.element.ElementKind; 40 import javax.lang.model.element.ExecutableElement; 41 import javax.lang.model.element.Modifier; 42 import javax.lang.model.element.Name; 43 import javax.lang.model.element.NestingKind; 44 import javax.lang.model.element.PackageElement; 45 import javax.lang.model.element.TypeElement; 46 import javax.lang.model.element.VariableElement; 47 import javax.lang.model.type.DeclaredType; 48 import javax.lang.model.type.MirroredTypeException; 49 import javax.lang.model.type.MirroredTypesException; 50 import javax.lang.model.type.TypeKind; 51 import javax.lang.model.type.TypeMirror; 52 import javax.lang.model.util.ElementFilter; 53 54 import org.eclipse.jdt.compiler.apt.tests.annotations.TypedAnnos; 55 import org.eclipse.jdt.compiler.apt.tests.processors.base.BaseProcessor; 56 57 /** 58 * A processor that explores the "model" target hierarchy and complains if it does 59 * not find what it expects. To enable this processor, add 60 * -Aorg.eclipse.jdt.compiler.apt.tests.processors.elements.ElementProc to the command line. 61 * @since 3.3 62 */ 63 @SupportedAnnotationTypes("*") 64 @SupportedSourceVersion(SourceVersion.RELEASE_6) 65 public class ElementProc extends BaseProcessor { 66 67 // The set of elements we expect getRootElements to return in package pa 68 private static final String[] ROOT_ELEMENT_NAMES = new String[] { 69 "targets.model.pa.AnnoZ", "targets.model.pa.A", "targets.model.pa.IA", "targets.model.pa.ExceptionA"}; 70 71 // Initialized in collectElements() 72 private TypeElement _elementIA; 73 private TypeElement _elementAB; 74 private TypeElement _elementA; 75 private TypeElement _elementD; 76 private TypeElement _elementDChild; 77 private TypeElement _elementAnnoZ; 78 private TypeElement _elementString; 79 80 // Initialized in examineDMethods() 81 private ExecutableElement _methodDvoid; 82 private ExecutableElement _methodDvoid2; 83 private ExecutableElement _methodDvoid3; 84 private TypeElement _elementDEnum; 85 86 // Always return false from this processor, because it supports "*". 87 // The return value does not signify success or failure! 88 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)89 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 90 if (roundEnv.processingOver()) { 91 // We're not interested in the postprocessing round. 92 return false; 93 } 94 Map<String, String> options = processingEnv.getOptions(); 95 if (!options.containsKey(this.getClass().getName())) { 96 // Disable this processor unless we are intentionally performing the test. 97 return false; 98 } 99 100 if (!collectElements()) { 101 return false; 102 } 103 104 if (!examineRoundEnv(roundEnv)) { 105 return false; 106 } 107 108 if (!examineABInterfaces()) { 109 return false; 110 } 111 112 if (!examineABModifiers()) { 113 return false; 114 } 115 116 if (!examineDHierarchy()) { 117 return false; 118 } 119 120 if (!examineAMethodsAndFields()) { 121 return false; 122 } 123 124 if (!examineAMethodThrowables()) { 125 return false; 126 } 127 128 if (!examineDMethods()) { 129 return false; 130 } 131 132 if (!examineDEnum()) { 133 return false; 134 } 135 136 if (!examinePBPackage()) { 137 return false; 138 } 139 140 if (!examineDAnnotations()) { 141 return false; 142 } 143 144 if (!examineGetAnnotation()) { 145 return false; 146 } 147 148 if (!bug261969()) { 149 return false; 150 } 151 152 if(!bug300408()) { 153 return false; 154 } 155 if (!examineTypesInPackage()) { 156 return false; 157 } 158 159 if (!bug467928_enumFields()) { 160 return false; 161 } 162 163 reportSuccess(); 164 return false; 165 } 166 bug467928_enumFields()167 private boolean bug467928_enumFields() { 168 TypeElement type = _elementUtils.getTypeElement( "targets.model.enumfields.EnumWithFields"); 169 Map<String, VariableElement> fields = new HashMap<>(); 170 for (Element element : type.getEnclosedElements()) { 171 if (element instanceof VariableElement) { 172 fields.put(element.getSimpleName().toString(), (VariableElement) element); 173 } else if (element instanceof ExecutableElement) { 174 ExecutableElement method = (ExecutableElement) element; 175 if (method.getSimpleName().toString().equals("setField")) { 176 fields.put("param", method.getParameters().get(0)); 177 } 178 } 179 } 180 181 if (fields.get("CONST").getKind() != ElementKind.ENUM_CONSTANT) { 182 return false; 183 } 184 185 if (fields.get("field").getKind() != ElementKind.FIELD) { 186 return false; 187 } 188 if (fields.get("param").getKind() != ElementKind.PARAMETER) { 189 return false; 190 } 191 192 return true; 193 } 194 195 /** 196 * Regression test for Bug 300408, checking if TypeElement.getEnclosedTypes() returns the elements 197 * in the order as declared in the source 198 * 199 * @return true if all tests passed 200 */ bug300408()201 private boolean bug300408() { 202 if (!enclosedElementOrderCorrect( 203 "targets.model.order.Ordered", 204 Arrays.asList(ElementKind.CONSTRUCTOR), 205 "methodB", "field1", "methodA")) { 206 207 return false; 208 } 209 210 if (!enclosedElementOrderCorrect("targets.model.order.EnumInstances", 211 Arrays.asList(ElementKind.CONSTRUCTOR, ElementKind.METHOD), 212 "A", "G", "U", "D", "I", "N")) { 213 214 return false; 215 } 216 217 return true; 218 } 219 enclosedElementOrderCorrect(String className, Collection<ElementKind> ignoredKinds, String ... expectedOrder)220 private boolean enclosedElementOrderCorrect(String className, Collection<ElementKind> ignoredKinds, String ... expectedOrder) { 221 TypeElement elementOrdered = _elementUtils.getTypeElement(className); 222 List<? extends Element> enclosedElements = elementOrdered.getEnclosedElements(); 223 224 List<String> elementNames = new ArrayList<String>(enclosedElements.size()); 225 for (Element e : enclosedElements) { 226 if (!ignoredKinds.contains(e.getKind())) { 227 elementNames.add(e.getSimpleName().toString()); 228 } 229 } 230 231 List<String> expected = Arrays.asList(expectedOrder); 232 233 if (!elementNames.equals(expected)) { 234 reportError("Unexpected order of elements in class " + className + ". Expected: " + expected + ", but got: " + elementNames); 235 return false; 236 } 237 238 return true; 239 } 240 241 /** 242 * Collect some elements that will be reused in various tests 243 * @return true if all tests passed 244 */ collectElements()245 private boolean collectElements() { 246 _elementIA = _elementUtils.getTypeElement("targets.model.pa.IA"); 247 if (_elementIA == null) { 248 reportError("element IA was not found"); 249 return false; 250 } 251 if (_elementIA.getKind() != ElementKind.INTERFACE) { 252 reportError("IA claims to not be an interface"); 253 return false; 254 } 255 if (_elementIA.getNestingKind() != NestingKind.TOP_LEVEL) { 256 reportError("NestingKind of element IA is not TOP_LEVEL"); 257 return false; 258 } 259 260 _elementA = _elementUtils.getTypeElement("targets.model.pa.A"); 261 if (_elementA == null) { 262 reportError("element A was not found"); 263 return false; 264 } 265 if (_elementA.getKind() != ElementKind.CLASS) { 266 reportError("A claims to not be a class"); 267 return false; 268 } 269 270 _elementAnnoZ = _elementUtils.getTypeElement("targets.model.pa.AnnoZ"); 271 if (_elementAnnoZ == null) { 272 reportError("element AnnoZ was not found"); 273 return false; 274 } 275 if (_elementAnnoZ.getKind() != ElementKind.ANNOTATION_TYPE) { 276 reportError("AnnoZ claims to not be an annotation type"); 277 return false; 278 } 279 280 _elementAB = _elementUtils.getTypeElement("targets.model.pb.AB"); 281 if (_elementAB == null) { 282 reportError("element AB was not found"); 283 return false; 284 } 285 if (_elementAB.getKind() != ElementKind.CLASS) { 286 reportError("AB claims to not be a class"); 287 return false; 288 } 289 290 _elementD = _elementUtils.getTypeElement("targets.model.pb.D"); 291 if (_elementD == null) { 292 reportError("element D was not found"); 293 return false; 294 } 295 if (_elementD.getKind() != ElementKind.CLASS) { 296 reportError("D claims to not be a class"); 297 return false; 298 } 299 300 _elementDChild = _elementUtils.getTypeElement("targets.model.pb.DChild"); 301 if (_elementDChild == null) { 302 reportError("secondary element DChild was not found"); 303 return false; 304 } 305 if (_elementDChild.getKind() != ElementKind.CLASS) { 306 reportError("DChild claims to not be a class"); 307 return false; 308 } 309 _elementString = _elementUtils.getTypeElement("java.lang.String"); 310 return true; 311 } 312 313 /** 314 * Check the methods on RoundEnvironment method 315 * @return true if all tests passed 316 */ examineRoundEnv(RoundEnvironment roundEnv)317 private boolean examineRoundEnv(RoundEnvironment roundEnv) { 318 // Verify that we get the root elements we expect 319 Set<String> expectedRootElementNames = Stream.of(ROOT_ELEMENT_NAMES).collect(Collectors.toSet()); 320 Set<? extends Element> actualRootElements = roundEnv.getRootElements(); 321 if (null == actualRootElements) { 322 reportError("getRootElements() returned null"); 323 return false; 324 } 325 for (Element e : actualRootElements) { 326 if (e instanceof TypeElement) { 327 String name = ((TypeElement)e).getQualifiedName().toString(); 328 if (name.startsWith("targets.model.pa.") && !expectedRootElementNames.remove(name)) { 329 reportError("Missing root element " + name); 330 return false; 331 } 332 } 333 } 334 if (!expectedRootElementNames.isEmpty()) { 335 reportError("Found extra root elements including " + expectedRootElementNames.iterator().next()); 336 return false; 337 } 338 339 // Verify that we get the annotations we expect 340 Set<? extends Element> annotatedWithAnnoZ = roundEnv.getElementsAnnotatedWith(_elementAnnoZ); 341 if (null == annotatedWithAnnoZ || !annotatedWithAnnoZ.contains(_elementD)) { 342 reportError("Elements annotated with AnnoZ does not include D"); 343 return false; 344 } 345 346 // targets.model.pc.Deprecation contains @Deprecated annotations 347 Set<? extends Element> annotatedWithDeprecated = roundEnv.getElementsAnnotatedWith(Deprecated.class); 348 if (null == annotatedWithDeprecated) { 349 reportError("getElementsAnnotatedWith(@Deprecated) returned null"); 350 return false; 351 } 352 boolean foundDeprecation = false; 353 for (TypeElement deprecatedElement : ElementFilter.typesIn(annotatedWithDeprecated)) { 354 if ("targets.model.pc.Deprecation".equals(deprecatedElement.getQualifiedName().toString())) { 355 foundDeprecation = true; 356 break; 357 } 358 } 359 if (!foundDeprecation) { 360 reportError("getElementsAnnotatedWith(@Deprecation) did not find targets.model.pc.Deprecation"); 361 } 362 363 return true; 364 } 365 366 /** 367 * Examine the interfaces that AB implements 368 * @return true if all tests passed 369 */ examineABInterfaces()370 private boolean examineABInterfaces() { 371 List<? extends TypeMirror> interfacesAB = _elementAB.getInterfaces(); 372 if (null == interfacesAB) { 373 reportError("AB.getInterfaces() returned null"); 374 return false; 375 } 376 boolean foundIAinterface = false; 377 for (TypeMirror type : interfacesAB) { 378 Element decl = _typeUtils.asElement(type); 379 if (null == decl) { 380 reportError("One of AB's interfaces, " + type.toString() + ", produced null from Types.asElement()"); 381 return false; 382 } 383 if (_elementIA.equals(decl)) { 384 foundIAinterface = true; 385 break; 386 } 387 } 388 if (!foundIAinterface) { 389 reportError("AB does not have IA as an interface"); 390 return false; 391 } 392 return true; 393 } 394 395 /** 396 * Examine the modifiers of AB's contents 397 * @return true if all tests passed 398 */ examineABModifiers()399 private boolean examineABModifiers() { 400 Map<String, Element> contents = new HashMap<String, Element>(); 401 for (Element enclosed : _elementAB.getEnclosedElements()) { 402 contents.put(enclosed.getSimpleName().toString(), enclosed); 403 } 404 Element publicMethod = contents.get("methodIAString"); 405 Element protectedField = contents.get("_fieldListIA"); 406 Element privateClass = contents.get("E"); 407 if (null == publicMethod || null == protectedField || null == privateClass) { 408 reportError("AB does not contain the expected enclosed elements"); 409 return false; 410 } 411 Set<Modifier> modifiers = publicMethod.getModifiers(); 412 if (!modifiers.contains(Modifier.PUBLIC) || modifiers.size() > 1) { 413 reportError("AB.methodIAString() has unexpected modifiers"); 414 return false; 415 } 416 modifiers = protectedField.getModifiers(); 417 if (!modifiers.contains(Modifier.PROTECTED) || modifiers.size() > 1) { 418 reportError("AB._fieldListIA() has unexpected modifiers"); 419 return false; 420 } 421 modifiers = privateClass.getModifiers(); 422 if (!modifiers.contains(Modifier.PRIVATE) || modifiers.size() > 1) { 423 reportError("AB.E() has unexpected modifiers"); 424 return false; 425 } 426 return true; 427 } 428 429 /** 430 * Examine the hierarchy of element D 431 * @return true if all tests passed 432 */ examineDHierarchy()433 private boolean examineDHierarchy() { 434 TypeMirror supertypeD = _elementD.getSuperclass(); 435 if (null == supertypeD) { 436 reportError("element D's supertype was null"); 437 return false; 438 } 439 Element superclassD = _typeUtils.asElement(supertypeD); 440 if (!_elementAB.equals(superclassD)) { 441 reportError("element D's superclass did not equal element AB"); 442 return false; 443 } 444 445 return true; 446 } 447 448 /** 449 * Examine the methods and fields of element A 450 * @return true if all tests passed 451 */ examineAMethodsAndFields()452 private boolean examineAMethodsAndFields() { 453 // METHODS 454 List<? extends Element> enclosedA = _elementA.getEnclosedElements(); 455 if (enclosedA == null) { 456 reportError("elementA.getEnclosedElements() returned null"); 457 return false; 458 } 459 List<ExecutableElement> methodsA = ElementFilter.methodsIn(enclosedA); 460 ExecutableElement methodIAString = null; 461 for (ExecutableElement method : methodsA) { 462 Name methodName = method.getSimpleName(); 463 if ("methodIAString".equals(methodName.toString())) { 464 methodIAString = method; 465 } 466 } 467 if (null == methodIAString) { 468 reportError("element A did not contain methodIAString()"); 469 return false; 470 } 471 if (methodIAString.getKind() != ElementKind.METHOD) { 472 reportError("A.methodIAString is not an ElementKind.METHOD"); 473 return false; 474 } 475 Element enclosingMethodIAStringInA = methodIAString.getEnclosingElement(); 476 if (null == enclosingMethodIAStringInA || !_elementA.equals(enclosingMethodIAStringInA)) { 477 reportError("Element enclosing A.methodIAString() is not A"); 478 return false; 479 } 480 481 // RETURN AND PARAMS 482 TypeMirror returnType = methodIAString.getReturnType(); 483 if (!(returnType instanceof DeclaredType) || returnType.getKind() != TypeKind.DECLARED) { 484 reportError("Return type of A.methodIAString() is not a declared type"); 485 return false; 486 } 487 if (!_elementString.equals(((DeclaredType)returnType).asElement())) { 488 reportError("Return type of A.methodIAString() does not equal java.lang.String"); 489 return false; 490 } 491 List<ExecutableElement> methodsD = ElementFilter.methodsIn(_elementString.getEnclosedElements()); 492 for (ExecutableElement method : methodsD) { 493 List<? extends VariableElement> params = method.getParameters(); 494 for (VariableElement param : params) { 495 Element enclosingElement = param.getEnclosingElement(); 496 if (enclosingElement == null) { 497 reportError("Enclosing element of a parameter in one of the java.lang.String methods is null"); 498 return false; 499 } 500 if (!enclosingElement.equals(method)) { 501 reportError("Enclosing element of a parameter in one of the java.lang.String methods is not the method itself"); 502 return false; 503 } 504 } 505 } 506 List<? extends VariableElement> paramsMethodIAString = methodIAString.getParameters(); 507 VariableElement int1 = null; 508 for (VariableElement param : paramsMethodIAString) { 509 int1 = param; 510 } 511 TypeMirror int1Type = int1.asType(); 512 if (null == int1Type || int1Type.getKind() != TypeKind.INT) { 513 reportError("The first parameter of A.methodIAString() is not of int type"); 514 return false; 515 } 516 if (!("int1".equals(int1.getSimpleName().toString()))) { 517 reportError("The first parameter of A.methodIAString() is not named int1"); 518 return false; 519 } 520 521 // FIELDS 522 List<VariableElement> fieldsA = ElementFilter.fieldsIn(enclosedA); 523 VariableElement fieldAint = null; 524 for (VariableElement field : fieldsA) { 525 Name fieldName = field.getSimpleName(); 526 if ("_fieldAint".equals(fieldName.toString())) { 527 fieldAint = field; 528 } 529 } 530 if (null == fieldAint) { 531 reportError("element A did not contain _fieldAint"); 532 return false; 533 } 534 if (fieldAint.getKind() != ElementKind.FIELD) { 535 reportError("A._fieldAint is not an ElementKind.FIELD"); 536 return false; 537 } 538 return true; 539 } 540 541 /** 542 * Examine the methods of A which have throws clauses 543 * @return true if all tests passed 544 */ examineAMethodThrowables()545 private boolean examineAMethodThrowables() { 546 List<ExecutableElement> methodsA = ElementFilter.methodsIn(_elementA.getEnclosedElements()); 547 ExecutableElement methodIAString = null; // no throws clauses 548 ExecutableElement methodThrows1 = null; 549 ExecutableElement methodThrows2 = null; 550 for (ExecutableElement method : methodsA) { 551 String methodName = method.getSimpleName().toString(); 552 if ("methodIAString".equals(methodName)) { 553 methodIAString = method; 554 } 555 if ("methodThrows1".equals(methodName)) { 556 methodThrows1 = method; 557 } 558 else if ("methodThrows2".equals(methodName)) { 559 methodThrows2 = method; 560 } 561 } 562 if (null == methodIAString || null == methodThrows1 || null == methodThrows2) { 563 reportError("element A did not contain methodIAString(), methodThrows1(), or methodThrows2()"); 564 return false; 565 } 566 List<? extends TypeMirror> thrownTypes0 = methodIAString.getThrownTypes(); 567 List<? extends TypeMirror> thrownTypes1 = methodThrows1.getThrownTypes(); 568 List<? extends TypeMirror> thrownTypes2 = methodThrows2.getThrownTypes(); 569 if (null == thrownTypes0 || null == thrownTypes1 || null == thrownTypes2) { 570 reportError("getThrownTypes() on A.methodIAString(), methodThrows1(), or methodThrows2() returned null"); 571 return false; 572 } 573 if (!thrownTypes0.isEmpty()) { 574 reportError("A.methodIAString unexpectedly reports having a throws clause"); 575 return false; 576 } 577 boolean foundEA = false; 578 for (TypeMirror type : thrownTypes1) { 579 Element element = _typeUtils.asElement(type); 580 if ("ExceptionA".equals(element.getSimpleName().toString())) { 581 foundEA = true; 582 } 583 } 584 if (thrownTypes1.size() != 1 || !foundEA) { 585 reportError("A.methodThrows1() reported unexpected throwables"); 586 return false; 587 } 588 foundEA = false; 589 boolean foundUOE = false; 590 for (TypeMirror type : thrownTypes2) { 591 Element element = _typeUtils.asElement(type); 592 if ("UnsupportedOperationException".equals(element.getSimpleName().toString())) { 593 foundUOE = true; 594 } 595 else if ("ExceptionA".equals(element.getSimpleName().toString())) { 596 foundEA = true; 597 } 598 } 599 if (thrownTypes2.size() != 2 || !foundEA || !foundUOE) { 600 reportError("A.methodThrows2() reported unexpected throwables"); 601 return false; 602 } 603 return true; 604 } 605 606 /** 607 * Examine the methods of D (which are interesting because of an enum param and void return) 608 * @return true if all tests passed 609 */ examineDMethods()610 private boolean examineDMethods() { 611 List<ExecutableElement> methodsD = ElementFilter.methodsIn(_elementD.getEnclosedElements()); 612 _methodDvoid = null; 613 _methodDvoid2 = null; 614 _methodDvoid3 = null; 615 for (ExecutableElement method : methodsD) { 616 Name methodName = method.getSimpleName(); 617 if ("methodDvoid".equals(methodName.toString())) { 618 _methodDvoid = method; 619 } 620 if ("methodDvoid2".equals(methodName.toString())) { 621 _methodDvoid2 = method; 622 } 623 if ("methodDvoid3".equals(methodName.toString())) { 624 _methodDvoid3 = method; 625 } 626 } 627 if (null == _methodDvoid) { 628 reportError("element D did not contain methodDvoid()"); 629 return false; 630 } 631 TypeMirror returnType = _methodDvoid.getReturnType(); 632 if (returnType.getKind() != TypeKind.VOID) { 633 reportError("D.methodDvoid() return type was not void"); 634 return false; 635 } 636 List<? extends VariableElement> params = _methodDvoid.getParameters(); 637 if (null == params || params.isEmpty()) { 638 reportError("D.methodDvoid() reports no parameters"); 639 return false; 640 } 641 VariableElement param1 = params.iterator().next(); 642 TypeMirror param1Type = param1.asType(); 643 if (null == param1Type || param1Type.getKind() != TypeKind.DECLARED) { 644 reportError("First parameter of D.methodDvoid() is not a declared type"); 645 return false; 646 } 647 Element enclosingElement = param1.getEnclosingElement(); 648 if (enclosingElement == null || enclosingElement.getKind() != ElementKind.METHOD) { 649 reportError("Enclosing element of first parameter of D.methodDvoid() is null or not a method"); 650 return false; 651 } 652 if (!"targets.model.pb.D.DEnum".equals(param1Type.toString())) { 653 reportError("Type of first parameter of D.methodDvoid() is not DEnum"); 654 return false; 655 } 656 Element param1TypeElement = ((DeclaredType)param1Type).asElement(); 657 if (null == param1TypeElement || param1TypeElement.getKind() != ElementKind.ENUM || !(param1TypeElement instanceof TypeElement)) { 658 reportError("Type of first parameter of D.methodDvoid() is not an enum"); 659 return false; 660 } 661 _elementDEnum = (TypeElement)param1TypeElement; 662 return true; 663 } 664 665 /** 666 * Check the DEnum type declared inside element D 667 * @return true if all tests passed 668 */ examineDEnum()669 private boolean examineDEnum() 670 { 671 if (_elementDEnum.getNestingKind() != NestingKind.MEMBER) { 672 reportError("Type DEnum is not NestingKind.MEMBER"); 673 return false; 674 } 675 Map<String, VariableElement> values = new LinkedHashMap<String, VariableElement>(); 676 for (VariableElement enclosedElement : ElementFilter.fieldsIn(_elementDEnum.getEnclosedElements())) { 677 values.put(enclosedElement.getSimpleName().toString(), enclosedElement); 678 } 679 if (values.size() != 3) { 680 reportError("DEnum should have three values, but instead has: " + values.size()); 681 return false; 682 } 683 Iterator<String> iter = values.keySet().iterator(); 684 if (!"DEnum1".equals(iter.next()) || !"DEnum2".equals(iter.next()) || !"DEnum3".equals(iter.next())) { 685 reportError("DEnum does not have the expected values in the expected order"); 686 return false; 687 } 688 return true; 689 } 690 691 /** 692 * Check the PackageDeclaration of pb 693 * @return true if all tests passed 694 */ examinePBPackage()695 private boolean examinePBPackage() { 696 Element packagePB = _elementAB.getEnclosingElement(); 697 if (!(packagePB instanceof PackageElement) || packagePB.getKind() != ElementKind.PACKAGE) { 698 reportError("element AB is not enclosed by a package"); 699 return false; 700 } 701 if (!("targets.model.pb".equals(((PackageElement)packagePB).getQualifiedName().toString()))) { 702 reportError("The name of package pb is not targets.model.pb"); 703 return false; 704 } 705 return true; 706 } 707 708 /** 709 * Read the annotations on element D (class and method) 710 * @return true if all tests passed 711 */ examineDAnnotations()712 private boolean examineDAnnotations() { 713 // Examine annotation on class declaration 714 List<? extends AnnotationMirror> annotsD = _elementD.getAnnotationMirrors(); 715 if (null == annotsD || annotsD.isEmpty()) { 716 reportError("element D reports no annotations"); 717 return false; 718 } 719 for (AnnotationMirror annotD : annotsD) { 720 DeclaredType annotDType = annotD.getAnnotationType(); 721 if (null == annotDType) { 722 reportError("annotation mirror of AnnoZ on element D reports null type"); 723 return false; 724 } 725 Element annotDElem = annotDType.asElement(); 726 if (!(annotDElem instanceof TypeElement) || 727 !"targets.model.pa.AnnoZ".equals(((TypeElement)annotDElem).getQualifiedName().toString())) { 728 reportError("annotation on element D is not TypeElement targets.model.pa.AnnoZ"); 729 return false; 730 } 731 Map<? extends ExecutableElement, ? extends AnnotationValue> values = annotD.getElementValues(); 732 if (null == values || values.isEmpty()) { 733 reportError("@AnnoZ on element D reports no values"); 734 return false; 735 } 736 boolean foundStringMethod = false; 737 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : values.entrySet()) { 738 String methodName = entry.getKey().getSimpleName().toString(); 739 if ("annoZString".equals(methodName)) { 740 foundStringMethod = true; 741 Object value = entry.getValue().getValue(); 742 if (!"annoZOnD".equals(value)) { 743 reportError("Value of annoZString param on element D is not \"annoZOnD\""); 744 return false; 745 } 746 } 747 } 748 if (!foundStringMethod) { 749 reportError("Failed to find method annoZString on @AnnoZ on element D"); 750 return false; 751 } 752 753 // Check Elements.getElementValuesWithDefaults() 754 Map<? extends ExecutableElement, ? extends AnnotationValue> defaults = 755 _elementUtils.getElementValuesWithDefaults(annotD); 756 if (null == defaults) { 757 reportError("Element.getElementValuesWithDefaults(annotD) returned null"); 758 return false; 759 } 760 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : defaults.entrySet()) { 761 String methodName = entry.getKey().getSimpleName().toString(); 762 if ("annoZString".equals(methodName)) { 763 foundStringMethod = true; 764 Object value = entry.getValue().getValue(); 765 if (!"annoZOnD".equals(value)) { 766 reportError("Explicit value of AnnoZ.annoZString is not \"annoZOnD\""); 767 return false; 768 } 769 } 770 else if ("annoZint".equals(methodName)) { 771 foundStringMethod = true; 772 Object value = entry.getValue().getValue(); 773 if (null == value || !value.equals(17)) { 774 reportError("Default value of AnnoZ.annoZint() is not 17"); 775 return false; 776 } 777 } 778 } 779 } 780 781 List<? extends AnnotationMirror> annotsMethodDvoid = _methodDvoid.getAnnotationMirrors(); 782 if (null == annotsMethodDvoid || annotsMethodDvoid.isEmpty()) { 783 reportError("method D.methodDvoid() reports no annotations"); 784 return false; 785 } 786 for (AnnotationMirror annotMethodDvoid : annotsMethodDvoid) { 787 DeclaredType annotDType = annotMethodDvoid.getAnnotationType(); 788 if (null == annotDType) { 789 reportError("annotation mirror of AnnoZ on D.methodDvoid() reports null type"); 790 return false; 791 } 792 Element annotDElem = annotDType.asElement(); 793 if (!(annotDElem instanceof TypeElement) || 794 !"targets.model.pa.AnnoZ".equals(((TypeElement)annotDElem).getQualifiedName().toString())) { 795 reportError("annotation on D.methodDvoid() is not TypeElement targets.model.pa.AnnoZ"); 796 return false; 797 } 798 Map<? extends ExecutableElement, ? extends AnnotationValue> values = annotMethodDvoid.getElementValues(); 799 if (null == values || values.isEmpty()) { 800 reportError("@AnnoZ on D.methodDvoid() reports no values"); 801 return false; 802 } 803 boolean foundIntMethod = false; 804 int order = 0; 805 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : values.entrySet()) { 806 String methodName = entry.getKey().getSimpleName().toString(); 807 ++order; 808 if ("annoZint".equals(methodName)) { 809 foundIntMethod = true; 810 Object value = entry.getValue().getValue(); 811 if (!(value instanceof Integer) || (Integer)value != 31) { 812 reportError("Value of annoZint param on D.methodDvoid() is not 31"); 813 return false; 814 } 815 // Annotation value map should preserve order of annotation values 816 if (order != 1) { 817 reportError("The annoZint param on D.methodDvoid should be first in the map, but was " + order); 818 return false; 819 } 820 } 821 } 822 if (!foundIntMethod) { 823 reportError("Failed to find method annoZint on @AnnoZ on D.methodDvoid()"); 824 return false; 825 } 826 } 827 828 // methodDvoid2 is like methodDvoid but the annotation values are in opposite order; 829 // check to see that order has been preserved 830 List<? extends AnnotationMirror> annotsMethodDvoid2 = _methodDvoid2.getAnnotationMirrors(); 831 for (AnnotationMirror annotMethodDvoid2 : annotsMethodDvoid2) { 832 Map<? extends ExecutableElement, ? extends AnnotationValue> values = annotMethodDvoid2.getElementValues(); 833 if (null == values || values.size() != 2) { 834 reportError("@AnnoZ on D.methodDvoid2() should have two values but had: " + 835 (values == null ? 0 : values.size())); 836 return false; 837 } 838 int order = 0; 839 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : values.entrySet()) { 840 String methodName = entry.getKey().getSimpleName().toString(); 841 switch (++order) { 842 case 1: 843 if (!"annoZString".equals(methodName)) { 844 reportError("First value of @AnnoZ on D.methodDvoid2 should be annoZString, but was: " + methodName); 845 return false; 846 } 847 break; 848 case 2: 849 if (!"annoZint".equals(methodName)) { 850 reportError("Second value of @AnnoZ on D.methodDvoid2 should be annoZint, but was: " + methodName); 851 return false; 852 } 853 break; 854 } 855 } 856 } 857 858 // methodDvoid3 has an annotation with string array type, but its value is a single string. 859 // See bug 261969. 860 List<? extends AnnotationMirror> annotsMethodDvoid3 = _methodDvoid3.getAnnotationMirrors(); 861 if (1 != annotsMethodDvoid3.size()) { 862 reportError("Wrong number of annotations on D.methodDvoid3(): expected 1, got " + annotsMethodDvoid3.size()); 863 return false; 864 } 865 AnnotationMirror annotMethodDvoid3 = annotsMethodDvoid3.get(0); 866 Map<? extends ExecutableElement, ? extends AnnotationValue> annotMethodDvoid3Values = annotMethodDvoid3.getElementValues(); 867 if (1 != annotMethodDvoid3Values.size()) { 868 reportError("Wrong number of values on annotation on D.methodDvoid3(): expected 1, got " 869 + annotMethodDvoid3Values.size()); 870 return false; 871 } 872 AnnotationValue annotMethodDvoid3Value = annotMethodDvoid3Values.values().iterator().next(); 873 Object annotMethodDvoid3RealValue = annotMethodDvoid3Value.getValue(); 874 if (null == annotMethodDvoid3RealValue) { 875 reportError("Value of annotation on D.methodDvoid3() was null"); 876 return false; 877 } 878 if (!(annotMethodDvoid3RealValue instanceof List<?>)) { 879 reportError("Expected type of annotation on D.methodDvoid3() to be List<?> but was: " + 880 annotMethodDvoid3RealValue.getClass().getName()); 881 return false; 882 } 883 // If it's a List, then it's a List<AnnotationValue> so we've got another layer to decipher 884 AnnotationValue innerDvoid3Value = ((AnnotationValue)((List<?>)annotMethodDvoid3RealValue).get(0)); 885 if (!"methodDvoid3Value".equals((String)innerDvoid3Value.getValue())) { 886 reportError("Expected value of annotation on D.methodDvoid3() to be \"methodDvoid3Value\" but was: " + 887 innerDvoid3Value.getValue()); 888 return false; 889 } 890 891 return true; 892 } 893 894 /** 895 * Test the Element.getAnnotation() implementation 896 * @return true if all tests passed 897 */ examineGetAnnotation()898 private boolean examineGetAnnotation() { 899 TypeElement annotatedElement = _elementUtils.getTypeElement("targets.model.pc.AnnotatedWithManyTypes.Annotated"); 900 if (null == annotatedElement || annotatedElement.getKind() != ElementKind.CLASS) { 901 reportError("examineGetAnnotation: couldn't get AnnotatedWithManyTypes.Annotated element"); 902 return false; 903 } 904 final String badValue = "examineGetAnnotation: unexpected value for "; 905 TypedAnnos.AnnoByte annoByte = annotatedElement.getAnnotation(TypedAnnos.AnnoByte.class); 906 if (null == annoByte || annoByte.value() != 3) { 907 reportError(badValue + "AnnoByte"); 908 return false; 909 } 910 TypedAnnos.AnnoBoolean annoBoolean = annotatedElement.getAnnotation(TypedAnnos.AnnoBoolean.class); 911 if (null == annoBoolean || !annoBoolean.value()) { 912 reportError(badValue + "AnnoBoolean"); 913 return false; 914 } 915 TypedAnnos.AnnoChar annoChar = annotatedElement.getAnnotation(TypedAnnos.AnnoChar.class); 916 if (null == annoChar || annoChar.value() != 'c') { 917 reportError(badValue + "AnnoChar"); 918 return false; 919 } 920 TypedAnnos.AnnoDouble annoDouble = annotatedElement.getAnnotation(TypedAnnos.AnnoDouble.class); 921 if (null == annoDouble || annoDouble.value() != 6.3) { 922 reportError(badValue + "AnnoDouble"); 923 return false; 924 } 925 TypedAnnos.AnnoFloat annoFloat = annotatedElement.getAnnotation(TypedAnnos.AnnoFloat.class); 926 if (null == annoFloat || annoFloat.value() != 26.7F) { 927 reportError(badValue + "AnnoFloat"); 928 return false; 929 } 930 TypedAnnos.AnnoInt annoInt = annotatedElement.getAnnotation(TypedAnnos.AnnoInt.class); 931 if (null == annoInt || annoInt.value() != 19) { 932 reportError(badValue + "AnnoInt"); 933 return false; 934 } 935 TypedAnnos.AnnoLong annoLong = annotatedElement.getAnnotation(TypedAnnos.AnnoLong.class); 936 if (null == annoLong || annoLong.value() != 300L) { 937 reportError(badValue + "AnnoLong"); 938 return false; 939 } 940 TypedAnnos.AnnoShort annoShort = annotatedElement.getAnnotation(TypedAnnos.AnnoShort.class); 941 if (null == annoShort || annoShort.value() != 289) { 942 reportError(badValue + "AnnoShort"); 943 return false; 944 } 945 TypedAnnos.AnnoString annoString = annotatedElement.getAnnotation(TypedAnnos.AnnoString.class); 946 if (null == annoString || !"foo".equals(annoString.value())) { 947 reportError(badValue + "AnnoString"); 948 return false; 949 } 950 TypedAnnos.AnnoEnumConst annoEnumConst = annotatedElement.getAnnotation(TypedAnnos.AnnoEnumConst.class); 951 if (null == annoEnumConst || annoEnumConst.value() != TypedAnnos.Enum.A) { 952 reportError(badValue + "AnnoEnumConst"); 953 return false; 954 } 955 TypedAnnos.AnnoType annoType = annotatedElement.getAnnotation(TypedAnnos.AnnoType.class); 956 if (null == annoType) { 957 reportError(badValue + "AnnoType"); 958 return false; 959 } 960 try { 961 Class<?> clazz = annoType.value(); 962 reportError("examineGetAnnotation: annoType.value() should have thrown a MirroredTypeException but instead returned " + clazz); 963 return false; 964 } 965 catch (MirroredTypeException mte) { 966 TypeMirror clazzMirror = mte.getTypeMirror(); 967 if (null == clazzMirror || clazzMirror.getKind() != TypeKind.DECLARED) { 968 reportError("examineGetAnnotation: annoType.value() returned an incorrect mirror: " + clazzMirror); 969 return false; 970 } 971 } 972 TypedAnnos.AnnoAnnoChar annoAnnoChar = annotatedElement.getAnnotation(TypedAnnos.AnnoAnnoChar.class); 973 if (null == annoAnnoChar || null == annoAnnoChar.value() || 'x' != annoAnnoChar.value().value()) { 974 reportError(badValue + "AnnoAnnoChar"); 975 return false; 976 } 977 978 TypedAnnos.AnnoArrayInt annoArrayInt = annotatedElement.getAnnotation(TypedAnnos.AnnoArrayInt.class); 979 if (null == annoArrayInt) { 980 reportError(badValue + "AnnoArrayInt"); 981 return false; 982 } 983 int[] arrayInt = annoArrayInt.value(); 984 if (arrayInt == null || arrayInt.length != 3 || arrayInt[1] != 8) { 985 reportError(badValue + "AnnoArrayInt contents"); 986 return false; 987 } 988 989 TypedAnnos.AnnoArrayString annoArrayString = annotatedElement.getAnnotation(TypedAnnos.AnnoArrayString.class); 990 if (null == annoArrayString) { 991 reportError(badValue + "AnnoArrayString"); 992 return false; 993 } 994 String[] arrayString = annoArrayString.value(); 995 if (arrayString == null || arrayString.length != 2 || !"quux".equals(arrayString[1])) { 996 reportError(badValue + "AnnoArrayString contents"); 997 return false; 998 } 999 //TODO: AnnoArrayAnnoChar 1000 //TODO: AnnoArrayEnumConst 1001 TypedAnnos.AnnoArrayType annoArrayType = annotatedElement.getAnnotation(TypedAnnos.AnnoArrayType.class); 1002 if (null == annoArrayType) { 1003 reportError(badValue + "AnnoArrayType"); 1004 return false; 1005 } 1006 try { 1007 Class<?>[] contents = annoArrayType.value(); 1008 reportError("examineGetAnnotation: annoArrayType.value() should have thrown a MirroredTypesException but instead returned " + contents); 1009 return false; 1010 } 1011 catch (MirroredTypeException mte) { 1012 // ignore, because javac incorrectly throws this; see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519115 1013 } 1014 catch (MirroredTypesException mte) { 1015 List<? extends TypeMirror> clazzMirrors = mte.getTypeMirrors(); 1016 if (null == clazzMirrors || clazzMirrors.size() != 2) { 1017 reportError("examineGetAnnotation: annoArrayType.value() returned an incorrect mirror list"); 1018 return false; 1019 } 1020 } 1021 return true; 1022 } 1023 1024 /** 1025 * Regression test for bug 261969, retrieving annotation value for string[]-typed 1026 * annotation where the actual value is a non-arrayed string. 1027 * @return true if all tests passed 1028 */ bug261969()1029 private boolean bug261969() { 1030 TypeElement annotatedElement = _elementUtils.getTypeElement("targets.model.pc.Bug261969.Annotated"); 1031 if (null == annotatedElement || annotatedElement.getKind() != ElementKind.CLASS) { 1032 reportError("bug261969: couldn't get Bug261969.Annotated element"); 1033 return false; 1034 } 1035 final String badValue = "bug261969: unexpected value for "; 1036 TypedAnnos.AnnoArrayString annoArrayString = annotatedElement.getAnnotation(TypedAnnos.AnnoArrayString.class); 1037 if (null == annoArrayString) { 1038 reportError(badValue + "AnnoArrayString"); 1039 return false; 1040 } 1041 String[] arrayString = annoArrayString.value(); 1042 if (arrayString == null || arrayString.length != 1 || !"foo".equals(arrayString[0])) { 1043 reportError(badValue + "AnnoArrayString contents"); 1044 return false; 1045 } 1046 return true; 1047 } examineTypesInPackage()1048 private boolean examineTypesInPackage() { 1049 PackageElement pack = _elementUtils.getPackageElement("java.util.concurrent"); 1050 List<? extends Element> enclosedElements = pack.getEnclosedElements(); 1051 if (enclosedElements.size() == 0) { 1052 reportError("Should find types in package java.util.concurrent"); 1053 return false; 1054 } 1055 return true; 1056 } 1057 } 1058