JavacRoundEnvironment.java revision 2981:d1e5707cd4eb
1214946Sthompsa/*
2214946Sthompsa * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
3214946Sthompsa * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4214946Sthompsa *
5214946Sthompsa * This code is free software; you can redistribute it and/or modify it
6214946Sthompsa * under the terms of the GNU General Public License version 2 only, as
7214946Sthompsa * published by the Free Software Foundation.  Oracle designates this
8214946Sthompsa * particular file as subject to the "Classpath" exception as provided
9214946Sthompsa * by Oracle in the LICENSE file that accompanied this code.
10214946Sthompsa *
11214946Sthompsa * This code is distributed in the hope that it will be useful, but WITHOUT
12214946Sthompsa * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13214946Sthompsa * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14214946Sthompsa * version 2 for more details (a copy is included in the LICENSE file that
15214946Sthompsa * accompanied this code).
16214946Sthompsa *
17214946Sthompsa * You should have received a copy of the GNU General Public License version
18214946Sthompsa * 2 along with this work; if not, write to the Free Software Foundation,
19214946Sthompsa * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20214946Sthompsa *
21214946Sthompsa * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22214946Sthompsa * or visit www.oracle.com if you need additional information or have any
23214946Sthompsa * questions.
24214946Sthompsa */
25214946Sthompsa
26214946Sthompsapackage com.sun.tools.javac.processing;
27214946Sthompsa
28214946Sthompsaimport java.lang.annotation.Annotation;
29214946Sthompsaimport javax.annotation.processing.*;
30214946Sthompsaimport javax.lang.model.element.*;
31214946Sthompsaimport javax.lang.model.util.*;
32214946Sthompsaimport java.util.*;
33214946Sthompsa
34214946Sthompsaimport com.sun.tools.javac.util.DefinedBy;
35214946Sthompsaimport com.sun.tools.javac.util.DefinedBy.Api;
36214946Sthompsa
37214946Sthompsa/**
38214946Sthompsa * Object providing state about a prior round of annotation processing.
39214946Sthompsa *
40214946Sthompsa * <p>The methods in this class do not take type annotations into account,
41214946Sthompsa * as target types, not java elements.
42214946Sthompsa *
43214946Sthompsa * <p><b>This is NOT part of any supported API.
44214946Sthompsa * If you write code that depends on this, you do so at your own risk.
45214946Sthompsa * This code and its internal interfaces are subject to change or
46214946Sthompsa * deletion without notice.</b>
47214946Sthompsa */
48214946Sthompsapublic class JavacRoundEnvironment implements RoundEnvironment {
49214946Sthompsa    // Default equals and hashCode methods are okay.
50214946Sthompsa
51214946Sthompsa    private final boolean processingOver;
52214946Sthompsa    private final boolean errorRaised;
53214946Sthompsa    private final ProcessingEnvironment processingEnv;
54214946Sthompsa
55214946Sthompsa    // Caller must pass in an immutable set
56214946Sthompsa    private final Set<? extends Element> rootElements;
57214946Sthompsa
58214946Sthompsa    JavacRoundEnvironment(boolean processingOver,
59214946Sthompsa                          boolean errorRaised,
60214946Sthompsa                          Set<? extends Element> rootElements,
61214946Sthompsa                          ProcessingEnvironment processingEnv) {
62214946Sthompsa        this.processingOver = processingOver;
63214946Sthompsa        this.errorRaised = errorRaised;
64214946Sthompsa        this.rootElements = rootElements;
65214946Sthompsa        this.processingEnv = processingEnv;
66214946Sthompsa    }
67214946Sthompsa
68214946Sthompsa    public String toString() {
69214946Sthompsa        return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
70214946Sthompsa                             errorRaised,
71214946Sthompsa                             rootElements,
72214946Sthompsa                             processingOver);
73214946Sthompsa    }
74214946Sthompsa
75214946Sthompsa    @DefinedBy(Api.ANNOTATION_PROCESSING)
76214946Sthompsa    public boolean processingOver() {
77214946Sthompsa        return processingOver;
78214946Sthompsa    }
79214946Sthompsa
80214946Sthompsa    /**
81214946Sthompsa     * Returns {@code true} if an error was raised in the prior round
82214946Sthompsa     * of processing; returns {@code false} otherwise.
83214946Sthompsa     *
84214946Sthompsa     * @return {@code true} if an error was raised in the prior round
85214946Sthompsa     * of processing; returns {@code false} otherwise.
86214946Sthompsa     */
87214946Sthompsa    @DefinedBy(Api.ANNOTATION_PROCESSING)
88214946Sthompsa    public boolean errorRaised() {
89214946Sthompsa        return errorRaised;
90214946Sthompsa    }
91214946Sthompsa
92214946Sthompsa    /**
93214946Sthompsa     * Returns the type elements specified by the prior round.
94214946Sthompsa     *
95214946Sthompsa     * @return the types elements specified by the prior round, or an
96214946Sthompsa     * empty set if there were none
97214946Sthompsa     */
98214946Sthompsa    @DefinedBy(Api.ANNOTATION_PROCESSING)
99214946Sthompsa    public Set<? extends Element> getRootElements() {
100214946Sthompsa        return rootElements;
101214946Sthompsa    }
102214946Sthompsa
103214946Sthompsa    private static final String NOT_AN_ANNOTATION_TYPE =
104214946Sthompsa        "The argument does not represent an annotation type: ";
105214946Sthompsa
106214946Sthompsa    /**
107214946Sthompsa     * Returns the elements annotated with the given annotation type.
108214946Sthompsa     * Only type elements <i>included</i> in this round of annotation
109214946Sthompsa     * processing, or declarations of members, parameters, or type
110214946Sthompsa     * parameters declared within those, are returned.  Included type
111214946Sthompsa     * elements are {@linkplain #getRootElements specified
112214946Sthompsa     * types} and any types nested within them.
113214946Sthompsa     *
114214946Sthompsa     * @param a  annotation type being requested
115214946Sthompsa     * @return the elements annotated with the given annotation type,
116214946Sthompsa     * or an empty set if there are none
117214946Sthompsa     */
118214946Sthompsa    @DefinedBy(Api.ANNOTATION_PROCESSING)
119214946Sthompsa    public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
120214946Sthompsa        Set<Element> result = Collections.emptySet();
121214946Sthompsa        if (a.getKind() != ElementKind.ANNOTATION_TYPE)
122214946Sthompsa            throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
123214946Sthompsa
124214946Sthompsa        ElementScanner9<Set<Element>, TypeElement> scanner =
125214946Sthompsa            new AnnotationSetScanner(result);
126214946Sthompsa
127214946Sthompsa        for (Element element : rootElements)
128214946Sthompsa            result = scanner.scan(element, a);
129214946Sthompsa
130214946Sthompsa        return result;
131214946Sthompsa    }
132214946Sthompsa
133214946Sthompsa    // Could be written as a local class inside getElementsAnnotatedWith
134214946Sthompsa    private class AnnotationSetScanner extends
135214946Sthompsa        ElementScanner9<Set<Element>, TypeElement> {
136214946Sthompsa        // Insertion-order preserving set
137214946Sthompsa        Set<Element> annotatedElements = new LinkedHashSet<>();
138214946Sthompsa
139214946Sthompsa        AnnotationSetScanner(Set<Element> defaultSet) {
140214946Sthompsa            super(defaultSet);
141214946Sthompsa        }
142214946Sthompsa
143214946Sthompsa        @Override @DefinedBy(Api.LANGUAGE_MODEL)
144214946Sthompsa        public Set<Element> visitType(TypeElement e, TypeElement p) {
145214946Sthompsa            // Type parameters are not considered to be enclosed by a type
146214946Sthompsa            scan(e.getTypeParameters(), p);
147214946Sthompsa            return super.visitType(e, p);
148214946Sthompsa        }
149214946Sthompsa
150214946Sthompsa        @Override @DefinedBy(Api.LANGUAGE_MODEL)
151215319Sthompsa        public Set<Element> visitExecutable(ExecutableElement e, TypeElement p) {
152214946Sthompsa            // Type parameters are not considered to be enclosed by an executable
153214946Sthompsa            scan(e.getTypeParameters(), p);
154214946Sthompsa            return super.visitExecutable(e, p);
155214946Sthompsa        }
156214946Sthompsa
157214946Sthompsa        @Override @DefinedBy(Api.LANGUAGE_MODEL)
158214946Sthompsa        public Set<Element> scan(Element e, TypeElement p) {
159214946Sthompsa            java.util.List<? extends AnnotationMirror> annotationMirrors =
160214946Sthompsa                processingEnv.getElementUtils().getAllAnnotationMirrors(e);
161215319Sthompsa            for (AnnotationMirror annotationMirror : annotationMirrors) {
162214946Sthompsa                if (p.equals(annotationMirror.getAnnotationType().asElement()))
163214946Sthompsa                    annotatedElements.add(e);
164214946Sthompsa            }
165214946Sthompsa            e.accept(this, p);
166214946Sthompsa            return annotatedElements;
167214946Sthompsa        }
168214946Sthompsa    }
169214946Sthompsa
170214946Sthompsa    /**
171214946Sthompsa     * {@inheritDoc}
172214946Sthompsa     */
173214946Sthompsa    @DefinedBy(Api.ANNOTATION_PROCESSING)
174214946Sthompsa    public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
175214946Sthompsa        if (!a.isAnnotation())
176214946Sthompsa            throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
177214946Sthompsa        String name = a.getCanonicalName();
178214946Sthompsa        if (name == null)
179214946Sthompsa            return Collections.emptySet();
180214946Sthompsa        else {
181214946Sthompsa            TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
182214946Sthompsa            if (annotationType == null)
183214946Sthompsa                return Collections.emptySet();
184214946Sthompsa            else
185214946Sthompsa                return getElementsAnnotatedWith(annotationType);
186214946Sthompsa        }
187214946Sthompsa    }
188214946Sthompsa}
189214946Sthompsa