001: /*
002: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.tree;
027:
028: import com.sun.source.tree.Tree;
029: import com.sun.tools.javac.comp.AttrContext;
030: import com.sun.tools.javac.comp.Env;
031: import java.util.Map;
032: import com.sun.tools.javac.util.*;
033: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
034: import com.sun.tools.javac.code.*;
035: import com.sun.tools.javac.tree.JCTree.*;
036:
037: import static com.sun.tools.javac.code.Flags.*;
038: import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
039:
040: /** Utility class containing inspector methods for trees.
041: *
042: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
043: * you write code that depends on this, you do so at your own risk.
044: * This code and its internal interfaces are subject to change or
045: * deletion without notice.</b>
046: */
047: @Version("@(#)TreeInfo.java 1.57 07/06/14")
048: public class TreeInfo {
049: protected static final Context.Key<TreeInfo> treeInfoKey = new Context.Key<TreeInfo>();
050:
051: public static TreeInfo instance(Context context) {
052: TreeInfo instance = context.get(treeInfoKey);
053: if (instance == null)
054: instance = new TreeInfo(context);
055: return instance;
056: }
057:
058: /** The names of all operators.
059: */
060: private Name[] opname = new Name[JCTree.MOD - JCTree.POS + 1];
061:
062: private TreeInfo(Context context) {
063: context.put(treeInfoKey, this );
064:
065: Name.Table names = Name.Table.instance(context);
066: opname[JCTree.POS - JCTree.POS] = names.fromString("+");
067: opname[JCTree.NEG - JCTree.POS] = names.hyphen;
068: opname[JCTree.NOT - JCTree.POS] = names.fromString("!");
069: opname[JCTree.COMPL - JCTree.POS] = names.fromString("~");
070: opname[JCTree.PREINC - JCTree.POS] = names.fromString("++");
071: opname[JCTree.PREDEC - JCTree.POS] = names.fromString("--");
072: opname[JCTree.POSTINC - JCTree.POS] = names.fromString("++");
073: opname[JCTree.POSTDEC - JCTree.POS] = names.fromString("--");
074: opname[JCTree.NULLCHK - JCTree.POS] = names
075: .fromString("<*nullchk*>");
076: opname[JCTree.OR - JCTree.POS] = names.fromString("||");
077: opname[JCTree.AND - JCTree.POS] = names.fromString("&&");
078: opname[JCTree.EQ - JCTree.POS] = names.fromString("==");
079: opname[JCTree.NE - JCTree.POS] = names.fromString("!=");
080: opname[JCTree.LT - JCTree.POS] = names.fromString("<");
081: opname[JCTree.GT - JCTree.POS] = names.fromString(">");
082: opname[JCTree.LE - JCTree.POS] = names.fromString("<=");
083: opname[JCTree.GE - JCTree.POS] = names.fromString(">=");
084: opname[JCTree.BITOR - JCTree.POS] = names.fromString("|");
085: opname[JCTree.BITXOR - JCTree.POS] = names.fromString("^");
086: opname[JCTree.BITAND - JCTree.POS] = names.fromString("&");
087: opname[JCTree.SL - JCTree.POS] = names.fromString("<<");
088: opname[JCTree.SR - JCTree.POS] = names.fromString(">>");
089: opname[JCTree.USR - JCTree.POS] = names.fromString(">>>");
090: opname[JCTree.PLUS - JCTree.POS] = names.fromString("+");
091: opname[JCTree.MINUS - JCTree.POS] = names.hyphen;
092: opname[JCTree.MUL - JCTree.POS] = names.asterisk;
093: opname[JCTree.DIV - JCTree.POS] = names.slash;
094: opname[JCTree.MOD - JCTree.POS] = names.fromString("%");
095: }
096:
097: /** Return name of operator with given tree tag.
098: */
099: public Name operatorName(int tag) {
100: return opname[tag - JCTree.POS];
101: }
102:
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: }
113:
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))
119: return true;
120: return false;
121: }
122:
123: /** Is statement an initializer for a synthetic field?
124: */
125: public static boolean isSyntheticInit(JCTree stat) {
126: if (stat.getTag() == JCTree.EXEC) {
127: JCExpressionStatement exec = (JCExpressionStatement) stat;
128: if (exec.expr.getTag() == JCTree.ASSIGN) {
129: JCAssign assign = (JCAssign) exec.expr;
130: if (assign.lhs.getTag() == JCTree.SELECT) {
131: JCFieldAccess select = (JCFieldAccess) assign.lhs;
132: if (select.sym != null
133: && (select.sym.flags() & SYNTHETIC) != 0) {
134: Name selected = name(select.selected);
135: if (selected != null
136: && selected == selected.table._this )
137: return true;
138: }
139: }
140: }
141: }
142: return false;
143: }
144:
145: /** If the expression is a method call, return the method name, null
146: * otherwise. */
147: public static Name calledMethodName(JCTree tree) {
148: if (tree.getTag() == JCTree.EXEC) {
149: JCExpressionStatement exec = (JCExpressionStatement) tree;
150: if (exec.expr.getTag() == JCTree.APPLY) {
151: Name mname = TreeInfo
152: .name(((JCMethodInvocation) exec.expr).meth);
153: return mname;
154: }
155: }
156: return null;
157: }
158:
159: /** Is this a call to this or super?
160: */
161: public static boolean isSelfCall(JCTree tree) {
162: Name name = calledMethodName(tree);
163: if (name != null) {
164: Name.Table names = name.table;
165: return name == names._this || name == names._super ;
166: } else {
167: return false;
168: }
169: }
170:
171: /** Is this a call to super?
172: */
173: public static boolean isSuperCall(JCTree tree) {
174: Name name = calledMethodName(tree);
175: if (name != null) {
176: Name.Table names = name.table;
177: return name == names._super ;
178: } else {
179: return false;
180: }
181: }
182:
183: /** Is this a constructor whose first (non-synthetic) statement is not
184: * of the form this(...)?
185: */
186: public static boolean isInitialConstructor(JCTree tree) {
187: JCMethodInvocation app = firstConstructorCall(tree);
188: if (app == null)
189: return false;
190: Name meth = name(app.meth);
191: return meth == null || meth != meth.table._this ;
192: }
193:
194: /** Return the first call in a constructor definition. */
195: public static JCMethodInvocation firstConstructorCall(JCTree tree) {
196: if (tree.getTag() != JCTree.METHODDEF)
197: return null;
198: JCMethodDecl md = (JCMethodDecl) tree;
199: Name.Table names = md.name.table;
200: if (md.name != names.init)
201: return null;
202: if (md.body == null)
203: return null;
204: List<JCStatement> stats = md.body.stats;
205: // Synthetic initializations can appear before the super call.
206: while (stats.nonEmpty() && isSyntheticInit(stats.head))
207: stats = stats.tail;
208: if (stats.isEmpty())
209: return null;
210: if (stats.head.getTag() != JCTree.EXEC)
211: return null;
212: JCExpressionStatement exec = (JCExpressionStatement) stats.head;
213: if (exec.expr.getTag() != JCTree.APPLY)
214: return null;
215: return (JCMethodInvocation) exec.expr;
216: }
217:
218: /** Return true if a tree represents the null literal. */
219: public static boolean isNull(JCTree tree) {
220: if (tree.getTag() != JCTree.LITERAL)
221: return false;
222: JCLiteral lit = (JCLiteral) tree;
223: return (lit.typetag == TypeTags.BOT);
224: }
225:
226: /** The position of the first statement in a block, or the position of
227: * the block itself if it is empty.
228: */
229: public static int firstStatPos(JCTree tree) {
230: if (tree.getTag() == JCTree.BLOCK
231: && ((JCBlock) tree).stats.nonEmpty())
232: return ((JCBlock) tree).stats.head.pos;
233: else
234: return tree.pos;
235: }
236:
237: /** The end position of given tree, if it is a block with
238: * defined endpos.
239: */
240: public static int endPos(JCTree tree) {
241: if (tree.getTag() == JCTree.BLOCK
242: && ((JCBlock) tree).endpos != Position.NOPOS)
243: return ((JCBlock) tree).endpos;
244: else if (tree.getTag() == JCTree.SYNCHRONIZED)
245: return endPos(((JCSynchronized) tree).body);
246: else if (tree.getTag() == JCTree.TRY) {
247: JCTry t = (JCTry) tree;
248: return endPos((t.finalizer != null) ? t.finalizer
249: : t.catchers.last().body);
250: } else
251: return tree.pos;
252: }
253:
254: /** Get the start position for a tree node. The start position is
255: * defined to be the position of the first character of the first
256: * token of the node's source text.
257: * @param tree The tree node
258: */
259: public static int getStartPos(JCTree tree) {
260: if (tree == null)
261: return Position.NOPOS;
262:
263: switch (tree.getTag()) {
264: case (JCTree.APPLY):
265: return getStartPos(((JCMethodInvocation) tree).meth);
266: case (JCTree.ASSIGN):
267: return getStartPos(((JCAssign) tree).lhs);
268: case (JCTree.BITOR_ASG):
269: case (JCTree.BITXOR_ASG):
270: case (JCTree.BITAND_ASG):
271: case (JCTree.SL_ASG):
272: case (JCTree.SR_ASG):
273: case (JCTree.USR_ASG):
274: case (JCTree.PLUS_ASG):
275: case (JCTree.MINUS_ASG):
276: case (JCTree.MUL_ASG):
277: case (JCTree.DIV_ASG):
278: case (JCTree.MOD_ASG):
279: return getStartPos(((JCAssignOp) tree).lhs);
280: case (JCTree.OR):
281: case (JCTree.AND):
282: case (JCTree.BITOR):
283: case (JCTree.BITXOR):
284: case (JCTree.BITAND):
285: case (JCTree.EQ):
286: case (JCTree.NE):
287: case (JCTree.LT):
288: case (JCTree.GT):
289: case (JCTree.LE):
290: case (JCTree.GE):
291: case (JCTree.SL):
292: case (JCTree.SR):
293: case (JCTree.USR):
294: case (JCTree.PLUS):
295: case (JCTree.MINUS):
296: case (JCTree.MUL):
297: case (JCTree.DIV):
298: case (JCTree.MOD):
299: return getStartPos(((JCBinary) tree).lhs);
300: case (JCTree.CLASSDEF): {
301: JCClassDecl node = (JCClassDecl) tree;
302: if (node.mods.pos != Position.NOPOS)
303: return node.mods.pos;
304: break;
305: }
306: case (JCTree.CONDEXPR):
307: return getStartPos(((JCConditional) tree).cond);
308: case (JCTree.EXEC):
309: return getStartPos(((JCExpressionStatement) tree).expr);
310: case (JCTree.INDEXED):
311: return getStartPos(((JCArrayAccess) tree).indexed);
312: case (JCTree.METHODDEF): {
313: JCMethodDecl node = (JCMethodDecl) tree;
314: if (node.mods.pos != Position.NOPOS)
315: return node.mods.pos;
316: if (node.typarams.nonEmpty()) // List.nil() used for no typarams
317: return getStartPos(node.typarams.head);
318: return node.restype == null ? node.pos
319: : getStartPos(node.restype);
320: }
321: case (JCTree.SELECT):
322: return getStartPos(((JCFieldAccess) tree).selected);
323: case (JCTree.TYPEAPPLY):
324: return getStartPos(((JCTypeApply) tree).clazz);
325: case (JCTree.TYPEARRAY):
326: return getStartPos(((JCArrayTypeTree) tree).elemtype);
327: case (JCTree.TYPETEST):
328: return getStartPos(((JCInstanceOf) tree).expr);
329: case (JCTree.POSTINC):
330: case (JCTree.POSTDEC):
331: return getStartPos(((JCUnary) tree).arg);
332: case (JCTree.VARDEF): {
333: JCVariableDecl node = (JCVariableDecl) tree;
334: if (node.mods.pos != Position.NOPOS) {
335: return node.mods.pos;
336: } else {
337: return getStartPos(node.vartype);
338: }
339: }
340: case (JCTree.ERRONEOUS): {
341: JCErroneous node = (JCErroneous) tree;
342: if (node.errs != null && node.errs.nonEmpty())
343: return getStartPos(node.errs.head);
344: }
345: }
346: return tree.pos;
347: }
348:
349: /** The end position of given tree, given a table of end positions generated by the parser
350: */
351: public static int getEndPos(JCTree tree,
352: Map<JCTree, Integer> endPositions) {
353: if (tree == null)
354: return Position.NOPOS;
355:
356: if (endPositions == null) {
357: // fall back on limited info in the tree
358: return endPos(tree);
359: }
360:
361: Integer mapPos = endPositions.get(tree);
362: if (mapPos != null)
363: return mapPos;
364:
365: switch (tree.getTag()) {
366: case (JCTree.BITOR_ASG):
367: case (JCTree.BITXOR_ASG):
368: case (JCTree.BITAND_ASG):
369: case (JCTree.SL_ASG):
370: case (JCTree.SR_ASG):
371: case (JCTree.USR_ASG):
372: case (JCTree.PLUS_ASG):
373: case (JCTree.MINUS_ASG):
374: case (JCTree.MUL_ASG):
375: case (JCTree.DIV_ASG):
376: case (JCTree.MOD_ASG):
377: return getEndPos(((JCAssignOp) tree).rhs, endPositions);
378: case (JCTree.OR):
379: case (JCTree.AND):
380: case (JCTree.BITOR):
381: case (JCTree.BITXOR):
382: case (JCTree.BITAND):
383: case (JCTree.EQ):
384: case (JCTree.NE):
385: case (JCTree.LT):
386: case (JCTree.GT):
387: case (JCTree.LE):
388: case (JCTree.GE):
389: case (JCTree.SL):
390: case (JCTree.SR):
391: case (JCTree.USR):
392: case (JCTree.PLUS):
393: case (JCTree.MINUS):
394: case (JCTree.MUL):
395: case (JCTree.DIV):
396: case (JCTree.MOD):
397: return getEndPos(((JCBinary) tree).rhs, endPositions);
398: case (JCTree.CASE):
399: return getEndPos(((JCCase) tree).stats.last(), endPositions);
400: case (JCTree.CATCH):
401: return getEndPos(((JCCatch) tree).body, endPositions);
402: case (JCTree.CONDEXPR):
403: return getEndPos(((JCConditional) tree).falsepart,
404: endPositions);
405: case (JCTree.FORLOOP):
406: return getEndPos(((JCForLoop) tree).body, endPositions);
407: case (JCTree.FOREACHLOOP):
408: return getEndPos(((JCEnhancedForLoop) tree).body,
409: endPositions);
410: case (JCTree.IF): {
411: JCIf node = (JCIf) tree;
412: if (node.elsepart == null) {
413: return getEndPos(node.thenpart, endPositions);
414: } else {
415: return getEndPos(node.elsepart, endPositions);
416: }
417: }
418: case (JCTree.LABELLED):
419: return getEndPos(((JCLabeledStatement) tree).body,
420: endPositions);
421: case (JCTree.MODIFIERS):
422: return getEndPos(((JCModifiers) tree).annotations.last(),
423: endPositions);
424: case (JCTree.SYNCHRONIZED):
425: return getEndPos(((JCSynchronized) tree).body, endPositions);
426: case (JCTree.TOPLEVEL):
427: return getEndPos(((JCCompilationUnit) tree).defs.last(),
428: endPositions);
429: case (JCTree.TRY): {
430: JCTry node = (JCTry) tree;
431: if (node.finalizer != null) {
432: return getEndPos(node.finalizer, endPositions);
433: } else if (!node.catchers.isEmpty()) {
434: return getEndPos(node.catchers.last(), endPositions);
435: } else {
436: return getEndPos(node.body, endPositions);
437: }
438: }
439: case (JCTree.WILDCARD):
440: return getEndPos(((JCWildcard) tree).inner, endPositions);
441: case (JCTree.TYPECAST):
442: return getEndPos(((JCTypeCast) tree).expr, endPositions);
443: case (JCTree.TYPETEST):
444: return getEndPos(((JCInstanceOf) tree).clazz, endPositions);
445: case (JCTree.POS):
446: case (JCTree.NEG):
447: case (JCTree.NOT):
448: case (JCTree.COMPL):
449: case (JCTree.PREINC):
450: case (JCTree.PREDEC):
451: return getEndPos(((JCUnary) tree).arg, endPositions);
452: case (JCTree.WHILELOOP):
453: return getEndPos(((JCWhileLoop) tree).body, endPositions);
454: case (JCTree.ERRONEOUS): {
455: JCErroneous node = (JCErroneous) tree;
456: if (node.errs != null && node.errs.nonEmpty())
457: return getEndPos(node.errs.last(), endPositions);
458: }
459: }
460: return Position.NOPOS;
461: }
462:
463: /** A DiagnosticPosition with the preferred position set to the
464: * end position of given tree, if it is a block with
465: * defined endpos.
466: */
467: public static DiagnosticPosition diagEndPos(final JCTree tree) {
468: final int endPos = TreeInfo.endPos(tree);
469: return new DiagnosticPosition() {
470: public JCTree getTree() {
471: return tree;
472: }
473:
474: public int getStartPosition() {
475: return TreeInfo.getStartPos(tree);
476: }
477:
478: public int getPreferredPosition() {
479: return endPos;
480: }
481:
482: public int getEndPosition(Map<JCTree, Integer> endPosTable) {
483: return TreeInfo.getEndPos(tree, endPosTable);
484: }
485: };
486: }
487:
488: /** The position of the finalizer of given try/synchronized statement.
489: */
490: public static int finalizerPos(JCTree tree) {
491: if (tree.getTag() == JCTree.TRY) {
492: JCTry t = (JCTry) tree;
493: assert t.finalizer != null;
494: return firstStatPos(t.finalizer);
495: } else if (tree.getTag() == JCTree.SYNCHRONIZED) {
496: return endPos(((JCSynchronized) tree).body);
497: } else {
498: throw new AssertionError();
499: }
500: }
501:
502: /** Find the position for reporting an error about a symbol, where
503: * that symbol is defined somewhere in the given tree. */
504: public static int positionFor(final Symbol sym, final JCTree tree) {
505: JCTree decl = declarationFor(sym, tree);
506: return ((decl != null) ? decl : tree).pos;
507: }
508:
509: /** Find the position for reporting an error about a symbol, where
510: * that symbol is defined somewhere in the given tree. */
511: public static DiagnosticPosition diagnosticPositionFor(
512: final Symbol sym, final JCTree tree) {
513: JCTree decl = declarationFor(sym, tree);
514: return ((decl != null) ? decl : tree).pos();
515: }
516:
517: /** Find the declaration for a symbol, where
518: * that symbol is defined somewhere in the given tree. */
519: public static JCTree declarationFor(final Symbol sym,
520: final JCTree tree) {
521: class DeclScanner extends TreeScanner {
522: JCTree result = null;
523:
524: public void scan(JCTree tree) {
525: if (tree != null && result == null)
526: tree.accept(this );
527: }
528:
529: public void visitTopLevel(JCCompilationUnit that) {
530: if (that.packge == sym)
531: result = that;
532: else
533: super .visitTopLevel(that);
534: }
535:
536: public void visitClassDef(JCClassDecl that) {
537: if (that.sym == sym)
538: result = that;
539: else
540: super .visitClassDef(that);
541: }
542:
543: public void visitMethodDef(JCMethodDecl that) {
544: if (that.sym == sym)
545: result = that;
546: else
547: super .visitMethodDef(that);
548: }
549:
550: public void visitVarDef(JCVariableDecl that) {
551: if (that.sym == sym)
552: result = that;
553: else
554: super .visitVarDef(that);
555: }
556: }
557: DeclScanner s = new DeclScanner();
558: tree.accept(s);
559: return s.result;
560: }
561:
562: public static Env<AttrContext> scopeFor(JCTree node,
563: JCCompilationUnit unit) {
564: return scopeFor(pathFor(node, unit));
565: }
566:
567: public static Env<AttrContext> scopeFor(List<JCTree> path) {
568: // TODO: not implemented yet
569: throw new UnsupportedOperationException("not implemented yet");
570: }
571:
572: public static List<JCTree> pathFor(final JCTree node,
573: final JCCompilationUnit unit) {
574: class Result extends Error {
575: static final long serialVersionUID = -5942088234594905625L;
576: List<JCTree> path;
577:
578: Result(List<JCTree> path) {
579: this .path = path;
580: }
581: }
582: class PathFinder extends TreeScanner {
583: List<JCTree> path = List.nil();
584:
585: public void scan(JCTree tree) {
586: if (tree != null) {
587: path = path.prepend(tree);
588: if (tree == node)
589: throw new Result(path);
590: super .scan(tree);
591: path = path.tail;
592: }
593: }
594: }
595: try {
596: new PathFinder().scan(unit);
597: } catch (Result result) {
598: return result.path;
599: }
600: return List.nil();
601: }
602:
603: /** Return the statement referenced by a label.
604: * If the label refers to a loop or switch, return that switch
605: * otherwise return the labelled statement itself
606: */
607: public static JCTree referencedStatement(JCLabeledStatement tree) {
608: JCTree t = tree;
609: do
610: t = ((JCLabeledStatement) t).body;
611: while (t.getTag() == JCTree.LABELLED);
612: switch (t.getTag()) {
613: case JCTree.DOLOOP:
614: case JCTree.WHILELOOP:
615: case JCTree.FORLOOP:
616: case JCTree.FOREACHLOOP:
617: case JCTree.SWITCH:
618: return t;
619: default:
620: return tree;
621: }
622: }
623:
624: /** Skip parens and return the enclosed expression
625: */
626: public static JCExpression skipParens(JCExpression tree) {
627: while (tree.getTag() == JCTree.PARENS) {
628: tree = ((JCParens) tree).expr;
629: }
630: return tree;
631: }
632:
633: /** Skip parens and return the enclosed expression
634: */
635: public static JCTree skipParens(JCTree tree) {
636: if (tree.getTag() == JCTree.PARENS)
637: return skipParens((JCParens) tree);
638: else
639: return tree;
640: }
641:
642: /** Return the types of a list of trees.
643: */
644: public static List<Type> types(List<? extends JCTree> trees) {
645: ListBuffer<Type> ts = new ListBuffer<Type>();
646: for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
647: ts.append(l.head.type);
648: return ts.toList();
649: }
650:
651: /** If this tree is an identifier or a field or a parameterized type,
652: * return its name, otherwise return null.
653: */
654: public static Name name(JCTree tree) {
655: switch (tree.getTag()) {
656: case JCTree.IDENT:
657: return ((JCIdent) tree).name;
658: case JCTree.SELECT:
659: return ((JCFieldAccess) tree).name;
660: case JCTree.TYPEAPPLY:
661: return name(((JCTypeApply) tree).clazz);
662: default:
663: return null;
664: }
665: }
666:
667: /** If this tree is a qualified identifier, its return fully qualified name,
668: * otherwise return null.
669: */
670: public static Name fullName(JCTree tree) {
671: tree = skipParens(tree);
672: switch (tree.getTag()) {
673: case JCTree.IDENT:
674: return ((JCIdent) tree).name;
675: case JCTree.SELECT:
676: Name sname = fullName(((JCFieldAccess) tree).selected);
677: return sname == null ? null : sname.append('.', name(tree));
678: default:
679: return null;
680: }
681: }
682:
683: public static Symbol symbolFor(JCTree node) {
684: node = skipParens(node);
685: switch (node.getTag()) {
686: case JCTree.CLASSDEF:
687: return ((JCClassDecl) node).sym;
688: case JCTree.METHODDEF:
689: return ((JCMethodDecl) node).sym;
690: case JCTree.VARDEF:
691: return ((JCVariableDecl) node).sym;
692: default:
693: return null;
694: }
695: }
696:
697: /** If this tree is an identifier or a field, return its symbol,
698: * otherwise return null.
699: */
700: public static Symbol symbol(JCTree tree) {
701: tree = skipParens(tree);
702: switch (tree.getTag()) {
703: case JCTree.IDENT:
704: return ((JCIdent) tree).sym;
705: case JCTree.SELECT:
706: return ((JCFieldAccess) tree).sym;
707: case JCTree.TYPEAPPLY:
708: return symbol(((JCTypeApply) tree).clazz);
709: default:
710: return null;
711: }
712: }
713:
714: /** Return true if this is a nonstatic selection. */
715: public static boolean nonstaticSelect(JCTree tree) {
716: tree = skipParens(tree);
717: if (tree.getTag() != JCTree.SELECT)
718: return false;
719: JCFieldAccess s = (JCFieldAccess) tree;
720: Symbol e = symbol(s.selected);
721: return e == null
722: || (e.kind != Kinds.PCK && e.kind != Kinds.TYP);
723: }
724:
725: /** If this tree is an identifier or a field, set its symbol, otherwise skip.
726: */
727: public static void setSymbol(JCTree tree, Symbol sym) {
728: tree = skipParens(tree);
729: switch (tree.getTag()) {
730: case JCTree.IDENT:
731: ((JCIdent) tree).sym = sym;
732: break;
733: case JCTree.SELECT:
734: ((JCFieldAccess) tree).sym = sym;
735: break;
736: default:
737: }
738: }
739:
740: /** If this tree is a declaration or a block, return its flags field,
741: * otherwise return 0.
742: */
743: public static long flags(JCTree tree) {
744: switch (tree.getTag()) {
745: case JCTree.VARDEF:
746: return ((JCVariableDecl) tree).mods.flags;
747: case JCTree.METHODDEF:
748: return ((JCMethodDecl) tree).mods.flags;
749: case JCTree.CLASSDEF:
750: return ((JCClassDecl) tree).mods.flags;
751: case JCTree.BLOCK:
752: return ((JCBlock) tree).flags;
753: default:
754: return 0;
755: }
756: }
757:
758: /** Return first (smallest) flag in `flags':
759: * pre: flags != 0
760: */
761: public static long firstFlag(long flags) {
762: int flag = 1;
763: while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
764: flag = flag << 1;
765: return flag;
766: }
767:
768: /** Return flags as a string, separated by " ".
769: */
770: public static String flagNames(long flags) {
771: return Flags.toString(flags & StandardFlags).trim();
772: }
773:
774: /** Operator precedences values.
775: */
776: public static final int notExpression = -1, // not an expression
777: noPrec = 0, // no enclosing expression
778: assignPrec = 1, assignopPrec = 2, condPrec = 3,
779: orPrec = 4,
780: andPrec = 5, bitorPrec = 6, bitxorPrec = 7,
781: bitandPrec = 8,
782: eqPrec = 9, ordPrec = 10, shiftPrec = 11,
783: addPrec = 12,
784: mulPrec = 13, prefixPrec = 14,
785: postfixPrec = 15,
786: precCount = 16;
787:
788: /** Map operators to their precedence levels.
789: */
790: public static int opPrec(int op) {
791: switch (op) {
792: case JCTree.POS:
793: case JCTree.NEG:
794: case JCTree.NOT:
795: case JCTree.COMPL:
796: case JCTree.PREINC:
797: case JCTree.PREDEC:
798: return prefixPrec;
799: case JCTree.POSTINC:
800: case JCTree.POSTDEC:
801: case JCTree.NULLCHK:
802: return postfixPrec;
803: case JCTree.ASSIGN:
804: return assignPrec;
805: case JCTree.BITOR_ASG:
806: case JCTree.BITXOR_ASG:
807: case JCTree.BITAND_ASG:
808: case JCTree.SL_ASG:
809: case JCTree.SR_ASG:
810: case JCTree.USR_ASG:
811: case JCTree.PLUS_ASG:
812: case JCTree.MINUS_ASG:
813: case JCTree.MUL_ASG:
814: case JCTree.DIV_ASG:
815: case JCTree.MOD_ASG:
816: return assignopPrec;
817: case JCTree.OR:
818: return orPrec;
819: case JCTree.AND:
820: return andPrec;
821: case JCTree.EQ:
822: case JCTree.NE:
823: return eqPrec;
824: case JCTree.LT:
825: case JCTree.GT:
826: case JCTree.LE:
827: case JCTree.GE:
828: return ordPrec;
829: case JCTree.BITOR:
830: return bitorPrec;
831: case JCTree.BITXOR:
832: return bitxorPrec;
833: case JCTree.BITAND:
834: return bitandPrec;
835: case JCTree.SL:
836: case JCTree.SR:
837: case JCTree.USR:
838: return shiftPrec;
839: case JCTree.PLUS:
840: case JCTree.MINUS:
841: return addPrec;
842: case JCTree.MUL:
843: case JCTree.DIV:
844: case JCTree.MOD:
845: return mulPrec;
846: case JCTree.TYPETEST:
847: return ordPrec;
848: default:
849: throw new AssertionError();
850: }
851: }
852:
853: static Tree.Kind tagToKind(int tag) {
854: switch (tag) {
855: // Postfix expressions
856: case JCTree.POSTINC: // _ ++
857: return Tree.Kind.POSTFIX_INCREMENT;
858: case JCTree.POSTDEC: // _ --
859: return Tree.Kind.POSTFIX_DECREMENT;
860:
861: // Unary operators
862: case JCTree.PREINC: // ++ _
863: return Tree.Kind.PREFIX_INCREMENT;
864: case JCTree.PREDEC: // -- _
865: return Tree.Kind.PREFIX_DECREMENT;
866: case JCTree.POS: // +
867: return Tree.Kind.UNARY_PLUS;
868: case JCTree.NEG: // -
869: return Tree.Kind.UNARY_MINUS;
870: case JCTree.COMPL: // ~
871: return Tree.Kind.BITWISE_COMPLEMENT;
872: case JCTree.NOT: // !
873: return Tree.Kind.LOGICAL_COMPLEMENT;
874:
875: // Binary operators
876:
877: // Multiplicative operators
878: case JCTree.MUL: // *
879: return Tree.Kind.MULTIPLY;
880: case JCTree.DIV: // /
881: return Tree.Kind.DIVIDE;
882: case JCTree.MOD: // %
883: return Tree.Kind.REMAINDER;
884:
885: // Additive operators
886: case JCTree.PLUS: // +
887: return Tree.Kind.PLUS;
888: case JCTree.MINUS: // -
889: return Tree.Kind.MINUS;
890:
891: // Shift operators
892: case JCTree.SL: // <<
893: return Tree.Kind.LEFT_SHIFT;
894: case JCTree.SR: // >>
895: return Tree.Kind.RIGHT_SHIFT;
896: case JCTree.USR: // >>>
897: return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
898:
899: // Relational operators
900: case JCTree.LT: // <
901: return Tree.Kind.LESS_THAN;
902: case JCTree.GT: // >
903: return Tree.Kind.GREATER_THAN;
904: case JCTree.LE: // <=
905: return Tree.Kind.LESS_THAN_EQUAL;
906: case JCTree.GE: // >=
907: return Tree.Kind.GREATER_THAN_EQUAL;
908:
909: // Equality operators
910: case JCTree.EQ: // ==
911: return Tree.Kind.EQUAL_TO;
912: case JCTree.NE: // !=
913: return Tree.Kind.NOT_EQUAL_TO;
914:
915: // Bitwise and logical operators
916: case JCTree.BITAND: // &
917: return Tree.Kind.AND;
918: case JCTree.BITXOR: // ^
919: return Tree.Kind.XOR;
920: case JCTree.BITOR: // |
921: return Tree.Kind.OR;
922:
923: // Conditional operators
924: case JCTree.AND: // &&
925: return Tree.Kind.CONDITIONAL_AND;
926: case JCTree.OR: // ||
927: return Tree.Kind.CONDITIONAL_OR;
928:
929: // Assignment operators
930: case JCTree.MUL_ASG: // *=
931: return Tree.Kind.MULTIPLY_ASSIGNMENT;
932: case JCTree.DIV_ASG: // /=
933: return Tree.Kind.DIVIDE_ASSIGNMENT;
934: case JCTree.MOD_ASG: // %=
935: return Tree.Kind.REMAINDER_ASSIGNMENT;
936: case JCTree.PLUS_ASG: // +=
937: return Tree.Kind.PLUS_ASSIGNMENT;
938: case JCTree.MINUS_ASG: // -=
939: return Tree.Kind.MINUS_ASSIGNMENT;
940: case JCTree.SL_ASG: // <<=
941: return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
942: case JCTree.SR_ASG: // >>=
943: return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
944: case JCTree.USR_ASG: // >>>=
945: return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
946: case JCTree.BITAND_ASG: // &=
947: return Tree.Kind.AND_ASSIGNMENT;
948: case JCTree.BITXOR_ASG: // ^=
949: return Tree.Kind.XOR_ASSIGNMENT;
950: case JCTree.BITOR_ASG: // |=
951: return Tree.Kind.OR_ASSIGNMENT;
952:
953: // Null check (implementation detail), for example, __.getClass()
954: case JCTree.NULLCHK:
955: return Tree.Kind.OTHER;
956:
957: default:
958: return null;
959: }
960: }
961: }
|