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

     1 /*
     2  * Copyright 2009 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  */
    26 package com.sun.source.util;
    28 import java.util.ArrayList;
    29 import java.util.HashSet;
    30 import java.util.List;
    31 import java.util.Set;
    33 import javax.annotation.processing.*;
    34 import javax.lang.model.element.Name;
    35 import javax.lang.model.element.TypeElement;
    36 import javax.lang.model.util.ElementFilter;
    38 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
    39 import com.sun.tools.javac.util.Context;
    40 import com.sun.tools.javac.util.Log;
    42 import com.sun.source.tree.ClassTree;
    44 /**
    45  * This class is an abstract annotation processor designed to be a
    46  * convenient superclass for concrete "type processors", processors that
    47  * require the type information in the processed source.
    48  *
    49  * <p>Type processing occurs in one round after the tool (e.g. java compiler)
    50  * analyzes the source (all sources taken as input to the tool and sources
    51  * generated by other annotation processors).
    52  *
    53  * <p>The tool infrastructure will interact with classes extending this abstract
    54  * class as follows:
    55  *
    56  * <ol>
    57  * [1-3: Identical to {@link Processor} life cycle]
    58  *
    59  * <li>If an existing {@code Processor} object is not being used, to
    60  * create an instance of a processor the tool calls the no-arg
    61  * constructor of the processor class.
    62  *
    63  * <li>Next, the tool calls the {@link #init init} method with
    64  * an appropriate {@code ProcessingEnvironment}.
    65  *
    66  * <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
    67  * getSupportedAnnotationTypes}, {@link #getSupportedOptions
    68  * getSupportedOptions}, and {@link #getSupportedSourceVersion
    69  * getSupportedSourceVersion}.  These methods are only called once per
    70  * run, not on each round.
    71  *
    72  * [4-5Unique to {@code AbstractTypeProcessor} subclasses]
    73  *
    74  * <li>For each class containing a supported annotation, the tool calls
    75  * {@link #typeProcess(TypeElement, TreePath) typeProcess} method on the
    76  * {@code Processor}.  The class is guaranteed to be type-checked Java code
    77  * and all the tree type and symbol information is resolved.
    78  *
    79  * <li>Finally, the tools calls the
    80  * {@link #typeProcessingOver() typeProcessingOver} method
    81  * on the {@code Processor}.
    82  *
    83  * </ol>
    84  *
    85  * <p>The tool is permitted to ask type processors to process a class once
    86  * it is analyzed before the rest of classes are analyzed.  The tool is also
    87  * permitted to stop type processing immediately if any errors are raised,
    88  * without invoking {@code typeProcessingOver}
    89  *
    90  * <p>A subclass may override any of the methods in this class, as long as the
    91  * general {@link javax.annotation.processing.Processor Processor}
    92  * contract is obeyed, with one notable exception.
    93  * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
    94  * is called during the regular annotation phase before classes are analyzed.
    95  *
    96  * @author Mahmood Ali
    97  * @since 1.7
    98  */
    99 public abstract class AbstractTypeProcessor extends AbstractProcessor {
   100     private final Set<Name> elements = new HashSet<Name>();
   101     private boolean hasInvokedTypeProcessingOver = false;
   102     private JavacProcessingEnvironment env;
   103     private final AttributionTaskListener listener = new AttributionTaskListener();
   105     /**
   106      * Constructor for subclasses to call.
   107      */
   108     protected AbstractTypeProcessor() { }
   110     /**
   111      * {@inheritDoc}
   112      */
   113     @Override
   114     public void init(ProcessingEnvironment env) {
   115         super.init(env);
   116         this.env = (JavacProcessingEnvironment)env;
   117         prepareContext(this.env.getContext());
   118     }
   120     /**
   121      * The use of this method is obsolete in type processors.  The method is
   122      * called during regular annotation processing phase only.
   123      */
   124     @Override
   125     public final boolean process(Set<? extends TypeElement> annotations,
   126             RoundEnvironment roundEnv) {
   127         for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) {
   128             elements.add(elem.getQualifiedName());
   129         }
   130         return false;
   131     }
   133     /**
   134      * Processes a fully analyzed class that contains a supported annotation
   135      * (look {@link #getSupportedAnnotationTypes()}).
   136      *
   137      * <p>The passed class is always a valid type-checked Java code.
   138      *
   139      * @param element       element of the analyzed class
   140      * @param tree  the tree path to the element, with the leaf being a
   141      *              {@link ClassTree}
   142      */
   143     public abstract void typeProcess(TypeElement element, TreePath tree);
   145     /**
   146      * A method to be called once all the classes are processed and no error
   147      * is reported.
   148      *
   149      * <p>Subclasses may override this method to do any aggregate analysis
   150      * (e.g. generate report, persistence) or resource deallocation.
   151      *
   152      * <p>If an error (a Java error or a processor error) is reported, this
   153      * method is not guaranteed to be invoked.
   154      */
   155     public void typeProcessingOver() { }
   157     /**
   158      * adds a listener for attribution.
   159      */
   160     private void prepareContext(Context context) {
   161         TaskListener otherListener = context.get(TaskListener.class);
   162         if (otherListener == null) {
   163             context.put(TaskListener.class, listener);
   164         } else {
   165             // handle cases of multiple listeners
   166             context.put(TaskListener.class, (TaskListener)null);
   167             TaskListeners listeners = new TaskListeners();
   168             listeners.add(otherListener);
   169             listeners.add(listener);
   170             context.put(TaskListener.class, listeners);
   171         }
   172     }
   174     /**
   175      * A task listener that invokes the processor whenever a class is fully
   176      * analyzed.
   177      */
   178     private final class AttributionTaskListener implements TaskListener {
   180         @Override
   181         public void finished(TaskEvent e) {
   182             Log log = Log.instance(env.getContext());
   184             if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
   185                 typeProcessingOver();
   186                 hasInvokedTypeProcessingOver = true;
   187             }
   189             if (e.getKind() != TaskEvent.Kind.ANALYZE)
   190                 return;
   192             if (e.getTypeElement() == null)
   193                 throw new AssertionError("event task without a type element");
   194             if (e.getCompilationUnit() == null)
   195                 throw new AssertionError("even task without compilation unit");
   197             if (!elements.remove(e.getTypeElement().getQualifiedName()))
   198                 return;
   200             if (log.nerrors != 0)
   201                 return;
   203             TypeElement elem = e.getTypeElement();
   204             TreePath p = Trees.instance(env).getPath(elem);
   206             typeProcess(elem, p);
   208             if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
   209                 typeProcessingOver();
   210                 hasInvokedTypeProcessingOver = true;
   211             }
   212         }
   214         @Override
   215         public void started(TaskEvent e) { }
   217     }
   219     /**
   220      * A task listener multiplexer.
   221      */
   222     private static class TaskListeners implements TaskListener {
   223         private final List<TaskListener> listeners = new ArrayList<TaskListener>();
   225         public void add(TaskListener listener) {
   226             listeners.add(listener);
   227         }
   229         public void remove(TaskListener listener) {
   230             listeners.remove(listener);
   231         }
   233         @Override
   234         public void finished(TaskEvent e) {
   235             for (TaskListener listener : listeners)
   236                 listener.finished(e);
   237         }
   239         @Override
   240         public void started(TaskEvent e) {
   241             for (TaskListener listener : listeners)
   242                 listener.started(e);
   243         }
   244     }
   245 }

mercurial