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