Home | History | Annotate | Download | only in el
      1 package annotations.el;
      2 
      3 /*>>>
      4 import org.checkerframework.checker.nullness.qual.*;
      5 */
      6 
      7 import java.util.ArrayList;
      8 import java.util.List;
      9 
     10 import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry;
     11 import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind;
     12 
     13 /**
     14  * A {@link TypeASTMapper} traverses a client-maintained abstract syntax
     15  * tree representing a type in parallel with an {@link ATypeElement} from
     16  * the annotation scene library, indicating corresponding pairs of AST nodes and
     17  * {@link AElement}s to the client so the client can process them in some
     18  * fashion.
     19  *
     20  * <p>
     21  * To use {@link TypeASTMapper}, write a subclass for your particular AST.
     22  * Implement {@link #getElementType}, {@link #numTypeArguments}, and
     23  * {@link #getTypeArgument} so that the mapper knows how to traverse your
     24  * AST; implement {@link #map} to perform whatever processing you desire on
     25  * each AST node and its corresponding {@link AElement}.  Then, pass the root
     26  * of your AST and the corresponding {@link ATypeElement} from your
     27  * annotation scene to {@link #traverse}.
     28  *
     29  * <p>
     30  * {@link TypeASTMapper} itself saves no state, but subclasses may save state
     31  * if they wish.
     32  *
     33  * {@link ATypeElement} objects that will be traversed
     34  * @param <N> common supertype of the AST nodes
     35  */
     36 public abstract class TypeASTMapper<N> {
     37     /**
     38      * Constructs a {@link TypeASTMapper}.  A {@link TypeASTMapper} stores no
     39      * state.
     40      */
     41     protected TypeASTMapper() {
     42     }
     43 
     44     private static ATypeElement getInnerType(ATypeElement te,
     45                                              List<TypePathEntry> ls) {
     46         if (ls.isEmpty()) {
     47             return te;
     48         } else {
     49             return te.innerTypes.vivify(new InnerTypeLocation(ls));
     50         }
     51     }
     52 
     53     /**
     54      * Traverses the type AST rooted at <code>tastRoot</code>, calling
     55      * {@link #map} with each AST node and the corresponding {@link AElement}
     56      * from <code>aslRoot</code>.
     57      *
     58      * If a node of the AST has no corresponding inner type in
     59      * <code>aslRoot</code>, an inner type {@link AElement} is vivified to hold
     60      * any annotations that {@link #map} might wish to store in it.  Thus,
     61      * a call to {@link #traverse} may write to <code>aslRoot</code> even if
     62      * {@link #map} does not write to its {@link AElement} argument.  You
     63      * may wish to {@linkplain AElement#prune prune} <code>aslRoot</code> after
     64      * traversal.
     65      */
     66     public void traverse(N tastRoot, ATypeElement aslRoot) {
     67         // Elements are added and removed from the end of this sole mutable
     68         // list during the traversal.
     69         List<TypePathEntry> ls = new ArrayList<TypePathEntry>();
     70         traverse1(tastRoot, aslRoot, ls);
     71     }
     72 
     73     // "Sane": top-level or type argument
     74     private void traverse1(N n, ATypeElement te, List<TypePathEntry> ls) {
     75         N elType = getElementType(n);
     76         if (elType == null) {
     77             // no array, so the prefix corresponds to the type right here
     78             // System.out.printf("non-array: map(%s, getInnerType(%s, %s)=%s)%n",
     79             //                   n, te, ls, getInnerType(te, ls));
     80             map(n, getInnerType(te, ls));
     81             int nta = numTypeArguments(n);
     82             for (int tai = 0; tai < nta; tai++) {
     83                 ls.add(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, tai));
     84                 traverse1(getTypeArgument(n, tai), te, ls);
     85                 ls.remove(ls.size() - 1);
     86             }
     87         } else {
     88             // System.out.printf("array top-level: map(%s, getInnerType(%s, %s)=%s)%n",
     89             //                   n, te, ls, getInnerType(te, ls));
     90             map(n, getInnerType(te, ls));
     91 
     92             // at least one array layer to confuse us
     93             int layers = 0;
     94             while ((elType = getElementType(n)) != null) {
     95                 ls.add(TypePathEntry.ARRAY);
     96                 // System.out.printf("layers=%d, map(%s, getInnerType(%s, %s)=%s)%n",
     97                 //                   layers, elType, te, ls, getInnerType(te, ls));
     98                 map(elType, getInnerType(te, ls));
     99                 n = elType;
    100                 layers++;
    101             }
    102             // // n is now the innermost element type
    103             // // map it to the prefix
    104             // map(n, getInnerType(te, ls));
    105 
    106             int nta = numTypeArguments(n);
    107             for (int tai = 0; tai < nta; tai++) {
    108                 ls.add(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, tai));
    109                 traverse1(getTypeArgument(n, tai), te, ls);
    110                 ls.remove(ls.size() - 1);
    111             }
    112 
    113             for (int i = 0; i < layers; i++) {
    114                 ls.remove(ls.size() - 1);
    115             }
    116         }
    117     }
    118 
    119     /**
    120      * If <code>n</code> represents an array type, {@link #getElementType}
    121      * returns the node for the element type of the array; otherwise it returns
    122      * <code>null</code>.
    123      */
    124     protected abstract N getElementType(N n);
    125 
    126     /**
    127      * If <code>n</code> represents a parameterized type,
    128      * {@link #numTypeArguments} returns the number of type arguments;
    129      * otherwise it returns 0.
    130      */
    131     protected abstract int numTypeArguments(N n);
    132 
    133     /**
    134      * Returns the node corresponding to the type argument of <code>n</code>
    135      * (which must be a parameterized type) at the given index.  The caller
    136      * must ensure that
    137      * <code>0 &lt;= index &lt; {@link #numTypeArguments}(n)</code>.
    138      */
    139     protected abstract  N getTypeArgument(N n, int index);
    140 
    141     /**
    142      * Signals to the client that <code>n</code> corresponds to <code>e</code>.
    143      * The client may, for example, set flags in <code>n</code> based on the
    144      * annotations in
    145      * <code>e.{@link AElement#tlAnnotationsHere tlAnnotationsHere}</code>.
    146      * The {@link TypeASTMapper} calls {@link #map} on <code>n</code> before it
    147      * calls {@link #map} on sub-nodes of <code>n</code> but not necessarily
    148      * before it explores the structure of <code>n</code>'s subtree.
    149      */
    150     protected abstract void map(N n, ATypeElement e);
    151 }
    152