1 /*
   2  * Copyright 2005-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package com.sun.tools.javac.processing;
  27 
  28 import java.lang.annotation.Annotation;
  29 import com.sun.tools.javac.tree.JCTree.*;
  30 import javax.annotation.processing.*;
  31 import javax.lang.model.element.*;
  32 import javax.lang.model.type.DeclaredType;
  33 import javax.lang.model.type.TypeMirror;
  34 import javax.lang.model.util.*;
  35 import java.util.*;
  36 
  37 /**
  38  * Object providing state about a prior round of annotation processing.
  39  *
  40  * <p><b>This is NOT part of any API supported by Sun Microsystems.
  41  * If you write code that depends on this, you do so at your own risk.
  42  * This code and its internal interfaces are subject to change or
  43  * deletion without notice.</b>
  44  */
  45 public class JavacRoundEnvironment implements RoundEnvironment {
  46     // Default equals and hashCode methods are okay.
  47 
  48     private final boolean processingOver;
  49     private final boolean errorRaised;
  50     private final ProcessingEnvironment processingEnv;
  51 
  52     // Caller must pass in an immutable set
  53     private final Set<? extends Element> rootElements;
  54 
  55     JavacRoundEnvironment(boolean processingOver,
  56                           boolean errorRaised,
  57                           Set<? extends Element> rootElements,
  58                           ProcessingEnvironment processingEnv) {
  59         this.processingOver = processingOver;
  60         this.errorRaised = errorRaised;
  61         this.rootElements = rootElements;
  62         this.processingEnv = processingEnv;
  63     }
  64 
  65     public String toString() {
  66         return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
  67                              errorRaised,
  68                              rootElements,
  69                              processingOver);
  70     }
  71 
  72     public boolean processingOver() {
  73         return processingOver;
  74     }
  75 
  76     /**
  77      * Returns {@code true} if an error was raised in the prior round
  78      * of processing; returns {@code false} otherwise.
  79      *
  80      * @return {@code true} if an error was raised in the prior round
  81      * of processing; returns {@code false} otherwise.
  82      */
  83     public boolean errorRaised() {
  84         return errorRaised;
  85     }
  86 
  87     /**
  88      * Returns the type elements specified by the prior round.
  89      *
  90      * @return the types elements specified by the prior round, or an
  91      * empty set if there were none
  92      */
  93     public Set<? extends Element> getRootElements() {
  94         return rootElements;
  95     }
  96 
  97     private static final String NOT_AN_ANNOTATION_TYPE =
  98         "The argument does not represent an annotation type: ";
  99 
 100     /**
 101      * Returns the elements annotated with the given annotation type.
 102      * Only type elements <i>included</i> in this round of annotation
 103      * processing, or declarations of members, parameters, or type
 104      * parameters declared within those, are returned.  Included type
 105      * elements are {@linkplain #getSpecifiedTypeElements specified
 106      * types} and any types nested within them.
 107      *
 108      * @param a  annotation type being requested
 109      * @return the elements annotated with the given annotation type,
 110      * or an empty set if there are none
 111      */
 112     public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
 113         Set<Element> result = Collections.emptySet();
 114         Types typeUtil = processingEnv.getTypeUtils();
 115         if (a.getKind() != ElementKind.ANNOTATION_TYPE)
 116             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
 117 
 118         DeclaredType annotationTypeElement;
 119         TypeMirror tm = a.asType();
 120         if ( tm instanceof DeclaredType )
 121             annotationTypeElement = (DeclaredType) a.asType();
 122         else
 123             throw new AssertionError("Bad implementation type for " + tm);
 124 
 125         ElementScanner6<Set<Element>, DeclaredType> scanner =
 126             new AnnotationSetScanner(result, typeUtil);
 127 
 128         for (Element element : rootElements)
 129             result = scanner.scan(element, annotationTypeElement);
 130 
 131         return result;
 132     }
 133 
 134     // Could be written as a local class inside getElementsAnnotatedWith
 135     private class AnnotationSetScanner extends
 136         ElementScanner6<Set<Element>, DeclaredType> {
 137         // Insertion-order preserving set
 138         Set<Element> annotatedElements = new LinkedHashSet<Element>();
 139         Types typeUtil;
 140 
 141         AnnotationSetScanner(Set<Element> defaultSet, Types typeUtil) {
 142             super(defaultSet);
 143             this.typeUtil = typeUtil;
 144         }
 145 
 146         @Override
 147         public Set<Element> scan(Element e, DeclaredType p) {
 148             java.util.List<? extends AnnotationMirror> annotationMirrors =
 149                 processingEnv.getElementUtils().getAllAnnotationMirrors(e);
 150             for (AnnotationMirror annotationMirror : annotationMirrors) {
 151                 if (typeUtil.isSameType(annotationMirror.getAnnotationType(), p))
 152                     annotatedElements.add(e);
 153             }
 154             e.accept(this, p);
 155             return annotatedElements;
 156         }
 157 
 158     }
 159 
 160     /**
 161      * {@inheritdoc}
 162      */
 163     public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
 164         if (!a.isAnnotation())
 165             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
 166         String name = a.getCanonicalName();
 167         if (name == null)
 168             return Collections.emptySet();
 169         else {
 170             TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
 171             if (annotationType == null)
 172                 return Collections.emptySet();
 173             else
 174                 return getElementsAnnotatedWith(annotationType);
 175         }
 176     }
 177 }