0N/A/*
814N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
553N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
553N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
553N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
553N/A * or visit www.oracle.com if you need additional information or have any
553N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.tools.javac.tree;
0N/A
0N/Aimport com.sun.source.tree.Tree;
0N/Aimport com.sun.tools.javac.comp.AttrContext;
0N/Aimport com.sun.tools.javac.comp.Env;
0N/Aimport java.util.Map;
0N/Aimport com.sun.tools.javac.util.*;
0N/Aimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
0N/Aimport com.sun.tools.javac.code.*;
0N/Aimport com.sun.tools.javac.tree.JCTree.*;
0N/A
0N/Aimport static com.sun.tools.javac.code.Flags.*;
0N/A
0N/A/** Utility class containing inspector methods for trees.
0N/A *
580N/A * <p><b>This is NOT part of any supported API.
580N/A * If you write code that depends on this, you do so at your own risk.
0N/A * This code and its internal interfaces are subject to change or
0N/A * deletion without notice.</b>
0N/A */
0N/Apublic class TreeInfo {
0N/A protected static final Context.Key<TreeInfo> treeInfoKey =
0N/A new Context.Key<TreeInfo>();
0N/A
0N/A public static TreeInfo instance(Context context) {
0N/A TreeInfo instance = context.get(treeInfoKey);
0N/A if (instance == null)
0N/A instance = new TreeInfo(context);
0N/A return instance;
0N/A }
0N/A
0N/A /** The names of all operators.
0N/A */
0N/A private Name[] opname = new Name[JCTree.MOD - JCTree.POS + 1];
0N/A
0N/A private TreeInfo(Context context) {
0N/A context.put(treeInfoKey, this);
0N/A
112N/A Names names = Names.instance(context);
0N/A opname[JCTree.POS - JCTree.POS] = names.fromString("+");
0N/A opname[JCTree.NEG - JCTree.POS] = names.hyphen;
0N/A opname[JCTree.NOT - JCTree.POS] = names.fromString("!");
0N/A opname[JCTree.COMPL - JCTree.POS] = names.fromString("~");
0N/A opname[JCTree.PREINC - JCTree.POS] = names.fromString("++");
0N/A opname[JCTree.PREDEC - JCTree.POS] = names.fromString("--");
0N/A opname[JCTree.POSTINC - JCTree.POS] = names.fromString("++");
0N/A opname[JCTree.POSTDEC - JCTree.POS] = names.fromString("--");
0N/A opname[JCTree.NULLCHK - JCTree.POS] = names.fromString("<*nullchk*>");
0N/A opname[JCTree.OR - JCTree.POS] = names.fromString("||");
0N/A opname[JCTree.AND - JCTree.POS] = names.fromString("&&");
0N/A opname[JCTree.EQ - JCTree.POS] = names.fromString("==");
0N/A opname[JCTree.NE - JCTree.POS] = names.fromString("!=");
0N/A opname[JCTree.LT - JCTree.POS] = names.fromString("<");
0N/A opname[JCTree.GT - JCTree.POS] = names.fromString(">");
0N/A opname[JCTree.LE - JCTree.POS] = names.fromString("<=");
0N/A opname[JCTree.GE - JCTree.POS] = names.fromString(">=");
0N/A opname[JCTree.BITOR - JCTree.POS] = names.fromString("|");
0N/A opname[JCTree.BITXOR - JCTree.POS] = names.fromString("^");
0N/A opname[JCTree.BITAND - JCTree.POS] = names.fromString("&");
0N/A opname[JCTree.SL - JCTree.POS] = names.fromString("<<");
0N/A opname[JCTree.SR - JCTree.POS] = names.fromString(">>");
0N/A opname[JCTree.USR - JCTree.POS] = names.fromString(">>>");
0N/A opname[JCTree.PLUS - JCTree.POS] = names.fromString("+");
0N/A opname[JCTree.MINUS - JCTree.POS] = names.hyphen;
0N/A opname[JCTree.MUL - JCTree.POS] = names.asterisk;
0N/A opname[JCTree.DIV - JCTree.POS] = names.slash;
0N/A opname[JCTree.MOD - JCTree.POS] = names.fromString("%");
0N/A }
0N/A
0N/A
0N/A /** Return name of operator with given tree tag.
0N/A */
0N/A public Name operatorName(int tag) {
0N/A return opname[tag - JCTree.POS];
0N/A }
0N/A
0N/A /** Is tree a constructor declaration?
0N/A */
0N/A public static boolean isConstructor(JCTree tree) {
0N/A if (tree.getTag() == JCTree.METHODDEF) {
0N/A Name name = ((JCMethodDecl) tree).name;
112N/A return name == name.table.names.init;
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /** Is there a constructor declaration in the given list of trees?
0N/A */
0N/A public static boolean hasConstructors(List<JCTree> trees) {
0N/A for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
0N/A if (isConstructor(l.head)) return true;
0N/A return false;
0N/A }
0N/A
549N/A public static boolean isMultiCatch(JCCatch catchClause) {
968N/A return catchClause.param.vartype.getTag() == JCTree.TYPEUNION;
549N/A }
549N/A
0N/A /** Is statement an initializer for a synthetic field?
0N/A */
0N/A public static boolean isSyntheticInit(JCTree stat) {
0N/A if (stat.getTag() == JCTree.EXEC) {
0N/A JCExpressionStatement exec = (JCExpressionStatement)stat;
0N/A if (exec.expr.getTag() == JCTree.ASSIGN) {
0N/A JCAssign assign = (JCAssign)exec.expr;
0N/A if (assign.lhs.getTag() == JCTree.SELECT) {
0N/A JCFieldAccess select = (JCFieldAccess)assign.lhs;
0N/A if (select.sym != null &&
0N/A (select.sym.flags() & SYNTHETIC) != 0) {
0N/A Name selected = name(select.selected);
112N/A if (selected != null && selected == selected.table.names._this)
0N/A return true;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /** If the expression is a method call, return the method name, null
0N/A * otherwise. */
0N/A public static Name calledMethodName(JCTree tree) {
0N/A if (tree.getTag() == JCTree.EXEC) {
0N/A JCExpressionStatement exec = (JCExpressionStatement)tree;
0N/A if (exec.expr.getTag() == JCTree.APPLY) {
0N/A Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
0N/A return mname;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /** Is this a call to this or super?
0N/A */
0N/A public static boolean isSelfCall(JCTree tree) {
0N/A Name name = calledMethodName(tree);
0N/A if (name != null) {
112N/A Names names = name.table.names;
0N/A return name==names._this || name==names._super;
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /** Is this a call to super?
0N/A */
0N/A public static boolean isSuperCall(JCTree tree) {
0N/A Name name = calledMethodName(tree);
0N/A if (name != null) {
112N/A Names names = name.table.names;
0N/A return name==names._super;
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /** Is this a constructor whose first (non-synthetic) statement is not
0N/A * of the form this(...)?
0N/A */
0N/A public static boolean isInitialConstructor(JCTree tree) {
0N/A JCMethodInvocation app = firstConstructorCall(tree);
0N/A if (app == null) return false;
0N/A Name meth = name(app.meth);
112N/A return meth == null || meth != meth.table.names._this;
0N/A }
0N/A
0N/A /** Return the first call in a constructor definition. */
0N/A public static JCMethodInvocation firstConstructorCall(JCTree tree) {
0N/A if (tree.getTag() != JCTree.METHODDEF) return null;
0N/A JCMethodDecl md = (JCMethodDecl) tree;
112N/A Names names = md.name.table.names;
0N/A if (md.name != names.init) return null;
0N/A if (md.body == null) return null;
0N/A List<JCStatement> stats = md.body.stats;
0N/A // Synthetic initializations can appear before the super call.
0N/A while (stats.nonEmpty() && isSyntheticInit(stats.head))
0N/A stats = stats.tail;
0N/A if (stats.isEmpty()) return null;
0N/A if (stats.head.getTag() != JCTree.EXEC) return null;
0N/A JCExpressionStatement exec = (JCExpressionStatement) stats.head;
0N/A if (exec.expr.getTag() != JCTree.APPLY) return null;
0N/A return (JCMethodInvocation)exec.expr;
0N/A }
0N/A
536N/A /** Return true if a tree represents a diamond new expr. */
536N/A public static boolean isDiamond(JCTree tree) {
536N/A switch(tree.getTag()) {
536N/A case JCTree.TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
536N/A case JCTree.NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
536N/A default: return false;
536N/A }
536N/A }
536N/A
1421N/A public static boolean isEnumInit(JCTree tree) {
1421N/A switch (tree.getTag()) {
1421N/A case JCTree.VARDEF:
1421N/A return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
1421N/A default:
1421N/A return false;
1421N/A }
1421N/A }
1421N/A
0N/A /** Return true if a tree represents the null literal. */
0N/A public static boolean isNull(JCTree tree) {
0N/A if (tree.getTag() != JCTree.LITERAL)
0N/A return false;
0N/A JCLiteral lit = (JCLiteral) tree;
0N/A return (lit.typetag == TypeTags.BOT);
0N/A }
0N/A
0N/A /** The position of the first statement in a block, or the position of
0N/A * the block itself if it is empty.
0N/A */
0N/A public static int firstStatPos(JCTree tree) {
0N/A if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).stats.nonEmpty())
0N/A return ((JCBlock) tree).stats.head.pos;
0N/A else
0N/A return tree.pos;
0N/A }
0N/A
0N/A /** The end position of given tree, if it is a block with
0N/A * defined endpos.
0N/A */
0N/A public static int endPos(JCTree tree) {
0N/A if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).endpos != Position.NOPOS)
0N/A return ((JCBlock) tree).endpos;
0N/A else if (tree.getTag() == JCTree.SYNCHRONIZED)
0N/A return endPos(((JCSynchronized) tree).body);
0N/A else if (tree.getTag() == JCTree.TRY) {
0N/A JCTry t = (JCTry) tree;
0N/A return endPos((t.finalizer != null)
0N/A ? t.finalizer
1258N/A : (t.catchers.isEmpty()? t.body : t.catchers.last().body));
0N/A } else
0N/A return tree.pos;
0N/A }
0N/A
0N/A
0N/A /** Get the start position for a tree node. The start position is
0N/A * defined to be the position of the first character of the first
0N/A * token of the node's source text.
0N/A * @param tree The tree node
0N/A */
0N/A public static int getStartPos(JCTree tree) {
0N/A if (tree == null)
0N/A return Position.NOPOS;
0N/A
0N/A switch(tree.getTag()) {
0N/A case(JCTree.APPLY):
0N/A return getStartPos(((JCMethodInvocation) tree).meth);
0N/A case(JCTree.ASSIGN):
0N/A return getStartPos(((JCAssign) tree).lhs);
0N/A case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
0N/A case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
0N/A case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
0N/A case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
0N/A return getStartPos(((JCAssignOp) tree).lhs);
0N/A case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
0N/A case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
0N/A case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
0N/A case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
0N/A case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
0N/A case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
0N/A case(JCTree.MOD):
0N/A return getStartPos(((JCBinary) tree).lhs);
0N/A case(JCTree.CLASSDEF): {
0N/A JCClassDecl node = (JCClassDecl)tree;
0N/A if (node.mods.pos != Position.NOPOS)
0N/A return node.mods.pos;
0N/A break;
0N/A }
0N/A case(JCTree.CONDEXPR):
0N/A return getStartPos(((JCConditional) tree).cond);
0N/A case(JCTree.EXEC):
0N/A return getStartPos(((JCExpressionStatement) tree).expr);
0N/A case(JCTree.INDEXED):
0N/A return getStartPos(((JCArrayAccess) tree).indexed);
0N/A case(JCTree.METHODDEF): {
0N/A JCMethodDecl node = (JCMethodDecl)tree;
0N/A if (node.mods.pos != Position.NOPOS)
0N/A return node.mods.pos;
0N/A if (node.typarams.nonEmpty()) // List.nil() used for no typarams
0N/A return getStartPos(node.typarams.head);
0N/A return node.restype == null ? node.pos : getStartPos(node.restype);
0N/A }
0N/A case(JCTree.SELECT):
0N/A return getStartPos(((JCFieldAccess) tree).selected);
0N/A case(JCTree.TYPEAPPLY):
0N/A return getStartPos(((JCTypeApply) tree).clazz);
0N/A case(JCTree.TYPEARRAY):
0N/A return getStartPos(((JCArrayTypeTree) tree).elemtype);
0N/A case(JCTree.TYPETEST):
0N/A return getStartPos(((JCInstanceOf) tree).expr);
0N/A case(JCTree.POSTINC):
0N/A case(JCTree.POSTDEC):
0N/A return getStartPos(((JCUnary) tree).arg);
481N/A case(JCTree.NEWCLASS): {
481N/A JCNewClass node = (JCNewClass)tree;
481N/A if (node.encl != null)
481N/A return getStartPos(node.encl);
481N/A break;
481N/A }
0N/A case(JCTree.VARDEF): {
0N/A JCVariableDecl node = (JCVariableDecl)tree;
0N/A if (node.mods.pos != Position.NOPOS) {
0N/A return node.mods.pos;
0N/A } else {
0N/A return getStartPos(node.vartype);
0N/A }
0N/A }
0N/A case(JCTree.ERRONEOUS): {
0N/A JCErroneous node = (JCErroneous)tree;
0N/A if (node.errs != null && node.errs.nonEmpty())
0N/A return getStartPos(node.errs.head);
0N/A }
0N/A }
0N/A return tree.pos;
0N/A }
0N/A
0N/A /** The end position of given tree, given a table of end positions generated by the parser
0N/A */
0N/A public static int getEndPos(JCTree tree, Map<JCTree, Integer> endPositions) {
0N/A if (tree == null)
0N/A return Position.NOPOS;
0N/A
0N/A if (endPositions == null) {
0N/A // fall back on limited info in the tree
0N/A return endPos(tree);
0N/A }
0N/A
0N/A Integer mapPos = endPositions.get(tree);
0N/A if (mapPos != null)
0N/A return mapPos;
0N/A
0N/A switch(tree.getTag()) {
0N/A case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
0N/A case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
0N/A case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
0N/A case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
0N/A return getEndPos(((JCAssignOp) tree).rhs, endPositions);
0N/A case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
0N/A case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
0N/A case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
0N/A case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
0N/A case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
0N/A case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
0N/A case(JCTree.MOD):
0N/A return getEndPos(((JCBinary) tree).rhs, endPositions);
0N/A case(JCTree.CASE):
0N/A return getEndPos(((JCCase) tree).stats.last(), endPositions);
0N/A case(JCTree.CATCH):
0N/A return getEndPos(((JCCatch) tree).body, endPositions);
0N/A case(JCTree.CONDEXPR):
0N/A return getEndPos(((JCConditional) tree).falsepart, endPositions);
0N/A case(JCTree.FORLOOP):
0N/A return getEndPos(((JCForLoop) tree).body, endPositions);
0N/A case(JCTree.FOREACHLOOP):
0N/A return getEndPos(((JCEnhancedForLoop) tree).body, endPositions);
0N/A case(JCTree.IF): {
0N/A JCIf node = (JCIf)tree;
0N/A if (node.elsepart == null) {
0N/A return getEndPos(node.thenpart, endPositions);
0N/A } else {
0N/A return getEndPos(node.elsepart, endPositions);
0N/A }
0N/A }
0N/A case(JCTree.LABELLED):
0N/A return getEndPos(((JCLabeledStatement) tree).body, endPositions);
0N/A case(JCTree.MODIFIERS):
0N/A return getEndPos(((JCModifiers) tree).annotations.last(), endPositions);
0N/A case(JCTree.SYNCHRONIZED):
0N/A return getEndPos(((JCSynchronized) tree).body, endPositions);
0N/A case(JCTree.TOPLEVEL):
0N/A return getEndPos(((JCCompilationUnit) tree).defs.last(), endPositions);
0N/A case(JCTree.TRY): {
0N/A JCTry node = (JCTry)tree;
0N/A if (node.finalizer != null) {
0N/A return getEndPos(node.finalizer, endPositions);
0N/A } else if (!node.catchers.isEmpty()) {
0N/A return getEndPos(node.catchers.last(), endPositions);
0N/A } else {
0N/A return getEndPos(node.body, endPositions);
0N/A }
0N/A }
0N/A case(JCTree.WILDCARD):
0N/A return getEndPos(((JCWildcard) tree).inner, endPositions);
0N/A case(JCTree.TYPECAST):
0N/A return getEndPos(((JCTypeCast) tree).expr, endPositions);
0N/A case(JCTree.TYPETEST):
0N/A return getEndPos(((JCInstanceOf) tree).clazz, endPositions);
0N/A case(JCTree.POS):
0N/A case(JCTree.NEG):
0N/A case(JCTree.NOT):
0N/A case(JCTree.COMPL):
0N/A case(JCTree.PREINC):
0N/A case(JCTree.PREDEC):
0N/A return getEndPos(((JCUnary) tree).arg, endPositions);
0N/A case(JCTree.WHILELOOP):
0N/A return getEndPos(((JCWhileLoop) tree).body, endPositions);
0N/A case(JCTree.ERRONEOUS): {
0N/A JCErroneous node = (JCErroneous)tree;
0N/A if (node.errs != null && node.errs.nonEmpty())
0N/A return getEndPos(node.errs.last(), endPositions);
0N/A }
0N/A }
0N/A return Position.NOPOS;
0N/A }
0N/A
0N/A
0N/A /** A DiagnosticPosition with the preferred position set to the
0N/A * end position of given tree, if it is a block with
0N/A * defined endpos.
0N/A */
0N/A public static DiagnosticPosition diagEndPos(final JCTree tree) {
0N/A final int endPos = TreeInfo.endPos(tree);
0N/A return new DiagnosticPosition() {
0N/A public JCTree getTree() { return tree; }
0N/A public int getStartPosition() { return TreeInfo.getStartPos(tree); }
0N/A public int getPreferredPosition() { return endPos; }
0N/A public int getEndPosition(Map<JCTree, Integer> endPosTable) {
0N/A return TreeInfo.getEndPos(tree, endPosTable);
0N/A }
0N/A };
0N/A }
0N/A
0N/A /** The position of the finalizer of given try/synchronized statement.
0N/A */
0N/A public static int finalizerPos(JCTree tree) {
0N/A if (tree.getTag() == JCTree.TRY) {
0N/A JCTry t = (JCTry) tree;
815N/A Assert.checkNonNull(t.finalizer);
0N/A return firstStatPos(t.finalizer);
0N/A } else if (tree.getTag() == JCTree.SYNCHRONIZED) {
0N/A return endPos(((JCSynchronized) tree).body);
0N/A } else {
0N/A throw new AssertionError();
0N/A }
0N/A }
0N/A
0N/A /** Find the position for reporting an error about a symbol, where
0N/A * that symbol is defined somewhere in the given tree. */
0N/A public static int positionFor(final Symbol sym, final JCTree tree) {
0N/A JCTree decl = declarationFor(sym, tree);
0N/A return ((decl != null) ? decl : tree).pos;
0N/A }
0N/A
0N/A /** Find the position for reporting an error about a symbol, where
0N/A * that symbol is defined somewhere in the given tree. */
0N/A public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
0N/A JCTree decl = declarationFor(sym, tree);
0N/A return ((decl != null) ? decl : tree).pos();
0N/A }
0N/A
0N/A /** Find the declaration for a symbol, where
0N/A * that symbol is defined somewhere in the given tree. */
0N/A public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
0N/A class DeclScanner extends TreeScanner {
0N/A JCTree result = null;
0N/A public void scan(JCTree tree) {
0N/A if (tree!=null && result==null)
0N/A tree.accept(this);
0N/A }
0N/A public void visitTopLevel(JCCompilationUnit that) {
0N/A if (that.packge == sym) result = that;
0N/A else super.visitTopLevel(that);
0N/A }
0N/A public void visitClassDef(JCClassDecl that) {
0N/A if (that.sym == sym) result = that;
0N/A else super.visitClassDef(that);
0N/A }
0N/A public void visitMethodDef(JCMethodDecl that) {
0N/A if (that.sym == sym) result = that;
0N/A else super.visitMethodDef(that);
0N/A }
0N/A public void visitVarDef(JCVariableDecl that) {
0N/A if (that.sym == sym) result = that;
0N/A else super.visitVarDef(that);
0N/A }
667N/A public void visitTypeParameter(JCTypeParameter that) {
770N/A if (that.type != null && that.type.tsym == sym) result = that;
667N/A else super.visitTypeParameter(that);
667N/A }
0N/A }
0N/A DeclScanner s = new DeclScanner();
0N/A tree.accept(s);
0N/A return s.result;
0N/A }
0N/A
0N/A public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
0N/A return scopeFor(pathFor(node, unit));
0N/A }
0N/A
0N/A public static Env<AttrContext> scopeFor(List<JCTree> path) {
0N/A // TODO: not implemented yet
0N/A throw new UnsupportedOperationException("not implemented yet");
0N/A }
0N/A
0N/A public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
0N/A class Result extends Error {
0N/A static final long serialVersionUID = -5942088234594905625L;
0N/A List<JCTree> path;
0N/A Result(List<JCTree> path) {
0N/A this.path = path;
0N/A }
0N/A }
0N/A class PathFinder extends TreeScanner {
0N/A List<JCTree> path = List.nil();
0N/A public void scan(JCTree tree) {
0N/A if (tree != null) {
0N/A path = path.prepend(tree);
0N/A if (tree == node)
0N/A throw new Result(path);
0N/A super.scan(tree);
0N/A path = path.tail;
0N/A }
0N/A }
0N/A }
0N/A try {
0N/A new PathFinder().scan(unit);
0N/A } catch (Result result) {
0N/A return result.path;
0N/A }
0N/A return List.nil();
0N/A }
0N/A
0N/A /** Return the statement referenced by a label.
0N/A * If the label refers to a loop or switch, return that switch
0N/A * otherwise return the labelled statement itself
0N/A */
0N/A public static JCTree referencedStatement(JCLabeledStatement tree) {
0N/A JCTree t = tree;
0N/A do t = ((JCLabeledStatement) t).body;
0N/A while (t.getTag() == JCTree.LABELLED);
0N/A switch (t.getTag()) {
0N/A case JCTree.DOLOOP: case JCTree.WHILELOOP: case JCTree.FORLOOP: case JCTree.FOREACHLOOP: case JCTree.SWITCH:
0N/A return t;
0N/A default:
0N/A return tree;
0N/A }
0N/A }
0N/A
0N/A /** Skip parens and return the enclosed expression
0N/A */
0N/A public static JCExpression skipParens(JCExpression tree) {
0N/A while (tree.getTag() == JCTree.PARENS) {
0N/A tree = ((JCParens) tree).expr;
0N/A }
0N/A return tree;
0N/A }
0N/A
0N/A /** Skip parens and return the enclosed expression
0N/A */
0N/A public static JCTree skipParens(JCTree tree) {
0N/A if (tree.getTag() == JCTree.PARENS)
0N/A return skipParens((JCParens)tree);
0N/A else
0N/A return tree;
0N/A }
0N/A
0N/A /** Return the types of a list of trees.
0N/A */
0N/A public static List<Type> types(List<? extends JCTree> trees) {
0N/A ListBuffer<Type> ts = new ListBuffer<Type>();
0N/A for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
0N/A ts.append(l.head.type);
0N/A return ts.toList();
0N/A }
0N/A
0N/A /** If this tree is an identifier or a field or a parameterized type,
0N/A * return its name, otherwise return null.
0N/A */
0N/A public static Name name(JCTree tree) {
0N/A switch (tree.getTag()) {
0N/A case JCTree.IDENT:
0N/A return ((JCIdent) tree).name;
0N/A case JCTree.SELECT:
0N/A return ((JCFieldAccess) tree).name;
0N/A case JCTree.TYPEAPPLY:
0N/A return name(((JCTypeApply) tree).clazz);
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /** If this tree is a qualified identifier, its return fully qualified name,
0N/A * otherwise return null.
0N/A */
0N/A public static Name fullName(JCTree tree) {
0N/A tree = skipParens(tree);
0N/A switch (tree.getTag()) {
0N/A case JCTree.IDENT:
0N/A return ((JCIdent) tree).name;
0N/A case JCTree.SELECT:
0N/A Name sname = fullName(((JCFieldAccess) tree).selected);
0N/A return sname == null ? null : sname.append('.', name(tree));
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A public static Symbol symbolFor(JCTree node) {
0N/A node = skipParens(node);
0N/A switch (node.getTag()) {
0N/A case JCTree.CLASSDEF:
0N/A return ((JCClassDecl) node).sym;
0N/A case JCTree.METHODDEF:
0N/A return ((JCMethodDecl) node).sym;
0N/A case JCTree.VARDEF:
0N/A return ((JCVariableDecl) node).sym;
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
671N/A public static boolean isDeclaration(JCTree node) {
671N/A node = skipParens(node);
671N/A switch (node.getTag()) {
671N/A case JCTree.CLASSDEF:
671N/A case JCTree.METHODDEF:
671N/A case JCTree.VARDEF:
671N/A return true;
671N/A default:
671N/A return false;
671N/A }
671N/A }
671N/A
0N/A /** If this tree is an identifier or a field, return its symbol,
0N/A * otherwise return null.
0N/A */
0N/A public static Symbol symbol(JCTree tree) {
0N/A tree = skipParens(tree);
0N/A switch (tree.getTag()) {
0N/A case JCTree.IDENT:
0N/A return ((JCIdent) tree).sym;
0N/A case JCTree.SELECT:
0N/A return ((JCFieldAccess) tree).sym;
0N/A case JCTree.TYPEAPPLY:
0N/A return symbol(((JCTypeApply) tree).clazz);
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /** Return true if this is a nonstatic selection. */
0N/A public static boolean nonstaticSelect(JCTree tree) {
0N/A tree = skipParens(tree);
0N/A if (tree.getTag() != JCTree.SELECT) return false;
0N/A JCFieldAccess s = (JCFieldAccess) tree;
0N/A Symbol e = symbol(s.selected);
0N/A return e == null || (e.kind != Kinds.PCK && e.kind != Kinds.TYP);
0N/A }
0N/A
0N/A /** If this tree is an identifier or a field, set its symbol, otherwise skip.
0N/A */
0N/A public static void setSymbol(JCTree tree, Symbol sym) {
0N/A tree = skipParens(tree);
0N/A switch (tree.getTag()) {
0N/A case JCTree.IDENT:
0N/A ((JCIdent) tree).sym = sym; break;
0N/A case JCTree.SELECT:
0N/A ((JCFieldAccess) tree).sym = sym; break;
0N/A default:
0N/A }
0N/A }
0N/A
0N/A /** If this tree is a declaration or a block, return its flags field,
0N/A * otherwise return 0.
0N/A */
0N/A public static long flags(JCTree tree) {
0N/A switch (tree.getTag()) {
0N/A case JCTree.VARDEF:
0N/A return ((JCVariableDecl) tree).mods.flags;
0N/A case JCTree.METHODDEF:
0N/A return ((JCMethodDecl) tree).mods.flags;
0N/A case JCTree.CLASSDEF:
0N/A return ((JCClassDecl) tree).mods.flags;
0N/A case JCTree.BLOCK:
0N/A return ((JCBlock) tree).flags;
0N/A default:
0N/A return 0;
0N/A }
0N/A }
0N/A
0N/A /** Return first (smallest) flag in `flags':
0N/A * pre: flags != 0
0N/A */
0N/A public static long firstFlag(long flags) {
0N/A int flag = 1;
0N/A while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
0N/A flag = flag << 1;
0N/A return flag;
0N/A }
0N/A
0N/A /** Return flags as a string, separated by " ".
0N/A */
0N/A public static String flagNames(long flags) {
0N/A return Flags.toString(flags & StandardFlags).trim();
0N/A }
0N/A
0N/A /** Operator precedences values.
0N/A */
0N/A public static final int
0N/A notExpression = -1, // not an expression
0N/A noPrec = 0, // no enclosing expression
0N/A assignPrec = 1,
0N/A assignopPrec = 2,
0N/A condPrec = 3,
0N/A orPrec = 4,
0N/A andPrec = 5,
0N/A bitorPrec = 6,
0N/A bitxorPrec = 7,
0N/A bitandPrec = 8,
0N/A eqPrec = 9,
0N/A ordPrec = 10,
0N/A shiftPrec = 11,
0N/A addPrec = 12,
0N/A mulPrec = 13,
0N/A prefixPrec = 14,
0N/A postfixPrec = 15,
0N/A precCount = 16;
0N/A
0N/A
0N/A /** Map operators to their precedence levels.
0N/A */
0N/A public static int opPrec(int op) {
0N/A switch(op) {
0N/A case JCTree.POS:
0N/A case JCTree.NEG:
0N/A case JCTree.NOT:
0N/A case JCTree.COMPL:
0N/A case JCTree.PREINC:
0N/A case JCTree.PREDEC: return prefixPrec;
0N/A case JCTree.POSTINC:
0N/A case JCTree.POSTDEC:
0N/A case JCTree.NULLCHK: return postfixPrec;
0N/A case JCTree.ASSIGN: return assignPrec;
0N/A case JCTree.BITOR_ASG:
0N/A case JCTree.BITXOR_ASG:
0N/A case JCTree.BITAND_ASG:
0N/A case JCTree.SL_ASG:
0N/A case JCTree.SR_ASG:
0N/A case JCTree.USR_ASG:
0N/A case JCTree.PLUS_ASG:
0N/A case JCTree.MINUS_ASG:
0N/A case JCTree.MUL_ASG:
0N/A case JCTree.DIV_ASG:
0N/A case JCTree.MOD_ASG: return assignopPrec;
0N/A case JCTree.OR: return orPrec;
0N/A case JCTree.AND: return andPrec;
0N/A case JCTree.EQ:
0N/A case JCTree.NE: return eqPrec;
0N/A case JCTree.LT:
0N/A case JCTree.GT:
0N/A case JCTree.LE:
0N/A case JCTree.GE: return ordPrec;
0N/A case JCTree.BITOR: return bitorPrec;
0N/A case JCTree.BITXOR: return bitxorPrec;
0N/A case JCTree.BITAND: return bitandPrec;
0N/A case JCTree.SL:
0N/A case JCTree.SR:
0N/A case JCTree.USR: return shiftPrec;
0N/A case JCTree.PLUS:
0N/A case JCTree.MINUS: return addPrec;
0N/A case JCTree.MUL:
0N/A case JCTree.DIV:
0N/A case JCTree.MOD: return mulPrec;
0N/A case JCTree.TYPETEST: return ordPrec;
0N/A default: throw new AssertionError();
0N/A }
0N/A }
0N/A
0N/A static Tree.Kind tagToKind(int tag) {
0N/A switch (tag) {
0N/A // Postfix expressions
0N/A case JCTree.POSTINC: // _ ++
0N/A return Tree.Kind.POSTFIX_INCREMENT;
0N/A case JCTree.POSTDEC: // _ --
0N/A return Tree.Kind.POSTFIX_DECREMENT;
0N/A
0N/A // Unary operators
0N/A case JCTree.PREINC: // ++ _
0N/A return Tree.Kind.PREFIX_INCREMENT;
0N/A case JCTree.PREDEC: // -- _
0N/A return Tree.Kind.PREFIX_DECREMENT;
0N/A case JCTree.POS: // +
0N/A return Tree.Kind.UNARY_PLUS;
0N/A case JCTree.NEG: // -
0N/A return Tree.Kind.UNARY_MINUS;
0N/A case JCTree.COMPL: // ~
0N/A return Tree.Kind.BITWISE_COMPLEMENT;
0N/A case JCTree.NOT: // !
0N/A return Tree.Kind.LOGICAL_COMPLEMENT;
0N/A
0N/A // Binary operators
0N/A
0N/A // Multiplicative operators
0N/A case JCTree.MUL: // *
0N/A return Tree.Kind.MULTIPLY;
0N/A case JCTree.DIV: // /
0N/A return Tree.Kind.DIVIDE;
0N/A case JCTree.MOD: // %
0N/A return Tree.Kind.REMAINDER;
0N/A
0N/A // Additive operators
0N/A case JCTree.PLUS: // +
0N/A return Tree.Kind.PLUS;
0N/A case JCTree.MINUS: // -
0N/A return Tree.Kind.MINUS;
0N/A
0N/A // Shift operators
0N/A case JCTree.SL: // <<
0N/A return Tree.Kind.LEFT_SHIFT;
0N/A case JCTree.SR: // >>
0N/A return Tree.Kind.RIGHT_SHIFT;
0N/A case JCTree.USR: // >>>
0N/A return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
0N/A
0N/A // Relational operators
0N/A case JCTree.LT: // <
0N/A return Tree.Kind.LESS_THAN;
0N/A case JCTree.GT: // >
0N/A return Tree.Kind.GREATER_THAN;
0N/A case JCTree.LE: // <=
0N/A return Tree.Kind.LESS_THAN_EQUAL;
0N/A case JCTree.GE: // >=
0N/A return Tree.Kind.GREATER_THAN_EQUAL;
0N/A
0N/A // Equality operators
0N/A case JCTree.EQ: // ==
0N/A return Tree.Kind.EQUAL_TO;
0N/A case JCTree.NE: // !=
0N/A return Tree.Kind.NOT_EQUAL_TO;
0N/A
0N/A // Bitwise and logical operators
0N/A case JCTree.BITAND: // &
0N/A return Tree.Kind.AND;
0N/A case JCTree.BITXOR: // ^
0N/A return Tree.Kind.XOR;
0N/A case JCTree.BITOR: // |
0N/A return Tree.Kind.OR;
0N/A
0N/A // Conditional operators
0N/A case JCTree.AND: // &&
0N/A return Tree.Kind.CONDITIONAL_AND;
0N/A case JCTree.OR: // ||
0N/A return Tree.Kind.CONDITIONAL_OR;
0N/A
0N/A // Assignment operators
0N/A case JCTree.MUL_ASG: // *=
0N/A return Tree.Kind.MULTIPLY_ASSIGNMENT;
0N/A case JCTree.DIV_ASG: // /=
0N/A return Tree.Kind.DIVIDE_ASSIGNMENT;
0N/A case JCTree.MOD_ASG: // %=
0N/A return Tree.Kind.REMAINDER_ASSIGNMENT;
0N/A case JCTree.PLUS_ASG: // +=
0N/A return Tree.Kind.PLUS_ASSIGNMENT;
0N/A case JCTree.MINUS_ASG: // -=
0N/A return Tree.Kind.MINUS_ASSIGNMENT;
0N/A case JCTree.SL_ASG: // <<=
0N/A return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
0N/A case JCTree.SR_ASG: // >>=
0N/A return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
0N/A case JCTree.USR_ASG: // >>>=
0N/A return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
0N/A case JCTree.BITAND_ASG: // &=
0N/A return Tree.Kind.AND_ASSIGNMENT;
0N/A case JCTree.BITXOR_ASG: // ^=
0N/A return Tree.Kind.XOR_ASSIGNMENT;
0N/A case JCTree.BITOR_ASG: // |=
0N/A return Tree.Kind.OR_ASSIGNMENT;
0N/A
0N/A // Null check (implementation detail), for example, __.getClass()
0N/A case JCTree.NULLCHK:
0N/A return Tree.Kind.OTHER;
0N/A
0N/A default:
0N/A return null;
0N/A }
0N/A }
307N/A
307N/A /**
307N/A * Returns the underlying type of the tree if it is annotated type,
307N/A * or the tree itself otherwise
307N/A */
307N/A public static JCExpression typeIn(JCExpression tree) {
307N/A switch (tree.getTag()) {
307N/A case JCTree.IDENT: /* simple names */
307N/A case JCTree.TYPEIDENT: /* primitive name */
307N/A case JCTree.SELECT: /* qualified name */
307N/A case JCTree.TYPEARRAY: /* array types */
307N/A case JCTree.WILDCARD: /* wild cards */
307N/A case JCTree.TYPEPARAMETER: /* type parameters */
307N/A case JCTree.TYPEAPPLY: /* parameterized types */
307N/A return tree;
307N/A default:
307N/A throw new AssertionError("Unexpected type tree: " + tree);
307N/A }
307N/A }
469N/A
469N/A public static JCTree innermostType(JCTree type) {
469N/A switch (type.getTag()) {
469N/A case JCTree.TYPEARRAY:
469N/A return innermostType(((JCArrayTypeTree)type).elemtype);
469N/A case JCTree.WILDCARD:
469N/A return innermostType(((JCWildcard)type).inner);
469N/A default:
469N/A return type;
469N/A }
469N/A }
0N/A}