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

Thu, 24 Jul 2008 19:06:57 +0100

author
mcimadamore
date
Thu, 24 Jul 2008 19:06:57 +0100
changeset 80
5c9cdeb740f2
parent 1
9a66ca7c79fa
child 104
5e89c4ca637c
permissions
-rw-r--r--

6717241: some diagnostic argument is prematurely converted into a String object
Summary: removed early toString() conversions applied to diagnostic arguments
Reviewed-by: jjg

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

mercurial