/******************************************************************************* * Copyright (c) 2007 BEA Systems, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * wharley@bea.com - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.compiler.apt.tests.processors.visitors; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.AbstractAnnotationValueVisitor6; import javax.lang.model.util.ElementScanner6; import org.eclipse.jdt.compiler.apt.tests.processors.base.BaseProcessor; /** * Processor that tests a variety of Visitors */ @SupportedAnnotationTypes({"*"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) public class VisitorProc extends BaseProcessor { /** * This visitor is invoked on the top-level types in resources/targets/model. * We expect to see each of the visitX() methods get hit as a result. */ private static class ElementVisitorTester extends ElementScanner6<Void, Void> { public enum Visited { TYPE, EXECUTABLE, VARIABLE, TYPEPARAM, PACKAGE, UNKNOWN } private EnumSet<Visited> _visited = EnumSet.noneOf(Visited.class); public boolean checkVisits() { boolean asExpected = true; asExpected &= _visited.contains(Visited.TYPE); asExpected &= _visited.contains(Visited.EXECUTABLE); asExpected &= _visited.contains(Visited.VARIABLE); // TODO: Following two cases not yet implemented: //asExpected &= _visited.contains(Visited.TYPEPARAM); //asExpected &= _visited.contains(Visited.PACKAGE); return asExpected; } /** * Check that we can visit types. * @return true if all tests passed */ @Override public Void visitType(TypeElement e, Void p) { _visited.add(Visited.TYPE); // Scan the type's subtypes, fields, and methods return super.visitType(e, p); } /** * Check that we can visit methods. */ @Override public Void visitExecutable(ExecutableElement e, Void p) { _visited.add(Visited.EXECUTABLE); // Scan the method's parameters return super.visitExecutable(e, p); } /** * Check that we can visit variables. */ @Override public Void visitVariable(VariableElement e, Void p) { _visited.add(Visited.VARIABLE); // Variables do not enclose any elements, so no need to call super. return null; } /** * Check that we can visit type parameters. */ @Override public Void visitTypeParameter(TypeParameterElement e, Void p) { _visited.add(Visited.TYPEPARAM); // Type parameters do not enclose any elements, so no need to call super. return null; } /** * Check that we can visit packages. */ @Override public Void visitPackage(PackageElement e, Void p) { _visited.add(Visited.PACKAGE); // We don't want to scan the package's types here, so don't call super. return null; } /** * This should not actually be encountered. */ @Override public Void visitUnknown(Element e, Void p) { _visited.add(Visited.UNKNOWN); return null; } } /* * The specific values checked by this visitor correspond to values in targets.model.pc.TypedAnnos.java */ private static class AnnotationVisitorTester extends AbstractAnnotationValueVisitor6<Void, Void> { public enum Visited { ANNOTATION, ARRAY, BOOLEAN, BYTE, CHAR, DOUBLE, ENUMCONSTANT, FLOAT, INT, LONG, SHORT, STRING, TYPE } private EnumSet<Visited> _visited = EnumSet.noneOf(Visited.class); public boolean checkVisits() { boolean asExpected = true; asExpected &= _visited.contains(Visited.ANNOTATION); asExpected &= _visited.contains(Visited.ARRAY); asExpected &= _visited.contains(Visited.BOOLEAN); asExpected &= _visited.contains(Visited.BYTE); asExpected &= _visited.contains(Visited.CHAR); asExpected &= _visited.contains(Visited.DOUBLE); asExpected &= _visited.contains(Visited.ENUMCONSTANT); asExpected &= _visited.contains(Visited.FLOAT); asExpected &= _visited.contains(Visited.INT); asExpected &= _visited.contains(Visited.LONG); asExpected &= _visited.contains(Visited.SHORT); asExpected &= _visited.contains(Visited.STRING); asExpected &= _visited.contains(Visited.TYPE); return asExpected; } @Override public Void visitAnnotation(AnnotationMirror a, Void p) { if (a != null && a.getElementValues() != null) { _visited.add(Visited.ANNOTATION); } // we could scan the values of the nested annotation here, but that doesn't help our test case return null; } @Override public Void visitArray(List<? extends AnnotationValue> vals, Void p) { if ( null != vals && vals.size() == 2 ) { if ( vals.iterator().next().getValue() instanceof TypeMirror) { _visited.add(Visited.ARRAY); } } // we could scan the array values here, but that doesn't help our test case return null; } @Override public Void visitBoolean(boolean b, Void p) { if (b) { _visited.add(Visited.BOOLEAN); } return null; } @Override public Void visitByte(byte b, Void p) { if (b == 3) { _visited.add(Visited.BYTE); } return null; } @Override public Void visitChar(char c, Void p) { if (c == 'c') { _visited.add(Visited.CHAR); } return null; } @Override public Void visitDouble(double d, Void p) { if (d == 6.3) { _visited.add(Visited.DOUBLE); } return null; } @Override public Void visitEnumConstant(VariableElement c, Void p) { if (c.getKind() == ElementKind.ENUM_CONSTANT) { if ("A".equals(c.getSimpleName().toString())) { _visited.add(Visited.ENUMCONSTANT); } } return null; } @Override public Void visitFloat(float f, Void p) { if (f == 26.7F) { _visited.add(Visited.FLOAT); } return null; } @Override public Void visitInt(int i, Void p) { if (i == 19) { _visited.add(Visited.INT); } return null; } @Override public Void visitLong(long i, Void p) { if (i == 300L) { _visited.add(Visited.LONG); } return null; } @Override public Void visitShort(short s, Void p) { if (s == 289) { _visited.add(Visited.SHORT); } return null; } @Override public Void visitString(String s, Void p) { if ("foo".equals(s)) { _visited.add(Visited.STRING); } return null; } @Override public Void visitType(TypeMirror t, Void p) { if ("java.lang.Exception".equals(t.toString())) { _visited.add(Visited.TYPE); } return null; } } @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } Map<String, String> options = processingEnv.getOptions(); if (!options.containsKey(this.getClass().getName())) { // Disable this processor unless we are intentionally performing the test. return false; } ElementVisitorTester elementVisitor = new ElementVisitorTester(); elementVisitor.scan(roundEnv.getRootElements(), null); if (!elementVisitor.checkVisits()) { reportError("Element visitor was not visited as expected"); return false; } AnnotationVisitorTester annoValVisitor = new AnnotationVisitorTester(); TypeElement typedAnnosDecl = _elementUtils.getTypeElement("org.eclipse.jdt.compiler.apt.tests.annotations.TypedAnnos"); if (null == typedAnnosDecl) { reportError("Couldn't find targets.model.pc.AnnotatedWithManyTypes"); return false; } for (TypeElement anno : annotations) { if (typedAnnosDecl.equals(anno.getEnclosingElement())) { for (Element elem : roundEnv.getElementsAnnotatedWith(anno)) { for (AnnotationMirror annoMirror : elem.getAnnotationMirrors()) { if (anno.equals(annoMirror.getAnnotationType().asElement())) { Map<? extends ExecutableElement, ? extends AnnotationValue> values = annoMirror.getElementValues(); for (AnnotationValue val : values.values()) { val.accept(annoValVisitor, null); } } } } } } if (!annoValVisitor.checkVisits()) { reportError("Annotation value visitor was not visited as expected"); return false; } reportSuccess(); return false; } }