src/share/classes/com/sun/tools/javac/tree/TreeInfo.java

Mon, 19 Oct 2009 13:38:09 -0700

author
jjg
date
Mon, 19 Oct 2009 13:38:09 -0700
changeset 428
2485f5641ed0
parent 383
8109aa93b212
child 470
b96ad32c004a
permissions
-rw-r--r--

6889255: javac MethodSymbol throws NPE if ClassReader does not read parameter names correctly
Reviewed-by: darcy

     1 /*
     2  * Copyright 1999-2008 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.tools.javac.tree;
    28 import com.sun.source.tree.Tree;
    29 import com.sun.tools.javac.comp.AttrContext;
    30 import com.sun.tools.javac.comp.Env;
    31 import java.util.Map;
    32 import com.sun.tools.javac.util.*;
    33 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    34 import com.sun.tools.javac.code.*;
    35 import com.sun.tools.javac.tree.JCTree.*;
    37 import static com.sun.tools.javac.code.Flags.*;
    39 /** Utility class containing inspector methods for trees.
    40  *
    41  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    42  *  you write code that depends on this, you do so at your own risk.
    43  *  This code and its internal interfaces are subject to change or
    44  *  deletion without notice.</b>
    45  */
    46 public class TreeInfo {
    47     protected static final Context.Key<TreeInfo> treeInfoKey =
    48         new Context.Key<TreeInfo>();
    50     public static TreeInfo instance(Context context) {
    51         TreeInfo instance = context.get(treeInfoKey);
    52         if (instance == null)
    53             instance = new TreeInfo(context);
    54         return instance;
    55     }
    57     /** The names of all operators.
    58      */
    59     private Name[] opname = new Name[JCTree.MOD - JCTree.POS + 1];
    61     private TreeInfo(Context context) {
    62         context.put(treeInfoKey, this);
    64         Names names = Names.instance(context);
    65         opname[JCTree.POS     - JCTree.POS] = names.fromString("+");
    66         opname[JCTree.NEG     - JCTree.POS] = names.hyphen;
    67         opname[JCTree.NOT     - JCTree.POS] = names.fromString("!");
    68         opname[JCTree.COMPL   - JCTree.POS] = names.fromString("~");
    69         opname[JCTree.PREINC  - JCTree.POS] = names.fromString("++");
    70         opname[JCTree.PREDEC  - JCTree.POS] = names.fromString("--");
    71         opname[JCTree.POSTINC - JCTree.POS] = names.fromString("++");
    72         opname[JCTree.POSTDEC - JCTree.POS] = names.fromString("--");
    73         opname[JCTree.NULLCHK - JCTree.POS] = names.fromString("<*nullchk*>");
    74         opname[JCTree.OR      - JCTree.POS] = names.fromString("||");
    75         opname[JCTree.AND     - JCTree.POS] = names.fromString("&&");
    76         opname[JCTree.EQ      - JCTree.POS] = names.fromString("==");
    77         opname[JCTree.NE      - JCTree.POS] = names.fromString("!=");
    78         opname[JCTree.LT      - JCTree.POS] = names.fromString("<");
    79         opname[JCTree.GT      - JCTree.POS] = names.fromString(">");
    80         opname[JCTree.LE      - JCTree.POS] = names.fromString("<=");
    81         opname[JCTree.GE      - JCTree.POS] = names.fromString(">=");
    82         opname[JCTree.BITOR   - JCTree.POS] = names.fromString("|");
    83         opname[JCTree.BITXOR  - JCTree.POS] = names.fromString("^");
    84         opname[JCTree.BITAND  - JCTree.POS] = names.fromString("&");
    85         opname[JCTree.SL      - JCTree.POS] = names.fromString("<<");
    86         opname[JCTree.SR      - JCTree.POS] = names.fromString(">>");
    87         opname[JCTree.USR     - JCTree.POS] = names.fromString(">>>");
    88         opname[JCTree.PLUS    - JCTree.POS] = names.fromString("+");
    89         opname[JCTree.MINUS   - JCTree.POS] = names.hyphen;
    90         opname[JCTree.MUL     - JCTree.POS] = names.asterisk;
    91         opname[JCTree.DIV     - JCTree.POS] = names.slash;
    92         opname[JCTree.MOD     - JCTree.POS] = names.fromString("%");
    93     }
    96     /** Return name of operator with given tree tag.
    97      */
    98     public Name operatorName(int tag) {
    99         return opname[tag - JCTree.POS];
   100     }
   102     /** Is tree a constructor declaration?
   103      */
   104     public static boolean isConstructor(JCTree tree) {
   105         if (tree.getTag() == JCTree.METHODDEF) {
   106             Name name = ((JCMethodDecl) tree).name;
   107             return name == name.table.names.init;
   108         } else {
   109             return false;
   110         }
   111     }
   113     /** Is there a constructor declaration in the given list of trees?
   114      */
   115     public static boolean hasConstructors(List<JCTree> trees) {
   116         for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
   117             if (isConstructor(l.head)) return true;
   118         return false;
   119     }
   121     /** Is statement an initializer for a synthetic field?
   122      */
   123     public static boolean isSyntheticInit(JCTree stat) {
   124         if (stat.getTag() == JCTree.EXEC) {
   125             JCExpressionStatement exec = (JCExpressionStatement)stat;
   126             if (exec.expr.getTag() == JCTree.ASSIGN) {
   127                 JCAssign assign = (JCAssign)exec.expr;
   128                 if (assign.lhs.getTag() == JCTree.SELECT) {
   129                     JCFieldAccess select = (JCFieldAccess)assign.lhs;
   130                     if (select.sym != null &&
   131                         (select.sym.flags() & SYNTHETIC) != 0) {
   132                         Name selected = name(select.selected);
   133                         if (selected != null && selected == selected.table.names._this)
   134                             return true;
   135                     }
   136                 }
   137             }
   138         }
   139         return false;
   140     }
   142     /** If the expression is a method call, return the method name, null
   143      *  otherwise. */
   144     public static Name calledMethodName(JCTree tree) {
   145         if (tree.getTag() == JCTree.EXEC) {
   146             JCExpressionStatement exec = (JCExpressionStatement)tree;
   147             if (exec.expr.getTag() == JCTree.APPLY) {
   148                 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
   149                 return mname;
   150             }
   151         }
   152         return null;
   153     }
   155     /** Is this a call to this or super?
   156      */
   157     public static boolean isSelfCall(JCTree tree) {
   158         Name name = calledMethodName(tree);
   159         if (name != null) {
   160             Names names = name.table.names;
   161             return name==names._this || name==names._super;
   162         } else {
   163             return false;
   164         }
   165     }
   167     /** Is this a call to super?
   168      */
   169     public static boolean isSuperCall(JCTree tree) {
   170         Name name = calledMethodName(tree);
   171         if (name != null) {
   172             Names names = name.table.names;
   173             return name==names._super;
   174         } else {
   175             return false;
   176         }
   177     }
   179     /** Is this a constructor whose first (non-synthetic) statement is not
   180      *  of the form this(...)?
   181      */
   182     public static boolean isInitialConstructor(JCTree tree) {
   183         JCMethodInvocation app = firstConstructorCall(tree);
   184         if (app == null) return false;
   185         Name meth = name(app.meth);
   186         return meth == null || meth != meth.table.names._this;
   187     }
   189     /** Return the first call in a constructor definition. */
   190     public static JCMethodInvocation firstConstructorCall(JCTree tree) {
   191         if (tree.getTag() != JCTree.METHODDEF) return null;
   192         JCMethodDecl md = (JCMethodDecl) tree;
   193         Names names = md.name.table.names;
   194         if (md.name != names.init) return null;
   195         if (md.body == null) return null;
   196         List<JCStatement> stats = md.body.stats;
   197         // Synthetic initializations can appear before the super call.
   198         while (stats.nonEmpty() && isSyntheticInit(stats.head))
   199             stats = stats.tail;
   200         if (stats.isEmpty()) return null;
   201         if (stats.head.getTag() != JCTree.EXEC) return null;
   202         JCExpressionStatement exec = (JCExpressionStatement) stats.head;
   203         if (exec.expr.getTag() != JCTree.APPLY) return null;
   204         return (JCMethodInvocation)exec.expr;
   205     }
   207     /** Return true if a tree represents a diamond new expr. */
   208     public static boolean isDiamond(JCTree tree) {
   209         switch(tree.getTag()) {
   210             case JCTree.TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
   211             case JCTree.NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
   212             default: return false;
   213         }
   214     }
   216     /** Return true if a tree represents the null literal. */
   217     public static boolean isNull(JCTree tree) {
   218         if (tree.getTag() != JCTree.LITERAL)
   219             return false;
   220         JCLiteral lit = (JCLiteral) tree;
   221         return (lit.typetag == TypeTags.BOT);
   222     }
   224     /** The position of the first statement in a block, or the position of
   225      *  the block itself if it is empty.
   226      */
   227     public static int firstStatPos(JCTree tree) {
   228         if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).stats.nonEmpty())
   229             return ((JCBlock) tree).stats.head.pos;
   230         else
   231             return tree.pos;
   232     }
   234     /** The end position of given tree, if it is a block with
   235      *  defined endpos.
   236      */
   237     public static int endPos(JCTree tree) {
   238         if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).endpos != Position.NOPOS)
   239             return ((JCBlock) tree).endpos;
   240         else if (tree.getTag() == JCTree.SYNCHRONIZED)
   241             return endPos(((JCSynchronized) tree).body);
   242         else if (tree.getTag() == JCTree.TRY) {
   243             JCTry t = (JCTry) tree;
   244             return endPos((t.finalizer != null)
   245                           ? t.finalizer
   246                           : t.catchers.last().body);
   247         } else
   248             return tree.pos;
   249     }
   252     /** Get the start position for a tree node.  The start position is
   253      * defined to be the position of the first character of the first
   254      * token of the node's source text.
   255      * @param tree  The tree node
   256      */
   257     public static int getStartPos(JCTree tree) {
   258         if (tree == null)
   259             return Position.NOPOS;
   261         switch(tree.getTag()) {
   262         case(JCTree.APPLY):
   263             return getStartPos(((JCMethodInvocation) tree).meth);
   264         case(JCTree.ASSIGN):
   265             return getStartPos(((JCAssign) tree).lhs);
   266         case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
   267         case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
   268         case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
   269         case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
   270             return getStartPos(((JCAssignOp) tree).lhs);
   271         case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
   272         case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
   273         case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
   274         case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
   275         case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
   276         case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
   277         case(JCTree.MOD):
   278             return getStartPos(((JCBinary) tree).lhs);
   279         case(JCTree.CLASSDEF): {
   280             JCClassDecl node = (JCClassDecl)tree;
   281             if (node.mods.pos != Position.NOPOS)
   282                 return node.mods.pos;
   283             break;
   284         }
   285         case(JCTree.CONDEXPR):
   286             return getStartPos(((JCConditional) tree).cond);
   287         case(JCTree.EXEC):
   288             return getStartPos(((JCExpressionStatement) tree).expr);
   289         case(JCTree.INDEXED):
   290             return getStartPos(((JCArrayAccess) tree).indexed);
   291         case(JCTree.METHODDEF): {
   292             JCMethodDecl node = (JCMethodDecl)tree;
   293             if (node.mods.pos != Position.NOPOS)
   294                 return node.mods.pos;
   295             if (node.typarams.nonEmpty()) // List.nil() used for no typarams
   296                 return getStartPos(node.typarams.head);
   297             return node.restype == null ? node.pos : getStartPos(node.restype);
   298         }
   299         case(JCTree.SELECT):
   300             return getStartPos(((JCFieldAccess) tree).selected);
   301         case(JCTree.TYPEAPPLY):
   302             return getStartPos(((JCTypeApply) tree).clazz);
   303         case(JCTree.TYPEARRAY):
   304             return getStartPos(((JCArrayTypeTree) tree).elemtype);
   305         case(JCTree.TYPETEST):
   306             return getStartPos(((JCInstanceOf) tree).expr);
   307         case(JCTree.POSTINC):
   308         case(JCTree.POSTDEC):
   309             return getStartPos(((JCUnary) tree).arg);
   310         case(JCTree.ANNOTATED_TYPE):
   311             return getStartPos(((JCAnnotatedType) tree).underlyingType);
   312         case(JCTree.VARDEF): {
   313             JCVariableDecl node = (JCVariableDecl)tree;
   314             if (node.mods.pos != Position.NOPOS) {
   315                 return node.mods.pos;
   316             } else {
   317                 return getStartPos(node.vartype);
   318             }
   319         }
   320         case(JCTree.ERRONEOUS): {
   321             JCErroneous node = (JCErroneous)tree;
   322             if (node.errs != null && node.errs.nonEmpty())
   323                 return getStartPos(node.errs.head);
   324         }
   325         }
   326         return tree.pos;
   327     }
   329     /** The end position of given tree, given  a table of end positions generated by the parser
   330      */
   331     public static int getEndPos(JCTree tree, Map<JCTree, Integer> endPositions) {
   332         if (tree == null)
   333             return Position.NOPOS;
   335         if (endPositions == null) {
   336             // fall back on limited info in the tree
   337             return endPos(tree);
   338         }
   340         Integer mapPos = endPositions.get(tree);
   341         if (mapPos != null)
   342             return mapPos;
   344         switch(tree.getTag()) {
   345         case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
   346         case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
   347         case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
   348         case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
   349             return getEndPos(((JCAssignOp) tree).rhs, endPositions);
   350         case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
   351         case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
   352         case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
   353         case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
   354         case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
   355         case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
   356         case(JCTree.MOD):
   357             return getEndPos(((JCBinary) tree).rhs, endPositions);
   358         case(JCTree.CASE):
   359             return getEndPos(((JCCase) tree).stats.last(), endPositions);
   360         case(JCTree.CATCH):
   361             return getEndPos(((JCCatch) tree).body, endPositions);
   362         case(JCTree.CONDEXPR):
   363             return getEndPos(((JCConditional) tree).falsepart, endPositions);
   364         case(JCTree.FORLOOP):
   365             return getEndPos(((JCForLoop) tree).body, endPositions);
   366         case(JCTree.FOREACHLOOP):
   367             return getEndPos(((JCEnhancedForLoop) tree).body, endPositions);
   368         case(JCTree.IF): {
   369             JCIf node = (JCIf)tree;
   370             if (node.elsepart == null) {
   371                 return getEndPos(node.thenpart, endPositions);
   372             } else {
   373                 return getEndPos(node.elsepart, endPositions);
   374             }
   375         }
   376         case(JCTree.LABELLED):
   377             return getEndPos(((JCLabeledStatement) tree).body, endPositions);
   378         case(JCTree.MODIFIERS):
   379             return getEndPos(((JCModifiers) tree).annotations.last(), endPositions);
   380         case(JCTree.SYNCHRONIZED):
   381             return getEndPos(((JCSynchronized) tree).body, endPositions);
   382         case(JCTree.TOPLEVEL):
   383             return getEndPos(((JCCompilationUnit) tree).defs.last(), endPositions);
   384         case(JCTree.TRY): {
   385             JCTry node = (JCTry)tree;
   386             if (node.finalizer != null) {
   387                 return getEndPos(node.finalizer, endPositions);
   388             } else if (!node.catchers.isEmpty()) {
   389                 return getEndPos(node.catchers.last(), endPositions);
   390             } else {
   391                 return getEndPos(node.body, endPositions);
   392             }
   393         }
   394         case(JCTree.WILDCARD):
   395             return getEndPos(((JCWildcard) tree).inner, endPositions);
   396         case(JCTree.TYPECAST):
   397             return getEndPos(((JCTypeCast) tree).expr, endPositions);
   398         case(JCTree.TYPETEST):
   399             return getEndPos(((JCInstanceOf) tree).clazz, endPositions);
   400         case(JCTree.POS):
   401         case(JCTree.NEG):
   402         case(JCTree.NOT):
   403         case(JCTree.COMPL):
   404         case(JCTree.PREINC):
   405         case(JCTree.PREDEC):
   406             return getEndPos(((JCUnary) tree).arg, endPositions);
   407         case(JCTree.WHILELOOP):
   408             return getEndPos(((JCWhileLoop) tree).body, endPositions);
   409         case(JCTree.ERRONEOUS): {
   410             JCErroneous node = (JCErroneous)tree;
   411             if (node.errs != null && node.errs.nonEmpty())
   412                 return getEndPos(node.errs.last(), endPositions);
   413         }
   414         }
   415         return Position.NOPOS;
   416     }
   419     /** A DiagnosticPosition with the preferred position set to the
   420      *  end position of given tree, if it is a block with
   421      *  defined endpos.
   422      */
   423     public static DiagnosticPosition diagEndPos(final JCTree tree) {
   424         final int endPos = TreeInfo.endPos(tree);
   425         return new DiagnosticPosition() {
   426             public JCTree getTree() { return tree; }
   427             public int getStartPosition() { return TreeInfo.getStartPos(tree); }
   428             public int getPreferredPosition() { return endPos; }
   429             public int getEndPosition(Map<JCTree, Integer> endPosTable) {
   430                 return TreeInfo.getEndPos(tree, endPosTable);
   431             }
   432         };
   433     }
   435     /** The position of the finalizer of given try/synchronized statement.
   436      */
   437     public static int finalizerPos(JCTree tree) {
   438         if (tree.getTag() == JCTree.TRY) {
   439             JCTry t = (JCTry) tree;
   440             assert t.finalizer != null;
   441             return firstStatPos(t.finalizer);
   442         } else if (tree.getTag() == JCTree.SYNCHRONIZED) {
   443             return endPos(((JCSynchronized) tree).body);
   444         } else {
   445             throw new AssertionError();
   446         }
   447     }
   449     /** Find the position for reporting an error about a symbol, where
   450      *  that symbol is defined somewhere in the given tree. */
   451     public static int positionFor(final Symbol sym, final JCTree tree) {
   452         JCTree decl = declarationFor(sym, tree);
   453         return ((decl != null) ? decl : tree).pos;
   454     }
   456     /** Find the position for reporting an error about a symbol, where
   457      *  that symbol is defined somewhere in the given tree. */
   458     public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
   459         JCTree decl = declarationFor(sym, tree);
   460         return ((decl != null) ? decl : tree).pos();
   461     }
   463     /** Find the declaration for a symbol, where
   464      *  that symbol is defined somewhere in the given tree. */
   465     public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
   466         class DeclScanner extends TreeScanner {
   467             JCTree result = null;
   468             public void scan(JCTree tree) {
   469                 if (tree!=null && result==null)
   470                     tree.accept(this);
   471             }
   472             public void visitTopLevel(JCCompilationUnit that) {
   473                 if (that.packge == sym) result = that;
   474                 else super.visitTopLevel(that);
   475             }
   476             public void visitClassDef(JCClassDecl that) {
   477                 if (that.sym == sym) result = that;
   478                 else super.visitClassDef(that);
   479             }
   480             public void visitMethodDef(JCMethodDecl that) {
   481                 if (that.sym == sym) result = that;
   482                 else super.visitMethodDef(that);
   483             }
   484             public void visitVarDef(JCVariableDecl that) {
   485                 if (that.sym == sym) result = that;
   486                 else super.visitVarDef(that);
   487             }
   488         }
   489         DeclScanner s = new DeclScanner();
   490         tree.accept(s);
   491         return s.result;
   492     }
   494     public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
   495         return scopeFor(pathFor(node, unit));
   496     }
   498     public static Env<AttrContext> scopeFor(List<JCTree> path) {
   499         // TODO: not implemented yet
   500         throw new UnsupportedOperationException("not implemented yet");
   501     }
   503     public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
   504         class Result extends Error {
   505             static final long serialVersionUID = -5942088234594905625L;
   506             List<JCTree> path;
   507             Result(List<JCTree> path) {
   508                 this.path = path;
   509             }
   510         }
   511         class PathFinder extends TreeScanner {
   512             List<JCTree> path = List.nil();
   513             public void scan(JCTree tree) {
   514                 if (tree != null) {
   515                     path = path.prepend(tree);
   516                     if (tree == node)
   517                         throw new Result(path);
   518                     super.scan(tree);
   519                     path = path.tail;
   520                 }
   521             }
   522         }
   523         try {
   524             new PathFinder().scan(unit);
   525         } catch (Result result) {
   526             return result.path;
   527         }
   528         return List.nil();
   529     }
   531     /** Return the statement referenced by a label.
   532      *  If the label refers to a loop or switch, return that switch
   533      *  otherwise return the labelled statement itself
   534      */
   535     public static JCTree referencedStatement(JCLabeledStatement tree) {
   536         JCTree t = tree;
   537         do t = ((JCLabeledStatement) t).body;
   538         while (t.getTag() == JCTree.LABELLED);
   539         switch (t.getTag()) {
   540         case JCTree.DOLOOP: case JCTree.WHILELOOP: case JCTree.FORLOOP: case JCTree.FOREACHLOOP: case JCTree.SWITCH:
   541             return t;
   542         default:
   543             return tree;
   544         }
   545     }
   547     /** Skip parens and return the enclosed expression
   548      */
   549     public static JCExpression skipParens(JCExpression tree) {
   550         while (tree.getTag() == JCTree.PARENS) {
   551             tree = ((JCParens) tree).expr;
   552         }
   553         return tree;
   554     }
   556     /** Skip parens and return the enclosed expression
   557      */
   558     public static JCTree skipParens(JCTree tree) {
   559         if (tree.getTag() == JCTree.PARENS)
   560             return skipParens((JCParens)tree);
   561         else
   562             return tree;
   563     }
   565     /** Return the types of a list of trees.
   566      */
   567     public static List<Type> types(List<? extends JCTree> trees) {
   568         ListBuffer<Type> ts = new ListBuffer<Type>();
   569         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
   570             ts.append(l.head.type);
   571         return ts.toList();
   572     }
   574     /** If this tree is an identifier or a field or a parameterized type,
   575      *  return its name, otherwise return null.
   576      */
   577     public static Name name(JCTree tree) {
   578         switch (tree.getTag()) {
   579         case JCTree.IDENT:
   580             return ((JCIdent) tree).name;
   581         case JCTree.SELECT:
   582             return ((JCFieldAccess) tree).name;
   583         case JCTree.TYPEAPPLY:
   584             return name(((JCTypeApply) tree).clazz);
   585         default:
   586             return null;
   587         }
   588     }
   590     /** If this tree is a qualified identifier, its return fully qualified name,
   591      *  otherwise return null.
   592      */
   593     public static Name fullName(JCTree tree) {
   594         tree = skipParens(tree);
   595         switch (tree.getTag()) {
   596         case JCTree.IDENT:
   597             return ((JCIdent) tree).name;
   598         case JCTree.SELECT:
   599             Name sname = fullName(((JCFieldAccess) tree).selected);
   600             return sname == null ? null : sname.append('.', name(tree));
   601         default:
   602             return null;
   603         }
   604     }
   606     public static Symbol symbolFor(JCTree node) {
   607         node = skipParens(node);
   608         switch (node.getTag()) {
   609         case JCTree.CLASSDEF:
   610             return ((JCClassDecl) node).sym;
   611         case JCTree.METHODDEF:
   612             return ((JCMethodDecl) node).sym;
   613         case JCTree.VARDEF:
   614             return ((JCVariableDecl) node).sym;
   615         default:
   616             return null;
   617         }
   618     }
   620     /** If this tree is an identifier or a field, return its symbol,
   621      *  otherwise return null.
   622      */
   623     public static Symbol symbol(JCTree tree) {
   624         tree = skipParens(tree);
   625         switch (tree.getTag()) {
   626         case JCTree.IDENT:
   627             return ((JCIdent) tree).sym;
   628         case JCTree.SELECT:
   629             return ((JCFieldAccess) tree).sym;
   630         case JCTree.TYPEAPPLY:
   631             return symbol(((JCTypeApply) tree).clazz);
   632         default:
   633             return null;
   634         }
   635     }
   637     /** Return true if this is a nonstatic selection. */
   638     public static boolean nonstaticSelect(JCTree tree) {
   639         tree = skipParens(tree);
   640         if (tree.getTag() != JCTree.SELECT) return false;
   641         JCFieldAccess s = (JCFieldAccess) tree;
   642         Symbol e = symbol(s.selected);
   643         return e == null || (e.kind != Kinds.PCK && e.kind != Kinds.TYP);
   644     }
   646     /** If this tree is an identifier or a field, set its symbol, otherwise skip.
   647      */
   648     public static void setSymbol(JCTree tree, Symbol sym) {
   649         tree = skipParens(tree);
   650         switch (tree.getTag()) {
   651         case JCTree.IDENT:
   652             ((JCIdent) tree).sym = sym; break;
   653         case JCTree.SELECT:
   654             ((JCFieldAccess) tree).sym = sym; break;
   655         default:
   656         }
   657     }
   659     /** If this tree is a declaration or a block, return its flags field,
   660      *  otherwise return 0.
   661      */
   662     public static long flags(JCTree tree) {
   663         switch (tree.getTag()) {
   664         case JCTree.VARDEF:
   665             return ((JCVariableDecl) tree).mods.flags;
   666         case JCTree.METHODDEF:
   667             return ((JCMethodDecl) tree).mods.flags;
   668         case JCTree.CLASSDEF:
   669             return ((JCClassDecl) tree).mods.flags;
   670         case JCTree.BLOCK:
   671             return ((JCBlock) tree).flags;
   672         default:
   673             return 0;
   674         }
   675     }
   677     /** Return first (smallest) flag in `flags':
   678      *  pre: flags != 0
   679      */
   680     public static long firstFlag(long flags) {
   681         int flag = 1;
   682         while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
   683             flag = flag << 1;
   684         return flag;
   685     }
   687     /** Return flags as a string, separated by " ".
   688      */
   689     public static String flagNames(long flags) {
   690         return Flags.toString(flags & StandardFlags).trim();
   691     }
   693     /** Operator precedences values.
   694      */
   695     public static final int
   696         notExpression = -1,   // not an expression
   697         noPrec = 0,           // no enclosing expression
   698         assignPrec = 1,
   699         assignopPrec = 2,
   700         condPrec = 3,
   701         orPrec = 4,
   702         andPrec = 5,
   703         bitorPrec = 6,
   704         bitxorPrec = 7,
   705         bitandPrec = 8,
   706         eqPrec = 9,
   707         ordPrec = 10,
   708         shiftPrec = 11,
   709         addPrec = 12,
   710         mulPrec = 13,
   711         prefixPrec = 14,
   712         postfixPrec = 15,
   713         precCount = 16;
   716     /** Map operators to their precedence levels.
   717      */
   718     public static int opPrec(int op) {
   719         switch(op) {
   720         case JCTree.POS:
   721         case JCTree.NEG:
   722         case JCTree.NOT:
   723         case JCTree.COMPL:
   724         case JCTree.PREINC:
   725         case JCTree.PREDEC: return prefixPrec;
   726         case JCTree.POSTINC:
   727         case JCTree.POSTDEC:
   728         case JCTree.NULLCHK: return postfixPrec;
   729         case JCTree.ASSIGN: return assignPrec;
   730         case JCTree.BITOR_ASG:
   731         case JCTree.BITXOR_ASG:
   732         case JCTree.BITAND_ASG:
   733         case JCTree.SL_ASG:
   734         case JCTree.SR_ASG:
   735         case JCTree.USR_ASG:
   736         case JCTree.PLUS_ASG:
   737         case JCTree.MINUS_ASG:
   738         case JCTree.MUL_ASG:
   739         case JCTree.DIV_ASG:
   740         case JCTree.MOD_ASG: return assignopPrec;
   741         case JCTree.OR: return orPrec;
   742         case JCTree.AND: return andPrec;
   743         case JCTree.EQ:
   744         case JCTree.NE: return eqPrec;
   745         case JCTree.LT:
   746         case JCTree.GT:
   747         case JCTree.LE:
   748         case JCTree.GE: return ordPrec;
   749         case JCTree.BITOR: return bitorPrec;
   750         case JCTree.BITXOR: return bitxorPrec;
   751         case JCTree.BITAND: return bitandPrec;
   752         case JCTree.SL:
   753         case JCTree.SR:
   754         case JCTree.USR: return shiftPrec;
   755         case JCTree.PLUS:
   756         case JCTree.MINUS: return addPrec;
   757         case JCTree.MUL:
   758         case JCTree.DIV:
   759         case JCTree.MOD: return mulPrec;
   760         case JCTree.TYPETEST: return ordPrec;
   761         default: throw new AssertionError();
   762         }
   763     }
   765     static Tree.Kind tagToKind(int tag) {
   766         switch (tag) {
   767         // Postfix expressions
   768         case JCTree.POSTINC:           // _ ++
   769             return Tree.Kind.POSTFIX_INCREMENT;
   770         case JCTree.POSTDEC:           // _ --
   771             return Tree.Kind.POSTFIX_DECREMENT;
   773         // Unary operators
   774         case JCTree.PREINC:            // ++ _
   775             return Tree.Kind.PREFIX_INCREMENT;
   776         case JCTree.PREDEC:            // -- _
   777             return Tree.Kind.PREFIX_DECREMENT;
   778         case JCTree.POS:               // +
   779             return Tree.Kind.UNARY_PLUS;
   780         case JCTree.NEG:               // -
   781             return Tree.Kind.UNARY_MINUS;
   782         case JCTree.COMPL:             // ~
   783             return Tree.Kind.BITWISE_COMPLEMENT;
   784         case JCTree.NOT:               // !
   785             return Tree.Kind.LOGICAL_COMPLEMENT;
   787         // Binary operators
   789         // Multiplicative operators
   790         case JCTree.MUL:               // *
   791             return Tree.Kind.MULTIPLY;
   792         case JCTree.DIV:               // /
   793             return Tree.Kind.DIVIDE;
   794         case JCTree.MOD:               // %
   795             return Tree.Kind.REMAINDER;
   797         // Additive operators
   798         case JCTree.PLUS:              // +
   799             return Tree.Kind.PLUS;
   800         case JCTree.MINUS:             // -
   801             return Tree.Kind.MINUS;
   803         // Shift operators
   804         case JCTree.SL:                // <<
   805             return Tree.Kind.LEFT_SHIFT;
   806         case JCTree.SR:                // >>
   807             return Tree.Kind.RIGHT_SHIFT;
   808         case JCTree.USR:               // >>>
   809             return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
   811         // Relational operators
   812         case JCTree.LT:                // <
   813             return Tree.Kind.LESS_THAN;
   814         case JCTree.GT:                // >
   815             return Tree.Kind.GREATER_THAN;
   816         case JCTree.LE:                // <=
   817             return Tree.Kind.LESS_THAN_EQUAL;
   818         case JCTree.GE:                // >=
   819             return Tree.Kind.GREATER_THAN_EQUAL;
   821         // Equality operators
   822         case JCTree.EQ:                // ==
   823             return Tree.Kind.EQUAL_TO;
   824         case JCTree.NE:                // !=
   825             return Tree.Kind.NOT_EQUAL_TO;
   827         // Bitwise and logical operators
   828         case JCTree.BITAND:            // &
   829             return Tree.Kind.AND;
   830         case JCTree.BITXOR:            // ^
   831             return Tree.Kind.XOR;
   832         case JCTree.BITOR:             // |
   833             return Tree.Kind.OR;
   835         // Conditional operators
   836         case JCTree.AND:               // &&
   837             return Tree.Kind.CONDITIONAL_AND;
   838         case JCTree.OR:                // ||
   839             return Tree.Kind.CONDITIONAL_OR;
   841         // Assignment operators
   842         case JCTree.MUL_ASG:           // *=
   843             return Tree.Kind.MULTIPLY_ASSIGNMENT;
   844         case JCTree.DIV_ASG:           // /=
   845             return Tree.Kind.DIVIDE_ASSIGNMENT;
   846         case JCTree.MOD_ASG:           // %=
   847             return Tree.Kind.REMAINDER_ASSIGNMENT;
   848         case JCTree.PLUS_ASG:          // +=
   849             return Tree.Kind.PLUS_ASSIGNMENT;
   850         case JCTree.MINUS_ASG:         // -=
   851             return Tree.Kind.MINUS_ASSIGNMENT;
   852         case JCTree.SL_ASG:            // <<=
   853             return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
   854         case JCTree.SR_ASG:            // >>=
   855             return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
   856         case JCTree.USR_ASG:           // >>>=
   857             return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
   858         case JCTree.BITAND_ASG:        // &=
   859             return Tree.Kind.AND_ASSIGNMENT;
   860         case JCTree.BITXOR_ASG:        // ^=
   861             return Tree.Kind.XOR_ASSIGNMENT;
   862         case JCTree.BITOR_ASG:         // |=
   863             return Tree.Kind.OR_ASSIGNMENT;
   865         // Null check (implementation detail), for example, __.getClass()
   866         case JCTree.NULLCHK:
   867             return Tree.Kind.OTHER;
   869         default:
   870             return null;
   871         }
   872     }
   874     /**
   875      * Returns the underlying type of the tree if it is annotated type,
   876      * or the tree itself otherwise
   877      */
   878     public static JCExpression typeIn(JCExpression tree) {
   879         switch (tree.getTag()) {
   880         case JCTree.ANNOTATED_TYPE:
   881             return ((JCAnnotatedType)tree).underlyingType;
   882         case JCTree.IDENT: /* simple names */
   883         case JCTree.TYPEIDENT: /* primitive name */
   884         case JCTree.SELECT: /* qualified name */
   885         case JCTree.TYPEARRAY: /* array types */
   886         case JCTree.WILDCARD: /* wild cards */
   887         case JCTree.TYPEPARAMETER: /* type parameters */
   888         case JCTree.TYPEAPPLY: /* parameterized types */
   889             return tree;
   890         default:
   891             throw new AssertionError("Unexpected type tree: " + tree);
   892         }
   893     }
   894 }

mercurial