src/share/classes/com/sun/source/util/AbstractTypeProcessor.java

Fri, 26 Jun 2009 19:12:41 -0700

author
jjg
date
Fri, 26 Jun 2009 19:12:41 -0700
changeset 309
664edca41e34
child 554
9d9f26857129
permissions
-rw-r--r--

6855544: add missing files
Reviewed-by: jjg, mcimadamore, darcy
Contributed-by: mernst@cs.washington.edu, mali@csail.mit.edu, mpapi@csail.mit.edu

jjg@309 1 /*
jjg@309 2 * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
jjg@309 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@309 4 *
jjg@309 5 * This code is free software; you can redistribute it and/or modify it
jjg@309 6 * under the terms of the GNU General Public License version 2 only, as
jjg@309 7 * published by the Free Software Foundation. Sun designates this
jjg@309 8 * particular file as subject to the "Classpath" exception as provided
jjg@309 9 * by Sun in the LICENSE file that accompanied this code.
jjg@309 10 *
jjg@309 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@309 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@309 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@309 14 * version 2 for more details (a copy is included in the LICENSE file that
jjg@309 15 * accompanied this code).
jjg@309 16 *
jjg@309 17 * You should have received a copy of the GNU General Public License version
jjg@309 18 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@309 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@309 20 *
jjg@309 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
jjg@309 22 * CA 95054 USA or visit www.sun.com if you need additional information or
jjg@309 23 * have any questions.
jjg@309 24 */
jjg@309 25
jjg@309 26 package com.sun.source.util;
jjg@309 27
jjg@309 28 import java.util.ArrayList;
jjg@309 29 import java.util.HashSet;
jjg@309 30 import java.util.List;
jjg@309 31 import java.util.Set;
jjg@309 32
jjg@309 33 import javax.annotation.processing.*;
jjg@309 34 import javax.lang.model.element.Name;
jjg@309 35 import javax.lang.model.element.TypeElement;
jjg@309 36 import javax.lang.model.util.ElementFilter;
jjg@309 37
jjg@309 38 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
jjg@309 39 import com.sun.tools.javac.util.Context;
jjg@309 40 import com.sun.tools.javac.util.Log;
jjg@309 41
jjg@309 42 import com.sun.source.tree.ClassTree;
jjg@309 43
jjg@309 44 /**
jjg@309 45 * This class is an abstract annotation processor designed to be a
jjg@309 46 * convenient superclass for concrete "type processors", processors that
jjg@309 47 * require the type information in the processed source.
jjg@309 48 *
jjg@309 49 * <p>Type processing occurs in one round after the tool (e.g. java compiler)
jjg@309 50 * analyzes the source (all sources taken as input to the tool and sources
jjg@309 51 * generated by other annotation processors).
jjg@309 52 *
jjg@309 53 * <p>The tool infrastructure will interact with classes extending this abstract
jjg@309 54 * class as follows:
jjg@309 55 *
jjg@309 56 * <ol>
jjg@309 57 * [1-3: Identical to {@link Processor} life cycle]
jjg@309 58 *
jjg@309 59 * <li>If an existing {@code Processor} object is not being used, to
jjg@309 60 * create an instance of a processor the tool calls the no-arg
jjg@309 61 * constructor of the processor class.
jjg@309 62 *
jjg@309 63 * <li>Next, the tool calls the {@link #init init} method with
jjg@309 64 * an appropriate {@code ProcessingEnvironment}.
jjg@309 65 *
jjg@309 66 * <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
jjg@309 67 * getSupportedAnnotationTypes}, {@link #getSupportedOptions
jjg@309 68 * getSupportedOptions}, and {@link #getSupportedSourceVersion
jjg@309 69 * getSupportedSourceVersion}. These methods are only called once per
jjg@309 70 * run, not on each round.
jjg@309 71 *
jjg@309 72 * [4-5Unique to {@code AbstractTypeProcessor} subclasses]
jjg@309 73 *
jjg@309 74 * <li>For each class containing a supported annotation, the tool calls
jjg@309 75 * {@link #typeProcess(TypeElement, TreePath) typeProcess} method on the
jjg@309 76 * {@code Processor}. The class is guaranteed to be type-checked Java code
jjg@309 77 * and all the tree type and symbol information is resolved.
jjg@309 78 *
jjg@309 79 * <li>Finally, the tools calls the
jjg@309 80 * {@link #typeProcessingOver() typeProcessingOver} method
jjg@309 81 * on the {@code Processor}.
jjg@309 82 *
jjg@309 83 * </ol>
jjg@309 84 *
jjg@309 85 * <p>The tool is permitted to ask type processors to process a class once
jjg@309 86 * it is analyzed before the rest of classes are analyzed. The tool is also
jjg@309 87 * permitted to stop type processing immediately if any errors are raised,
jjg@309 88 * without invoking {@code typeProcessingOver}
jjg@309 89 *
jjg@309 90 * <p>A subclass may override any of the methods in this class, as long as the
jjg@309 91 * general {@link javax.annotation.processing.Processor Processor}
jjg@309 92 * contract is obeyed, with one notable exception.
jjg@309 93 * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
jjg@309 94 * is called during the regular annotation phase before classes are analyzed.
jjg@309 95 *
jjg@309 96 * @author Mahmood Ali
jjg@309 97 * @since 1.7
jjg@309 98 */
jjg@309 99 public abstract class AbstractTypeProcessor extends AbstractProcessor {
jjg@309 100 private final Set<Name> elements = new HashSet<Name>();
jjg@309 101 private boolean hasInvokedTypeProcessingOver = false;
jjg@309 102 private JavacProcessingEnvironment env;
jjg@309 103 private final AttributionTaskListener listener = new AttributionTaskListener();
jjg@309 104
jjg@309 105 /**
jjg@309 106 * Constructor for subclasses to call.
jjg@309 107 */
jjg@309 108 protected AbstractTypeProcessor() { }
jjg@309 109
jjg@309 110 /**
jjg@309 111 * {@inheritDoc}
jjg@309 112 */
jjg@309 113 @Override
jjg@309 114 public void init(ProcessingEnvironment env) {
jjg@309 115 super.init(env);
jjg@309 116 this.env = (JavacProcessingEnvironment)env;
jjg@309 117 prepareContext(this.env.getContext());
jjg@309 118 }
jjg@309 119
jjg@309 120 /**
jjg@309 121 * The use of this method is obsolete in type processors. The method is
jjg@309 122 * called during regular annotation processing phase only.
jjg@309 123 */
jjg@309 124 @Override
jjg@309 125 public final boolean process(Set<? extends TypeElement> annotations,
jjg@309 126 RoundEnvironment roundEnv) {
jjg@309 127 for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) {
jjg@309 128 elements.add(elem.getQualifiedName());
jjg@309 129 }
jjg@309 130 return false;
jjg@309 131 }
jjg@309 132
jjg@309 133 /**
jjg@309 134 * Processes a fully analyzed class that contains a supported annotation
jjg@309 135 * (look {@link #getSupportedAnnotationTypes()}).
jjg@309 136 *
jjg@309 137 * <p>The passed class is always a valid type-checked Java code.
jjg@309 138 *
jjg@309 139 * @param element element of the analyzed class
jjg@309 140 * @param tree the tree path to the element, with the leaf being a
jjg@309 141 * {@link ClassTree}
jjg@309 142 */
jjg@309 143 public abstract void typeProcess(TypeElement element, TreePath tree);
jjg@309 144
jjg@309 145 /**
jjg@309 146 * A method to be called once all the classes are processed and no error
jjg@309 147 * is reported.
jjg@309 148 *
jjg@309 149 * <p>Subclasses may override this method to do any aggregate analysis
jjg@309 150 * (e.g. generate report, persistence) or resource deallocation.
jjg@309 151 *
jjg@309 152 * <p>If an error (a Java error or a processor error) is reported, this
jjg@309 153 * method is not guaranteed to be invoked.
jjg@309 154 */
jjg@309 155 public void typeProcessingOver() { }
jjg@309 156
jjg@309 157 /**
jjg@309 158 * adds a listener for attribution.
jjg@309 159 */
jjg@309 160 private void prepareContext(Context context) {
jjg@309 161 TaskListener otherListener = context.get(TaskListener.class);
jjg@309 162 if (otherListener == null) {
jjg@309 163 context.put(TaskListener.class, listener);
jjg@309 164 } else {
jjg@309 165 // handle cases of multiple listeners
jjg@309 166 context.put(TaskListener.class, (TaskListener)null);
jjg@309 167 TaskListeners listeners = new TaskListeners();
jjg@309 168 listeners.add(otherListener);
jjg@309 169 listeners.add(listener);
jjg@309 170 context.put(TaskListener.class, listeners);
jjg@309 171 }
jjg@309 172 }
jjg@309 173
jjg@309 174 /**
jjg@309 175 * A task listener that invokes the processor whenever a class is fully
jjg@309 176 * analyzed.
jjg@309 177 */
jjg@309 178 private final class AttributionTaskListener implements TaskListener {
jjg@309 179
jjg@309 180 @Override
jjg@309 181 public void finished(TaskEvent e) {
jjg@309 182 Log log = Log.instance(env.getContext());
jjg@309 183
jjg@309 184 if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
jjg@309 185 typeProcessingOver();
jjg@309 186 hasInvokedTypeProcessingOver = true;
jjg@309 187 }
jjg@309 188
jjg@309 189 if (e.getKind() != TaskEvent.Kind.ANALYZE)
jjg@309 190 return;
jjg@309 191
jjg@309 192 if (e.getTypeElement() == null)
jjg@309 193 throw new AssertionError("event task without a type element");
jjg@309 194 if (e.getCompilationUnit() == null)
jjg@309 195 throw new AssertionError("even task without compilation unit");
jjg@309 196
jjg@309 197 if (!elements.remove(e.getTypeElement().getQualifiedName()))
jjg@309 198 return;
jjg@309 199
jjg@309 200 if (log.nerrors != 0)
jjg@309 201 return;
jjg@309 202
jjg@309 203 TypeElement elem = e.getTypeElement();
jjg@309 204 TreePath p = Trees.instance(env).getPath(elem);
jjg@309 205
jjg@309 206 typeProcess(elem, p);
jjg@309 207
jjg@309 208 if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
jjg@309 209 typeProcessingOver();
jjg@309 210 hasInvokedTypeProcessingOver = true;
jjg@309 211 }
jjg@309 212 }
jjg@309 213
jjg@309 214 @Override
jjg@309 215 public void started(TaskEvent e) { }
jjg@309 216
jjg@309 217 }
jjg@309 218
jjg@309 219 /**
jjg@309 220 * A task listener multiplexer.
jjg@309 221 */
jjg@309 222 private static class TaskListeners implements TaskListener {
jjg@309 223 private final List<TaskListener> listeners = new ArrayList<TaskListener>();
jjg@309 224
jjg@309 225 public void add(TaskListener listener) {
jjg@309 226 listeners.add(listener);
jjg@309 227 }
jjg@309 228
jjg@309 229 public void remove(TaskListener listener) {
jjg@309 230 listeners.remove(listener);
jjg@309 231 }
jjg@309 232
jjg@309 233 @Override
jjg@309 234 public void finished(TaskEvent e) {
jjg@309 235 for (TaskListener listener : listeners)
jjg@309 236 listener.finished(e);
jjg@309 237 }
jjg@309 238
jjg@309 239 @Override
jjg@309 240 public void started(TaskEvent e) {
jjg@309 241 for (TaskListener listener : listeners)
jjg@309 242 listener.started(e);
jjg@309 243 }
jjg@309 244 }
jjg@309 245 }

mercurial