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