jjg@309: /* jjg@309: * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. jjg@309: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@309: * jjg@309: * This code is free software; you can redistribute it and/or modify it jjg@309: * under the terms of the GNU General Public License version 2 only, as jjg@309: * published by the Free Software Foundation. Sun designates this jjg@309: * particular file as subject to the "Classpath" exception as provided jjg@309: * by Sun in the LICENSE file that accompanied this code. jjg@309: * jjg@309: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@309: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@309: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@309: * version 2 for more details (a copy is included in the LICENSE file that jjg@309: * accompanied this code). jjg@309: * jjg@309: * You should have received a copy of the GNU General Public License version jjg@309: * 2 along with this work; if not, write to the Free Software Foundation, jjg@309: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@309: * jjg@309: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, jjg@309: * CA 95054 USA or visit www.sun.com if you need additional information or jjg@309: * have any questions. jjg@309: */ jjg@309: jjg@309: package com.sun.source.util; jjg@309: jjg@309: import java.util.ArrayList; jjg@309: import java.util.HashSet; jjg@309: import java.util.List; jjg@309: import java.util.Set; jjg@309: jjg@309: import javax.annotation.processing.*; jjg@309: import javax.lang.model.element.Name; jjg@309: import javax.lang.model.element.TypeElement; jjg@309: import javax.lang.model.util.ElementFilter; jjg@309: jjg@309: import com.sun.tools.javac.processing.JavacProcessingEnvironment; jjg@309: import com.sun.tools.javac.util.Context; jjg@309: import com.sun.tools.javac.util.Log; jjg@309: jjg@309: import com.sun.source.tree.ClassTree; jjg@309: jjg@309: /** jjg@309: * This class is an abstract annotation processor designed to be a jjg@309: * convenient superclass for concrete "type processors", processors that jjg@309: * require the type information in the processed source. jjg@309: * jjg@309: *
Type processing occurs in one round after the tool (e.g. java compiler) jjg@309: * analyzes the source (all sources taken as input to the tool and sources jjg@309: * generated by other annotation processors). jjg@309: * jjg@309: *
The tool infrastructure will interact with classes extending this abstract jjg@309: * class as follows: jjg@309: * jjg@309: *
The tool is permitted to ask type processors to process a class once jjg@309: * it is analyzed before the rest of classes are analyzed. The tool is also jjg@309: * permitted to stop type processing immediately if any errors are raised, jjg@309: * without invoking {@code typeProcessingOver} jjg@309: * jjg@309: *
A subclass may override any of the methods in this class, as long as the
jjg@309: * general {@link javax.annotation.processing.Processor Processor}
jjg@309: * contract is obeyed, with one notable exception.
jjg@309: * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
jjg@309: * is called during the regular annotation phase before classes are analyzed.
jjg@309: *
jjg@309: * @author Mahmood Ali
jjg@309: * @since 1.7
jjg@309: */
jjg@309: public abstract class AbstractTypeProcessor extends AbstractProcessor {
jjg@309: private final Set The passed class is always a valid type-checked Java code.
jjg@309: *
jjg@309: * @param element element of the analyzed class
jjg@309: * @param tree the tree path to the element, with the leaf being a
jjg@309: * {@link ClassTree}
jjg@309: */
jjg@309: public abstract void typeProcess(TypeElement element, TreePath tree);
jjg@309:
jjg@309: /**
jjg@309: * A method to be called once all the classes are processed and no error
jjg@309: * is reported.
jjg@309: *
jjg@309: * Subclasses may override this method to do any aggregate analysis
jjg@309: * (e.g. generate report, persistence) or resource deallocation.
jjg@309: *
jjg@309: * If an error (a Java error or a processor error) is reported, this
jjg@309: * method is not guaranteed to be invoked.
jjg@309: */
jjg@309: public void typeProcessingOver() { }
jjg@309:
jjg@309: /**
jjg@309: * adds a listener for attribution.
jjg@309: */
jjg@309: private void prepareContext(Context context) {
jjg@309: TaskListener otherListener = context.get(TaskListener.class);
jjg@309: if (otherListener == null) {
jjg@309: context.put(TaskListener.class, listener);
jjg@309: } else {
jjg@309: // handle cases of multiple listeners
jjg@309: context.put(TaskListener.class, (TaskListener)null);
jjg@309: TaskListeners listeners = new TaskListeners();
jjg@309: listeners.add(otherListener);
jjg@309: listeners.add(listener);
jjg@309: context.put(TaskListener.class, listeners);
jjg@309: }
jjg@309: }
jjg@309:
jjg@309: /**
jjg@309: * A task listener that invokes the processor whenever a class is fully
jjg@309: * analyzed.
jjg@309: */
jjg@309: private final class AttributionTaskListener implements TaskListener {
jjg@309:
jjg@309: @Override
jjg@309: public void finished(TaskEvent e) {
jjg@309: Log log = Log.instance(env.getContext());
jjg@309:
jjg@309: if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
jjg@309: typeProcessingOver();
jjg@309: hasInvokedTypeProcessingOver = true;
jjg@309: }
jjg@309:
jjg@309: if (e.getKind() != TaskEvent.Kind.ANALYZE)
jjg@309: return;
jjg@309:
jjg@309: if (e.getTypeElement() == null)
jjg@309: throw new AssertionError("event task without a type element");
jjg@309: if (e.getCompilationUnit() == null)
jjg@309: throw new AssertionError("even task without compilation unit");
jjg@309:
jjg@309: if (!elements.remove(e.getTypeElement().getQualifiedName()))
jjg@309: return;
jjg@309:
jjg@309: if (log.nerrors != 0)
jjg@309: return;
jjg@309:
jjg@309: TypeElement elem = e.getTypeElement();
jjg@309: TreePath p = Trees.instance(env).getPath(elem);
jjg@309:
jjg@309: typeProcess(elem, p);
jjg@309:
jjg@309: if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
jjg@309: typeProcessingOver();
jjg@309: hasInvokedTypeProcessingOver = true;
jjg@309: }
jjg@309: }
jjg@309:
jjg@309: @Override
jjg@309: public void started(TaskEvent e) { }
jjg@309:
jjg@309: }
jjg@309:
jjg@309: /**
jjg@309: * A task listener multiplexer.
jjg@309: */
jjg@309: private static class TaskListeners implements TaskListener {
jjg@309: private final List