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