Wed, 18 Jun 2014 12:30:29 -0400
8027886: javac allows illegal receiver parameters
8029042: Receiver parameter not supported on local class constructor
Reviewed-by: jfranck, jlahoda
1 /*
2 * Copyright (c) 1999, 2014, 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;
30 import com.sun.source.tree.Tree;
31 import com.sun.tools.javac.code.*;
32 import com.sun.tools.javac.comp.AttrContext;
33 import com.sun.tools.javac.comp.Env;
34 import com.sun.tools.javac.tree.JCTree.*;
35 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
36 import com.sun.tools.javac.util.*;
37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
38 import static com.sun.tools.javac.code.Flags.*;
39 import static com.sun.tools.javac.code.TypeTag.BOT;
40 import static com.sun.tools.javac.tree.JCTree.Tag.*;
41 import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK;
42 import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
44 /** Utility class containing inspector methods for trees.
45 *
46 * <p><b>This is NOT part of any supported API.
47 * If you write code that depends on this, you do so at your own risk.
48 * This code and its internal interfaces are subject to change or
49 * deletion without notice.</b>
50 */
51 public class TreeInfo {
52 protected static final Context.Key<TreeInfo> treeInfoKey =
53 new Context.Key<TreeInfo>();
55 public static TreeInfo instance(Context context) {
56 TreeInfo instance = context.get(treeInfoKey);
57 if (instance == null)
58 instance = new TreeInfo(context);
59 return instance;
60 }
62 /** The names of all operators.
63 */
64 private Name[] opname = new Name[Tag.getNumberOfOperators()];
66 private void setOpname(Tag tag, String name, Names names) {
67 setOpname(tag, names.fromString(name));
68 }
69 private void setOpname(Tag tag, Name name) {
70 opname[tag.operatorIndex()] = name;
71 }
73 private TreeInfo(Context context) {
74 context.put(treeInfoKey, this);
76 Names names = Names.instance(context);
77 /* Internally we use +++, --- for unary +, - to reduce +, - operators
78 * overloading
79 */
80 setOpname(POS, "+++", names);
81 setOpname(NEG, "---", names);
82 setOpname(NOT, "!", names);
83 setOpname(COMPL, "~", names);
84 setOpname(PREINC, "++", names);
85 setOpname(PREDEC, "--", names);
86 setOpname(POSTINC, "++", names);
87 setOpname(POSTDEC, "--", names);
88 setOpname(NULLCHK, "<*nullchk*>", names);
89 setOpname(OR, "||", names);
90 setOpname(AND, "&&", names);
91 setOpname(EQ, "==", names);
92 setOpname(NE, "!=", names);
93 setOpname(LT, "<", names);
94 setOpname(GT, ">", names);
95 setOpname(LE, "<=", names);
96 setOpname(GE, ">=", names);
97 setOpname(BITOR, "|", names);
98 setOpname(BITXOR, "^", names);
99 setOpname(BITAND, "&", names);
100 setOpname(SL, "<<", names);
101 setOpname(SR, ">>", names);
102 setOpname(USR, ">>>", names);
103 setOpname(PLUS, "+", names);
104 setOpname(MINUS, names.hyphen);
105 setOpname(MUL, names.asterisk);
106 setOpname(DIV, names.slash);
107 setOpname(MOD, "%", names);
108 }
110 public static List<JCExpression> args(JCTree t) {
111 switch (t.getTag()) {
112 case APPLY:
113 return ((JCMethodInvocation)t).args;
114 case NEWCLASS:
115 return ((JCNewClass)t).args;
116 default:
117 return null;
118 }
119 }
121 /** Return name of operator with given tree tag.
122 */
123 public Name operatorName(JCTree.Tag tag) {
124 return opname[tag.operatorIndex()];
125 }
127 /** Is tree a constructor declaration?
128 */
129 public static boolean isConstructor(JCTree tree) {
130 if (tree.hasTag(METHODDEF)) {
131 Name name = ((JCMethodDecl) tree).name;
132 return name == name.table.names.init;
133 } else {
134 return false;
135 }
136 }
138 public static boolean isReceiverParam(JCTree tree) {
139 if (tree.hasTag(VARDEF)) {
140 return ((JCVariableDecl)tree).nameexpr != null;
141 } else {
142 return false;
143 }
144 }
146 /** Is there a constructor declaration in the given list of trees?
147 */
148 public static boolean hasConstructors(List<JCTree> trees) {
149 for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
150 if (isConstructor(l.head)) return true;
151 return false;
152 }
154 public static boolean isMultiCatch(JCCatch catchClause) {
155 return catchClause.param.vartype.hasTag(TYPEUNION);
156 }
158 /** Is statement an initializer for a synthetic field?
159 */
160 public static boolean isSyntheticInit(JCTree stat) {
161 if (stat.hasTag(EXEC)) {
162 JCExpressionStatement exec = (JCExpressionStatement)stat;
163 if (exec.expr.hasTag(ASSIGN)) {
164 JCAssign assign = (JCAssign)exec.expr;
165 if (assign.lhs.hasTag(SELECT)) {
166 JCFieldAccess select = (JCFieldAccess)assign.lhs;
167 if (select.sym != null &&
168 (select.sym.flags() & SYNTHETIC) != 0) {
169 Name selected = name(select.selected);
170 if (selected != null && selected == selected.table.names._this)
171 return true;
172 }
173 }
174 }
175 }
176 return false;
177 }
179 /** If the expression is a method call, return the method name, null
180 * otherwise. */
181 public static Name calledMethodName(JCTree tree) {
182 if (tree.hasTag(EXEC)) {
183 JCExpressionStatement exec = (JCExpressionStatement)tree;
184 if (exec.expr.hasTag(APPLY)) {
185 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
186 return mname;
187 }
188 }
189 return null;
190 }
192 /** Is this a call to this or super?
193 */
194 public static boolean isSelfCall(JCTree tree) {
195 Name name = calledMethodName(tree);
196 if (name != null) {
197 Names names = name.table.names;
198 return name==names._this || name==names._super;
199 } else {
200 return false;
201 }
202 }
204 /** Is this a call to super?
205 */
206 public static boolean isSuperCall(JCTree tree) {
207 Name name = calledMethodName(tree);
208 if (name != null) {
209 Names names = name.table.names;
210 return name==names._super;
211 } else {
212 return false;
213 }
214 }
216 /** Is this a constructor whose first (non-synthetic) statement is not
217 * of the form this(...)?
218 */
219 public static boolean isInitialConstructor(JCTree tree) {
220 JCMethodInvocation app = firstConstructorCall(tree);
221 if (app == null) return false;
222 Name meth = name(app.meth);
223 return meth == null || meth != meth.table.names._this;
224 }
226 /** Return the first call in a constructor definition. */
227 public static JCMethodInvocation firstConstructorCall(JCTree tree) {
228 if (!tree.hasTag(METHODDEF)) return null;
229 JCMethodDecl md = (JCMethodDecl) tree;
230 Names names = md.name.table.names;
231 if (md.name != names.init) return null;
232 if (md.body == null) return null;
233 List<JCStatement> stats = md.body.stats;
234 // Synthetic initializations can appear before the super call.
235 while (stats.nonEmpty() && isSyntheticInit(stats.head))
236 stats = stats.tail;
237 if (stats.isEmpty()) return null;
238 if (!stats.head.hasTag(EXEC)) return null;
239 JCExpressionStatement exec = (JCExpressionStatement) stats.head;
240 if (!exec.expr.hasTag(APPLY)) return null;
241 return (JCMethodInvocation)exec.expr;
242 }
244 /** Return true if a tree represents a diamond new expr. */
245 public static boolean isDiamond(JCTree tree) {
246 switch(tree.getTag()) {
247 case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
248 case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
249 case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
250 default: return false;
251 }
252 }
254 public static boolean isEnumInit(JCTree tree) {
255 switch (tree.getTag()) {
256 case VARDEF:
257 return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
258 default:
259 return false;
260 }
261 }
263 /** set 'polyKind' on given tree */
264 public static void setPolyKind(JCTree tree, PolyKind pkind) {
265 switch (tree.getTag()) {
266 case APPLY:
267 ((JCMethodInvocation)tree).polyKind = pkind;
268 break;
269 case NEWCLASS:
270 ((JCNewClass)tree).polyKind = pkind;
271 break;
272 case REFERENCE:
273 ((JCMemberReference)tree).refPolyKind = pkind;
274 break;
275 default:
276 throw new AssertionError("Unexpected tree: " + tree);
277 }
278 }
280 /** set 'varargsElement' on given tree */
281 public static void setVarargsElement(JCTree tree, Type varargsElement) {
282 switch (tree.getTag()) {
283 case APPLY:
284 ((JCMethodInvocation)tree).varargsElement = varargsElement;
285 break;
286 case NEWCLASS:
287 ((JCNewClass)tree).varargsElement = varargsElement;
288 break;
289 case REFERENCE:
290 ((JCMemberReference)tree).varargsElement = varargsElement;
291 break;
292 default:
293 throw new AssertionError("Unexpected tree: " + tree);
294 }
295 }
297 /** Return true if the tree corresponds to an expression statement */
298 public static boolean isExpressionStatement(JCExpression tree) {
299 switch(tree.getTag()) {
300 case PREINC: case PREDEC:
301 case POSTINC: case POSTDEC:
302 case ASSIGN:
303 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
304 case SL_ASG: case SR_ASG: case USR_ASG:
305 case PLUS_ASG: case MINUS_ASG:
306 case MUL_ASG: case DIV_ASG: case MOD_ASG:
307 case APPLY: case NEWCLASS:
308 case ERRONEOUS:
309 return true;
310 default:
311 return false;
312 }
313 }
315 /**
316 * Return true if the AST corresponds to a static select of the kind A.B
317 */
318 public static boolean isStaticSelector(JCTree base, Names names) {
319 if (base == null)
320 return false;
321 switch (base.getTag()) {
322 case IDENT:
323 JCIdent id = (JCIdent)base;
324 return id.name != names._this &&
325 id.name != names._super &&
326 isStaticSym(base);
327 case SELECT:
328 return isStaticSym(base) &&
329 isStaticSelector(((JCFieldAccess)base).selected, names);
330 case TYPEAPPLY:
331 case TYPEARRAY:
332 return true;
333 case ANNOTATED_TYPE:
334 return isStaticSelector(((JCAnnotatedType)base).underlyingType, names);
335 default:
336 return false;
337 }
338 }
339 //where
340 private static boolean isStaticSym(JCTree tree) {
341 Symbol sym = symbol(tree);
342 return (sym.kind == Kinds.TYP ||
343 sym.kind == Kinds.PCK);
344 }
346 /** Return true if a tree represents the null literal. */
347 public static boolean isNull(JCTree tree) {
348 if (!tree.hasTag(LITERAL))
349 return false;
350 JCLiteral lit = (JCLiteral) tree;
351 return (lit.typetag == BOT);
352 }
354 public static String getCommentText(Env<?> env, JCTree tree) {
355 DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
356 ? ((JCCompilationUnit) tree).docComments
357 : env.toplevel.docComments;
358 return (docComments == null) ? null : docComments.getCommentText(tree);
359 }
361 public static DCTree.DCDocComment getCommentTree(Env<?> env, JCTree tree) {
362 DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
363 ? ((JCCompilationUnit) tree).docComments
364 : env.toplevel.docComments;
365 return (docComments == null) ? null : docComments.getCommentTree(tree);
366 }
368 /** The position of the first statement in a block, or the position of
369 * the block itself if it is empty.
370 */
371 public static int firstStatPos(JCTree tree) {
372 if (tree.hasTag(BLOCK) && ((JCBlock) tree).stats.nonEmpty())
373 return ((JCBlock) tree).stats.head.pos;
374 else
375 return tree.pos;
376 }
378 /** The end position of given tree, if it is a block with
379 * defined endpos.
380 */
381 public static int endPos(JCTree tree) {
382 if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS)
383 return ((JCBlock) tree).endpos;
384 else if (tree.hasTag(SYNCHRONIZED))
385 return endPos(((JCSynchronized) tree).body);
386 else if (tree.hasTag(TRY)) {
387 JCTry t = (JCTry) tree;
388 return endPos((t.finalizer != null) ? t.finalizer
389 : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body));
390 } else
391 return tree.pos;
392 }
395 /** Get the start position for a tree node. The start position is
396 * defined to be the position of the first character of the first
397 * token of the node's source text.
398 * @param tree The tree node
399 */
400 public static int getStartPos(JCTree tree) {
401 if (tree == null)
402 return Position.NOPOS;
404 switch(tree.getTag()) {
405 case APPLY:
406 return getStartPos(((JCMethodInvocation) tree).meth);
407 case ASSIGN:
408 return getStartPos(((JCAssign) tree).lhs);
409 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
410 case SL_ASG: case SR_ASG: case USR_ASG:
411 case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
412 case DIV_ASG: case MOD_ASG:
413 return getStartPos(((JCAssignOp) tree).lhs);
414 case OR: case AND: case BITOR:
415 case BITXOR: case BITAND: case EQ:
416 case NE: case LT: case GT:
417 case LE: case GE: case SL:
418 case SR: case USR: case PLUS:
419 case MINUS: case MUL: case DIV:
420 case MOD:
421 return getStartPos(((JCBinary) tree).lhs);
422 case CLASSDEF: {
423 JCClassDecl node = (JCClassDecl)tree;
424 if (node.mods.pos != Position.NOPOS)
425 return node.mods.pos;
426 break;
427 }
428 case CONDEXPR:
429 return getStartPos(((JCConditional) tree).cond);
430 case EXEC:
431 return getStartPos(((JCExpressionStatement) tree).expr);
432 case INDEXED:
433 return getStartPos(((JCArrayAccess) tree).indexed);
434 case METHODDEF: {
435 JCMethodDecl node = (JCMethodDecl)tree;
436 if (node.mods.pos != Position.NOPOS)
437 return node.mods.pos;
438 if (node.typarams.nonEmpty()) // List.nil() used for no typarams
439 return getStartPos(node.typarams.head);
440 return node.restype == null ? node.pos : getStartPos(node.restype);
441 }
442 case SELECT:
443 return getStartPos(((JCFieldAccess) tree).selected);
444 case TYPEAPPLY:
445 return getStartPos(((JCTypeApply) tree).clazz);
446 case TYPEARRAY:
447 return getStartPos(((JCArrayTypeTree) tree).elemtype);
448 case TYPETEST:
449 return getStartPos(((JCInstanceOf) tree).expr);
450 case POSTINC:
451 case POSTDEC:
452 return getStartPos(((JCUnary) tree).arg);
453 case ANNOTATED_TYPE: {
454 JCAnnotatedType node = (JCAnnotatedType) tree;
455 if (node.annotations.nonEmpty()) {
456 if (node.underlyingType.hasTag(TYPEARRAY) ||
457 node.underlyingType.hasTag(SELECT)) {
458 return getStartPos(node.underlyingType);
459 } else {
460 return getStartPos(node.annotations.head);
461 }
462 } else {
463 return getStartPos(node.underlyingType);
464 }
465 }
466 case NEWCLASS: {
467 JCNewClass node = (JCNewClass)tree;
468 if (node.encl != null)
469 return getStartPos(node.encl);
470 break;
471 }
472 case VARDEF: {
473 JCVariableDecl node = (JCVariableDecl)tree;
474 if (node.mods.pos != Position.NOPOS) {
475 return node.mods.pos;
476 } else if (node.vartype == null) {
477 //if there's no type (partially typed lambda parameter)
478 //simply return node position
479 return node.pos;
480 } else {
481 return getStartPos(node.vartype);
482 }
483 }
484 case ERRONEOUS: {
485 JCErroneous node = (JCErroneous)tree;
486 if (node.errs != null && node.errs.nonEmpty())
487 return getStartPos(node.errs.head);
488 }
489 }
490 return tree.pos;
491 }
493 /** The end position of given tree, given a table of end positions generated by the parser
494 */
495 public static int getEndPos(JCTree tree, EndPosTable endPosTable) {
496 if (tree == null)
497 return Position.NOPOS;
499 if (endPosTable == null) {
500 // fall back on limited info in the tree
501 return endPos(tree);
502 }
504 int mapPos = endPosTable.getEndPos(tree);
505 if (mapPos != Position.NOPOS)
506 return mapPos;
508 switch(tree.getTag()) {
509 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
510 case SL_ASG: case SR_ASG: case USR_ASG:
511 case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
512 case DIV_ASG: case MOD_ASG:
513 return getEndPos(((JCAssignOp) tree).rhs, endPosTable);
514 case OR: case AND: case BITOR:
515 case BITXOR: case BITAND: case EQ:
516 case NE: case LT: case GT:
517 case LE: case GE: case SL:
518 case SR: case USR: case PLUS:
519 case MINUS: case MUL: case DIV:
520 case MOD:
521 return getEndPos(((JCBinary) tree).rhs, endPosTable);
522 case CASE:
523 return getEndPos(((JCCase) tree).stats.last(), endPosTable);
524 case CATCH:
525 return getEndPos(((JCCatch) tree).body, endPosTable);
526 case CONDEXPR:
527 return getEndPos(((JCConditional) tree).falsepart, endPosTable);
528 case FORLOOP:
529 return getEndPos(((JCForLoop) tree).body, endPosTable);
530 case FOREACHLOOP:
531 return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable);
532 case IF: {
533 JCIf node = (JCIf)tree;
534 if (node.elsepart == null) {
535 return getEndPos(node.thenpart, endPosTable);
536 } else {
537 return getEndPos(node.elsepart, endPosTable);
538 }
539 }
540 case LABELLED:
541 return getEndPos(((JCLabeledStatement) tree).body, endPosTable);
542 case MODIFIERS:
543 return getEndPos(((JCModifiers) tree).annotations.last(), endPosTable);
544 case SYNCHRONIZED:
545 return getEndPos(((JCSynchronized) tree).body, endPosTable);
546 case TOPLEVEL:
547 return getEndPos(((JCCompilationUnit) tree).defs.last(), endPosTable);
548 case TRY: {
549 JCTry node = (JCTry)tree;
550 if (node.finalizer != null) {
551 return getEndPos(node.finalizer, endPosTable);
552 } else if (!node.catchers.isEmpty()) {
553 return getEndPos(node.catchers.last(), endPosTable);
554 } else {
555 return getEndPos(node.body, endPosTable);
556 }
557 }
558 case WILDCARD:
559 return getEndPos(((JCWildcard) tree).inner, endPosTable);
560 case TYPECAST:
561 return getEndPos(((JCTypeCast) tree).expr, endPosTable);
562 case TYPETEST:
563 return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
564 case POS:
565 case NEG:
566 case NOT:
567 case COMPL:
568 case PREINC:
569 case PREDEC:
570 return getEndPos(((JCUnary) tree).arg, endPosTable);
571 case WHILELOOP:
572 return getEndPos(((JCWhileLoop) tree).body, endPosTable);
573 case ANNOTATED_TYPE:
574 return getEndPos(((JCAnnotatedType) tree).underlyingType, endPosTable);
575 case ERRONEOUS: {
576 JCErroneous node = (JCErroneous)tree;
577 if (node.errs != null && node.errs.nonEmpty())
578 return getEndPos(node.errs.last(), endPosTable);
579 }
580 }
581 return Position.NOPOS;
582 }
585 /** A DiagnosticPosition with the preferred position set to the
586 * end position of given tree, if it is a block with
587 * defined endpos.
588 */
589 public static DiagnosticPosition diagEndPos(final JCTree tree) {
590 final int endPos = TreeInfo.endPos(tree);
591 return new DiagnosticPosition() {
592 public JCTree getTree() { return tree; }
593 public int getStartPosition() { return TreeInfo.getStartPos(tree); }
594 public int getPreferredPosition() { return endPos; }
595 public int getEndPosition(EndPosTable endPosTable) {
596 return TreeInfo.getEndPos(tree, endPosTable);
597 }
598 };
599 }
601 /** The position of the finalizer of given try/synchronized statement.
602 */
603 public static int finalizerPos(JCTree tree) {
604 if (tree.hasTag(TRY)) {
605 JCTry t = (JCTry) tree;
606 Assert.checkNonNull(t.finalizer);
607 return firstStatPos(t.finalizer);
608 } else if (tree.hasTag(SYNCHRONIZED)) {
609 return endPos(((JCSynchronized) tree).body);
610 } else {
611 throw new AssertionError();
612 }
613 }
615 /** Find the position for reporting an error about a symbol, where
616 * that symbol is defined somewhere in the given tree. */
617 public static int positionFor(final Symbol sym, final JCTree tree) {
618 JCTree decl = declarationFor(sym, tree);
619 return ((decl != null) ? decl : tree).pos;
620 }
622 /** Find the position for reporting an error about a symbol, where
623 * that symbol is defined somewhere in the given tree. */
624 public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
625 JCTree decl = declarationFor(sym, tree);
626 return ((decl != null) ? decl : tree).pos();
627 }
629 /** Find the declaration for a symbol, where
630 * that symbol is defined somewhere in the given tree. */
631 public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
632 class DeclScanner extends TreeScanner {
633 JCTree result = null;
634 public void scan(JCTree tree) {
635 if (tree!=null && result==null)
636 tree.accept(this);
637 }
638 public void visitTopLevel(JCCompilationUnit that) {
639 if (that.packge == sym) result = that;
640 else super.visitTopLevel(that);
641 }
642 public void visitClassDef(JCClassDecl that) {
643 if (that.sym == sym) result = that;
644 else super.visitClassDef(that);
645 }
646 public void visitMethodDef(JCMethodDecl that) {
647 if (that.sym == sym) result = that;
648 else super.visitMethodDef(that);
649 }
650 public void visitVarDef(JCVariableDecl that) {
651 if (that.sym == sym) result = that;
652 else super.visitVarDef(that);
653 }
654 public void visitTypeParameter(JCTypeParameter that) {
655 if (that.type != null && that.type.tsym == sym) result = that;
656 else super.visitTypeParameter(that);
657 }
658 }
659 DeclScanner s = new DeclScanner();
660 tree.accept(s);
661 return s.result;
662 }
664 public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
665 return scopeFor(pathFor(node, unit));
666 }
668 public static Env<AttrContext> scopeFor(List<JCTree> path) {
669 // TODO: not implemented yet
670 throw new UnsupportedOperationException("not implemented yet");
671 }
673 public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
674 class Result extends Error {
675 static final long serialVersionUID = -5942088234594905625L;
676 List<JCTree> path;
677 Result(List<JCTree> path) {
678 this.path = path;
679 }
680 }
681 class PathFinder extends TreeScanner {
682 List<JCTree> path = List.nil();
683 public void scan(JCTree tree) {
684 if (tree != null) {
685 path = path.prepend(tree);
686 if (tree == node)
687 throw new Result(path);
688 super.scan(tree);
689 path = path.tail;
690 }
691 }
692 }
693 try {
694 new PathFinder().scan(unit);
695 } catch (Result result) {
696 return result.path;
697 }
698 return List.nil();
699 }
701 /** Return the statement referenced by a label.
702 * If the label refers to a loop or switch, return that switch
703 * otherwise return the labelled statement itself
704 */
705 public static JCTree referencedStatement(JCLabeledStatement tree) {
706 JCTree t = tree;
707 do t = ((JCLabeledStatement) t).body;
708 while (t.hasTag(LABELLED));
709 switch (t.getTag()) {
710 case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH:
711 return t;
712 default:
713 return tree;
714 }
715 }
717 /** Skip parens and return the enclosed expression
718 */
719 public static JCExpression skipParens(JCExpression tree) {
720 while (tree.hasTag(PARENS)) {
721 tree = ((JCParens) tree).expr;
722 }
723 return tree;
724 }
726 /** Skip parens and return the enclosed expression
727 */
728 public static JCTree skipParens(JCTree tree) {
729 if (tree.hasTag(PARENS))
730 return skipParens((JCParens)tree);
731 else
732 return tree;
733 }
735 /** Return the types of a list of trees.
736 */
737 public static List<Type> types(List<? extends JCTree> trees) {
738 ListBuffer<Type> ts = new ListBuffer<Type>();
739 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
740 ts.append(l.head.type);
741 return ts.toList();
742 }
744 /** If this tree is an identifier or a field or a parameterized type,
745 * return its name, otherwise return null.
746 */
747 public static Name name(JCTree tree) {
748 switch (tree.getTag()) {
749 case IDENT:
750 return ((JCIdent) tree).name;
751 case SELECT:
752 return ((JCFieldAccess) tree).name;
753 case TYPEAPPLY:
754 return name(((JCTypeApply) tree).clazz);
755 default:
756 return null;
757 }
758 }
760 /** If this tree is a qualified identifier, its return fully qualified name,
761 * otherwise return null.
762 */
763 public static Name fullName(JCTree tree) {
764 tree = skipParens(tree);
765 switch (tree.getTag()) {
766 case IDENT:
767 return ((JCIdent) tree).name;
768 case SELECT:
769 Name sname = fullName(((JCFieldAccess) tree).selected);
770 return sname == null ? null : sname.append('.', name(tree));
771 default:
772 return null;
773 }
774 }
776 public static Symbol symbolFor(JCTree node) {
777 Symbol sym = symbolForImpl(node);
779 return sym != null ? sym.baseSymbol() : null;
780 }
782 private static Symbol symbolForImpl(JCTree node) {
783 node = skipParens(node);
784 switch (node.getTag()) {
785 case TOPLEVEL:
786 return ((JCCompilationUnit) node).packge;
787 case CLASSDEF:
788 return ((JCClassDecl) node).sym;
789 case METHODDEF:
790 return ((JCMethodDecl) node).sym;
791 case VARDEF:
792 return ((JCVariableDecl) node).sym;
793 case IDENT:
794 return ((JCIdent) node).sym;
795 case SELECT:
796 return ((JCFieldAccess) node).sym;
797 case REFERENCE:
798 return ((JCMemberReference) node).sym;
799 case NEWCLASS:
800 return ((JCNewClass) node).constructor;
801 case APPLY:
802 return symbolFor(((JCMethodInvocation) node).meth);
803 case TYPEAPPLY:
804 return symbolFor(((JCTypeApply) node).clazz);
805 case ANNOTATION:
806 case TYPE_ANNOTATION:
807 case TYPEPARAMETER:
808 if (node.type != null)
809 return node.type.tsym;
810 return null;
811 default:
812 return null;
813 }
814 }
816 public static boolean isDeclaration(JCTree node) {
817 node = skipParens(node);
818 switch (node.getTag()) {
819 case CLASSDEF:
820 case METHODDEF:
821 case VARDEF:
822 return true;
823 default:
824 return false;
825 }
826 }
828 /** If this tree is an identifier or a field, return its symbol,
829 * otherwise return null.
830 */
831 public static Symbol symbol(JCTree tree) {
832 tree = skipParens(tree);
833 switch (tree.getTag()) {
834 case IDENT:
835 return ((JCIdent) tree).sym;
836 case SELECT:
837 return ((JCFieldAccess) tree).sym;
838 case TYPEAPPLY:
839 return symbol(((JCTypeApply) tree).clazz);
840 case ANNOTATED_TYPE:
841 return symbol(((JCAnnotatedType) tree).underlyingType);
842 case REFERENCE:
843 return ((JCMemberReference) tree).sym;
844 default:
845 return null;
846 }
847 }
849 /** Return true if this is a nonstatic selection. */
850 public static boolean nonstaticSelect(JCTree tree) {
851 tree = skipParens(tree);
852 if (!tree.hasTag(SELECT)) return false;
853 JCFieldAccess s = (JCFieldAccess) tree;
854 Symbol e = symbol(s.selected);
855 return e == null || (e.kind != Kinds.PCK && e.kind != Kinds.TYP);
856 }
858 /** If this tree is an identifier or a field, set its symbol, otherwise skip.
859 */
860 public static void setSymbol(JCTree tree, Symbol sym) {
861 tree = skipParens(tree);
862 switch (tree.getTag()) {
863 case IDENT:
864 ((JCIdent) tree).sym = sym; break;
865 case SELECT:
866 ((JCFieldAccess) tree).sym = sym; break;
867 default:
868 }
869 }
871 /** If this tree is a declaration or a block, return its flags field,
872 * otherwise return 0.
873 */
874 public static long flags(JCTree tree) {
875 switch (tree.getTag()) {
876 case VARDEF:
877 return ((JCVariableDecl) tree).mods.flags;
878 case METHODDEF:
879 return ((JCMethodDecl) tree).mods.flags;
880 case CLASSDEF:
881 return ((JCClassDecl) tree).mods.flags;
882 case BLOCK:
883 return ((JCBlock) tree).flags;
884 default:
885 return 0;
886 }
887 }
889 /** Return first (smallest) flag in `flags':
890 * pre: flags != 0
891 */
892 public static long firstFlag(long flags) {
893 long flag = 1;
894 while ((flag & flags & ExtendedStandardFlags) == 0)
895 flag = flag << 1;
896 return flag;
897 }
899 /** Return flags as a string, separated by " ".
900 */
901 public static String flagNames(long flags) {
902 return Flags.toString(flags & ExtendedStandardFlags).trim();
903 }
905 /** Operator precedences values.
906 */
907 public static final int
908 notExpression = -1, // not an expression
909 noPrec = 0, // no enclosing expression
910 assignPrec = 1,
911 assignopPrec = 2,
912 condPrec = 3,
913 orPrec = 4,
914 andPrec = 5,
915 bitorPrec = 6,
916 bitxorPrec = 7,
917 bitandPrec = 8,
918 eqPrec = 9,
919 ordPrec = 10,
920 shiftPrec = 11,
921 addPrec = 12,
922 mulPrec = 13,
923 prefixPrec = 14,
924 postfixPrec = 15,
925 precCount = 16;
928 /** Map operators to their precedence levels.
929 */
930 public static int opPrec(JCTree.Tag op) {
931 switch(op) {
932 case POS:
933 case NEG:
934 case NOT:
935 case COMPL:
936 case PREINC:
937 case PREDEC: return prefixPrec;
938 case POSTINC:
939 case POSTDEC:
940 case NULLCHK: return postfixPrec;
941 case ASSIGN: return assignPrec;
942 case BITOR_ASG:
943 case BITXOR_ASG:
944 case BITAND_ASG:
945 case SL_ASG:
946 case SR_ASG:
947 case USR_ASG:
948 case PLUS_ASG:
949 case MINUS_ASG:
950 case MUL_ASG:
951 case DIV_ASG:
952 case MOD_ASG: return assignopPrec;
953 case OR: return orPrec;
954 case AND: return andPrec;
955 case EQ:
956 case NE: return eqPrec;
957 case LT:
958 case GT:
959 case LE:
960 case GE: return ordPrec;
961 case BITOR: return bitorPrec;
962 case BITXOR: return bitxorPrec;
963 case BITAND: return bitandPrec;
964 case SL:
965 case SR:
966 case USR: return shiftPrec;
967 case PLUS:
968 case MINUS: return addPrec;
969 case MUL:
970 case DIV:
971 case MOD: return mulPrec;
972 case TYPETEST: return ordPrec;
973 default: throw new AssertionError();
974 }
975 }
977 static Tree.Kind tagToKind(JCTree.Tag tag) {
978 switch (tag) {
979 // Postfix expressions
980 case POSTINC: // _ ++
981 return Tree.Kind.POSTFIX_INCREMENT;
982 case POSTDEC: // _ --
983 return Tree.Kind.POSTFIX_DECREMENT;
985 // Unary operators
986 case PREINC: // ++ _
987 return Tree.Kind.PREFIX_INCREMENT;
988 case PREDEC: // -- _
989 return Tree.Kind.PREFIX_DECREMENT;
990 case POS: // +
991 return Tree.Kind.UNARY_PLUS;
992 case NEG: // -
993 return Tree.Kind.UNARY_MINUS;
994 case COMPL: // ~
995 return Tree.Kind.BITWISE_COMPLEMENT;
996 case NOT: // !
997 return Tree.Kind.LOGICAL_COMPLEMENT;
999 // Binary operators
1001 // Multiplicative operators
1002 case MUL: // *
1003 return Tree.Kind.MULTIPLY;
1004 case DIV: // /
1005 return Tree.Kind.DIVIDE;
1006 case MOD: // %
1007 return Tree.Kind.REMAINDER;
1009 // Additive operators
1010 case PLUS: // +
1011 return Tree.Kind.PLUS;
1012 case MINUS: // -
1013 return Tree.Kind.MINUS;
1015 // Shift operators
1016 case SL: // <<
1017 return Tree.Kind.LEFT_SHIFT;
1018 case SR: // >>
1019 return Tree.Kind.RIGHT_SHIFT;
1020 case USR: // >>>
1021 return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
1023 // Relational operators
1024 case LT: // <
1025 return Tree.Kind.LESS_THAN;
1026 case GT: // >
1027 return Tree.Kind.GREATER_THAN;
1028 case LE: // <=
1029 return Tree.Kind.LESS_THAN_EQUAL;
1030 case GE: // >=
1031 return Tree.Kind.GREATER_THAN_EQUAL;
1033 // Equality operators
1034 case EQ: // ==
1035 return Tree.Kind.EQUAL_TO;
1036 case NE: // !=
1037 return Tree.Kind.NOT_EQUAL_TO;
1039 // Bitwise and logical operators
1040 case BITAND: // &
1041 return Tree.Kind.AND;
1042 case BITXOR: // ^
1043 return Tree.Kind.XOR;
1044 case BITOR: // |
1045 return Tree.Kind.OR;
1047 // Conditional operators
1048 case AND: // &&
1049 return Tree.Kind.CONDITIONAL_AND;
1050 case OR: // ||
1051 return Tree.Kind.CONDITIONAL_OR;
1053 // Assignment operators
1054 case MUL_ASG: // *=
1055 return Tree.Kind.MULTIPLY_ASSIGNMENT;
1056 case DIV_ASG: // /=
1057 return Tree.Kind.DIVIDE_ASSIGNMENT;
1058 case MOD_ASG: // %=
1059 return Tree.Kind.REMAINDER_ASSIGNMENT;
1060 case PLUS_ASG: // +=
1061 return Tree.Kind.PLUS_ASSIGNMENT;
1062 case MINUS_ASG: // -=
1063 return Tree.Kind.MINUS_ASSIGNMENT;
1064 case SL_ASG: // <<=
1065 return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
1066 case SR_ASG: // >>=
1067 return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
1068 case USR_ASG: // >>>=
1069 return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
1070 case BITAND_ASG: // &=
1071 return Tree.Kind.AND_ASSIGNMENT;
1072 case BITXOR_ASG: // ^=
1073 return Tree.Kind.XOR_ASSIGNMENT;
1074 case BITOR_ASG: // |=
1075 return Tree.Kind.OR_ASSIGNMENT;
1077 // Null check (implementation detail), for example, __.getClass()
1078 case NULLCHK:
1079 return Tree.Kind.OTHER;
1081 case ANNOTATION:
1082 return Tree.Kind.ANNOTATION;
1083 case TYPE_ANNOTATION:
1084 return Tree.Kind.TYPE_ANNOTATION;
1086 default:
1087 return null;
1088 }
1089 }
1091 /**
1092 * Returns the underlying type of the tree if it is an annotated type,
1093 * or the tree itself otherwise.
1094 */
1095 public static JCExpression typeIn(JCExpression tree) {
1096 switch (tree.getTag()) {
1097 case ANNOTATED_TYPE:
1098 return ((JCAnnotatedType)tree).underlyingType;
1099 case IDENT: /* simple names */
1100 case TYPEIDENT: /* primitive name */
1101 case SELECT: /* qualified name */
1102 case TYPEARRAY: /* array types */
1103 case WILDCARD: /* wild cards */
1104 case TYPEPARAMETER: /* type parameters */
1105 case TYPEAPPLY: /* parameterized types */
1106 case ERRONEOUS: /* error tree TODO: needed for BadCast JSR308 test case. Better way? */
1107 return tree;
1108 default:
1109 throw new AssertionError("Unexpected type tree: " + tree);
1110 }
1111 }
1113 /* Return the inner-most type of a type tree.
1114 * For an array that contains an annotated type, return that annotated type.
1115 * TODO: currently only used by Pretty. Describe behavior better.
1116 */
1117 public static JCTree innermostType(JCTree type) {
1118 JCTree lastAnnotatedType = null;
1119 JCTree cur = type;
1120 loop: while (true) {
1121 switch (cur.getTag()) {
1122 case TYPEARRAY:
1123 lastAnnotatedType = null;
1124 cur = ((JCArrayTypeTree)cur).elemtype;
1125 break;
1126 case WILDCARD:
1127 lastAnnotatedType = null;
1128 cur = ((JCWildcard)cur).inner;
1129 break;
1130 case ANNOTATED_TYPE:
1131 lastAnnotatedType = cur;
1132 cur = ((JCAnnotatedType)cur).underlyingType;
1133 break;
1134 default:
1135 break loop;
1136 }
1137 }
1138 if (lastAnnotatedType!=null) {
1139 return lastAnnotatedType;
1140 } else {
1141 return cur;
1142 }
1143 }
1145 private static class TypeAnnotationFinder extends TreeScanner {
1146 public boolean foundTypeAnno = false;
1148 @Override
1149 public void scan(JCTree tree) {
1150 if (foundTypeAnno || tree == null)
1151 return;
1152 super.scan(tree);
1153 }
1155 public void visitAnnotation(JCAnnotation tree) {
1156 foundTypeAnno = foundTypeAnno || tree.hasTag(TYPE_ANNOTATION);
1157 }
1158 }
1160 public static boolean containsTypeAnnotation(JCTree e) {
1161 TypeAnnotationFinder finder = new TypeAnnotationFinder();
1162 finder.scan(e);
1163 return finder.foundTypeAnno;
1164 }
1165 }