1 /*
   2  * Copyright (c) 2005, 2014, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.processing;
  27 
  28 import java.lang.annotation.Annotation;
  29 import javax.annotation.processing.*;
  30 import javax.lang.model.element.*;
  31 import javax.lang.model.util.*;
  32 import java.util.*;
  33 
  34 /**
  35  * Object providing state about a prior round of annotation processing.
  36  *
  37  * <p>The methods in this class do not take type annotations into account,
  38  * as target types, not java elements.
  39  *
  40  * <p><b>This is NOT part of any supported API.
  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 #getRootElements 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         ElementScanner8<Set<Element>, TypeElement> scanner =
 118             new AnnotationSetScanner(result);
 119 
 120         for (Element element : rootElements)
 121             result = scanner.scan(element, a);
 122 
 123         return result;
 124     }
 125 
 126     // Could be written as a local class inside getElementsAnnotatedWith
 127     private class AnnotationSetScanner extends
 128         ElementScanner8<Set<Element>, TypeElement> {
 129         // Insertion-order preserving set
 130         Set<Element> annotatedElements = new LinkedHashSet<>();
 131 
 132         AnnotationSetScanner(Set<Element> defaultSet) {
 133             super(defaultSet);
 134         }
 135 
 136         @Override
 137         public Set<Element> visitType(TypeElement e, TypeElement p) {
 138             // Type parameters are not considered to be enclosed by a type
 139             scan(e.getTypeParameters(), p);
 140             return super.visitType(e, p);
 141         }
 142 
 143         @Override
 144         public Set<Element> visitExecutable(ExecutableElement e, TypeElement p) {
 145             // Type parameters are not considered to be enclosed by an executable
 146             scan(e.getTypeParameters(), p);
 147             return super.visitExecutable(e, p);
 148         }
 149 
 150         @Override
 151         public Set<Element> scan(Element e, TypeElement p) {
 152             java.util.List<? extends AnnotationMirror> annotationMirrors =
 153                 processingEnv.getElementUtils().getAllAnnotationMirrors(e);
 154             for (AnnotationMirror annotationMirror : annotationMirrors) {
 155                 if (p.equals(annotationMirror.getAnnotationType().asElement()))
 156                     annotatedElements.add(e);
 157             }
 158             e.accept(this, p);
 159             return annotatedElements;
 160         }
 161     }
 162 
 163     /**
 164      * {@inheritdoc}
 165      */
 166     public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
 167         if (!a.isAnnotation())
 168             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
 169         String name = a.getCanonicalName();
 170         if (name == null)
 171             return Collections.emptySet();
 172         else {
 173             TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
 174             if (annotationType == null)
 175                 return Collections.emptySet();
 176             else
 177                 return getElementsAnnotatedWith(annotationType);
 178         }
 179     }
 180 }