1 /*
   2  * Copyright 2005-2008 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         if (a.getKind() != ElementKind.ANNOTATION_TYPE)
 115             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
 116 
 117         DeclaredType annotationTypeElement;
 118         TypeMirror tm = a.asType();
 119         if ( tm instanceof DeclaredType )
 120             annotationTypeElement = (DeclaredType) a.asType();
 121         else
 122             throw new AssertionError("Bad implementation type for " + tm);
 123 
 124         ElementScanner6<Set<Element>, DeclaredType> scanner =
 125             new AnnotationSetScanner(result);
 126 
 127         for (Element element : rootElements)
 128             result = scanner.scan(element, annotationTypeElement);
 129 
 130         return result;
 131     }
 132 
 133     // Could be written as a local class inside getElementsAnnotatedWith
 134     private class AnnotationSetScanner extends
 135         ElementScanner6<Set<Element>, DeclaredType> {
 136         // Insertion-order preserving set
 137         Set<Element> annotatedElements = new LinkedHashSet<Element>();
 138 
 139         AnnotationSetScanner(Set<Element> defaultSet) {
 140             super(defaultSet);
 141         }
 142 
 143         @Override
 144         public Set<Element> scan(Element e, DeclaredType p) {
 145             java.util.List<? extends AnnotationMirror> annotationMirrors =
 146                 processingEnv.getElementUtils().getAllAnnotationMirrors(e);
 147             for (AnnotationMirror annotationMirror : annotationMirrors) {
 148                 if (annotationMirror.getAnnotationType().equals(p))
 149                     annotatedElements.add(e);
 150             }
 151             e.accept(this, p);
 152             return annotatedElements;
 153         }
 154 
 155     }
 156 
 157     /**
 158      * {@inheritdoc}
 159      */
 160     public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
 161         if (!a.isAnnotation())
 162             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
 163         String name = a.getCanonicalName();
 164         if (name == null)
 165             return Collections.emptySet();
 166         else {
 167             TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
 168             if (annotationType == null)
 169                 return Collections.emptySet();
 170             else
 171                 return getElementsAnnotatedWith(annotationType);
 172         }
 173     }
 174 }