1 /* 2 * Copyright (c) 1999, 2024, 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 26 package com.sun.tools.javac.tree; 27 28 29 30 import com.sun.source.tree.Tree; 31 import com.sun.source.util.TreePath; 32 import com.sun.tools.javac.code.*; 33 import com.sun.tools.javac.code.Symbol.RecordComponent; 34 import com.sun.tools.javac.comp.AttrContext; 35 import com.sun.tools.javac.comp.Env; 36 import com.sun.tools.javac.tree.JCTree.*; 37 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; 38 import com.sun.tools.javac.util.*; 39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 40 41 import static com.sun.tools.javac.code.Flags.*; 42 import static com.sun.tools.javac.code.Kinds.Kind.*; 43 import com.sun.tools.javac.code.Symbol.VarSymbol; 44 import static com.sun.tools.javac.code.TypeTag.BOOLEAN; 45 import static com.sun.tools.javac.code.TypeTag.BOT; 46 import static com.sun.tools.javac.tree.JCTree.Tag.*; 47 import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK; 48 import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED; 49 50 import javax.lang.model.element.ElementKind; 51 import javax.tools.JavaFileObject; 52 53 import java.util.function.Function; 54 import java.util.function.Predicate; 55 import java.util.function.ToIntFunction; 56 57 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT; 58 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.RIGHT; 59 60 /** Utility class containing inspector methods for trees. 61 * 62 * <p><b>This is NOT part of any supported API. 63 * If you write code that depends on this, you do so at your own risk. 64 * This code and its internal interfaces are subject to change or 65 * deletion without notice.</b> 66 */ 67 public class TreeInfo { 68 69 public static List<JCExpression> args(JCTree t) { 70 switch (t.getTag()) { 71 case APPLY: 72 return ((JCMethodInvocation)t).args; 73 case NEWCLASS: 74 return ((JCNewClass)t).args; 75 default: 76 return null; 77 } 78 } 79 80 /** Is tree a constructor declaration? 81 */ 82 public static boolean isConstructor(JCTree tree) { 83 if (tree.hasTag(METHODDEF)) { 84 Name name = ((JCMethodDecl) tree).name; 85 return name == name.table.names.init; 86 } else { 87 return false; 88 } 89 } 90 91 public static boolean isCanonicalConstructor(JCTree tree) { 92 // the record flag is only set to the canonical constructor 93 return isConstructor(tree) && (((JCMethodDecl)tree).sym.flags_field & RECORD) != 0; 94 } 95 96 public static boolean isCompactConstructor(JCTree tree) { 97 // the record flag is only set to the canonical constructor 98 return isCanonicalConstructor(tree) && (((JCMethodDecl)tree).sym.flags_field & COMPACT_RECORD_CONSTRUCTOR) != 0; 99 } 100 101 public static boolean isReceiverParam(JCTree tree) { 102 if (tree.hasTag(VARDEF)) { 103 return ((JCVariableDecl)tree).nameexpr != null; 104 } else { 105 return false; 106 } 107 } 108 109 /** Is there a constructor declaration in the given list of trees? 110 */ 111 public static boolean hasConstructors(List<JCTree> trees) { 112 for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail) 113 if (isConstructor(l.head)) return true; 114 return false; 115 } 116 117 public static boolean isMultiCatch(JCCatch catchClause) { 118 return catchClause.param.vartype.hasTag(TYPEUNION); 119 } 120 121 /** Is statement an initializer for a synthetic field? 122 */ 123 public static boolean isSyntheticInit(JCTree stat) { 124 if (stat.hasTag(EXEC)) { 125 JCExpressionStatement exec = (JCExpressionStatement)stat; 126 if (exec.expr.hasTag(ASSIGN)) { 127 JCAssign assign = (JCAssign)exec.expr; 128 if (assign.lhs.hasTag(SELECT)) { 129 JCFieldAccess select = (JCFieldAccess)assign.lhs; 130 if (select.sym != null && 131 (select.sym.flags() & SYNTHETIC) != 0) { 132 Name selected = name(select.selected); 133 if (selected != null && selected == selected.table.names._this) 134 return true; 135 } 136 } 137 } 138 } 139 return false; 140 } 141 142 /** If the expression is a method call, return the method name, null 143 * otherwise. */ 144 public static Name calledMethodName(JCTree tree) { 145 if (tree.hasTag(EXEC)) { 146 JCExpressionStatement exec = (JCExpressionStatement)tree; 147 if (exec.expr.hasTag(APPLY)) { 148 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth); 149 return mname; 150 } 151 } 152 return null; 153 } 154 155 /** Is this tree a 'this' identifier? 156 */ 157 public static boolean isThisQualifier(JCTree tree) { 158 switch (tree.getTag()) { 159 case PARENS: 160 return isThisQualifier(skipParens(tree)); 161 case IDENT: { 162 JCIdent id = (JCIdent)tree; 163 return id.name == id.name.table.names._this; 164 } 165 default: 166 return false; 167 } 168 } 169 170 public static boolean isSuperQualifier(JCTree tree) { 171 switch (tree.getTag()) { 172 case PARENS: 173 return isThisQualifier(skipParens(tree)); 174 case IDENT: { 175 JCIdent id = (JCIdent)tree; 176 return id.name == id.name.table.names._super; 177 } 178 default: 179 return false; 180 } 181 } 182 183 /** Is this tree an identifier, possibly qualified by 'this'? 184 */ 185 public static boolean isIdentOrThisDotIdent(JCTree tree) { 186 switch (tree.getTag()) { 187 case PARENS: 188 return isIdentOrThisDotIdent(skipParens(tree)); 189 case IDENT: 190 return true; 191 case SELECT: 192 return isThisQualifier(((JCFieldAccess)tree).selected); 193 default: 194 return false; 195 } 196 } 197 198 /** Check if the given tree is an explicit reference to the 'this' instance of the 199 * class currently being compiled. This is true if tree is: 200 * - An unqualified 'this' identifier 201 * - A 'super' identifier qualified by a class name whose type is 'currentClass' or a supertype 202 * - A 'this' identifier qualified by a class name whose type is 'currentClass' or a supertype 203 * but also NOT an enclosing outer class of 'currentClass'. 204 */ 205 public static boolean isExplicitThisReference(Types types, Type.ClassType currentClass, JCTree tree) { 206 switch (tree.getTag()) { 207 case PARENS: 208 return isExplicitThisReference(types, currentClass, skipParens(tree)); 209 case IDENT: { 210 JCIdent ident = (JCIdent)tree; 211 Names names = ident.name.table.names; 212 return ident.name == names._this || ident.name == names._super; 213 } 214 case SELECT: { 215 JCFieldAccess select = (JCFieldAccess)tree; 216 Type selectedType = types.erasure(select.selected.type); 217 if (!selectedType.hasTag(TypeTag.CLASS)) 218 return false; 219 Symbol.ClassSymbol currentClassSym = (Symbol.ClassSymbol)((Type.ClassType)types.erasure(currentClass)).tsym; 220 Symbol.ClassSymbol selectedClassSym = (Symbol.ClassSymbol)((Type.ClassType)selectedType).tsym; 221 Names names = select.name.table.names; 222 return currentClassSym.isSubClass(selectedClassSym, types) && 223 (select.name == names._super || 224 (select.name == names._this && 225 (currentClassSym == selectedClassSym || 226 !currentClassSym.isEnclosedBy(selectedClassSym)))); 227 } 228 default: 229 return false; 230 } 231 } 232 233 /** Is this a call to super? 234 */ 235 public static boolean isSuperCall(JCTree tree) { 236 Name name = calledMethodName(tree); 237 if (name != null) { 238 Names names = name.table.names; 239 return name==names._super; 240 } else { 241 return false; 242 } 243 } 244 245 public static List<JCVariableDecl> recordFields(JCClassDecl tree) { 246 return tree.defs.stream() 247 .filter(t -> t.hasTag(VARDEF)) 248 .map(t -> (JCVariableDecl)t) 249 .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD) 250 .collect(List.collector()); 251 } 252 253 public static List<Type> recordFieldTypes(JCClassDecl tree) { 254 return recordFields(tree).stream() 255 .map(vd -> vd.type) 256 .collect(List.collector()); 257 } 258 259 /** Is the given method a constructor containing a super() or this() call? 260 */ 261 public static boolean hasAnyConstructorCall(JCMethodDecl tree) { 262 return hasConstructorCall(tree, null); 263 } 264 265 /** Is the given method a constructor containing a super() and/or this() call? 266 * The "target" is either names._this, names._super, or null for either/both. 267 */ 268 public static boolean hasConstructorCall(JCMethodDecl tree, Name target) { 269 JCMethodInvocation app = findConstructorCall(tree); 270 return app != null && (target == null || target == name(app.meth)); 271 } 272 273 /** Find the first super() or init() call in the given constructor. 274 */ 275 public static JCMethodInvocation findConstructorCall(JCMethodDecl md) { 276 if (!TreeInfo.isConstructor(md) || md.body == null) 277 return null; 278 return new ConstructorCallFinder(md.name.table.names).find(md).head; 279 } 280 281 /** Finds all calls to this() and/or super() in a given constructor. 282 * We can't assume they will be "top level" statements, because 283 * some synthetic calls to super() are added inside { } blocks. 284 * So we must recurse through the method's entire syntax tree. 285 */ 286 private static class ConstructorCallFinder extends TreeScanner { 287 288 final ListBuffer<JCMethodInvocation> calls = new ListBuffer<>(); 289 final Names names; 290 291 ConstructorCallFinder(Names names) { 292 this.names = names; 293 } 294 295 List<JCMethodInvocation> find(JCMethodDecl meth) { 296 scan(meth); 297 return calls.toList(); 298 } 299 300 @Override 301 public void visitApply(JCMethodInvocation invoke) { 302 Name name = TreeInfo.name(invoke.meth); 303 if ((name == names._this || name == names._super)) 304 calls.append(invoke); 305 super.visitApply(invoke); 306 } 307 308 @Override 309 public void visitClassDef(JCClassDecl tree) { 310 // don't descend any further 311 } 312 313 @Override 314 public void visitLambda(JCLambda tree) { 315 // don't descend any further 316 } 317 } 318 319 /** 320 * Is the given method invocation an invocation of this(...) or super(...)? 321 */ 322 public static boolean isConstructorCall(JCMethodInvocation invoke) { 323 Name name = TreeInfo.name(invoke.meth); 324 Names names = name.table.names; 325 326 return (name == names._this || name == names._super); 327 } 328 329 /** Finds super() invocations and translates them using the given mapping. 330 */ 331 public static void mapSuperCalls(JCBlock block, Function<? super JCExpressionStatement, ? extends JCStatement> mapper) { 332 block.stats = block.stats.map(new TreeInfo.SuperCallTranslator(mapper)::translate); 333 } 334 335 /** Finds all super() invocations and translates them somehow. 336 */ 337 private static class SuperCallTranslator extends TreeTranslator { 338 339 final Function<? super JCExpressionStatement, ? extends JCStatement> translator; 340 341 /** Constructor. 342 * 343 * @param translator translates super() invocations, returning replacement statement or null for no change 344 */ 345 SuperCallTranslator(Function<? super JCExpressionStatement, ? extends JCStatement> translator) { 346 this.translator = translator; 347 } 348 349 // Because it returns void, anywhere super() can legally appear must be a location where a JCStatement 350 // could also appear, so it's OK that we are replacing a JCExpressionStatement with a JCStatement here. 351 @Override 352 public void visitExec(JCExpressionStatement stat) { 353 if (!TreeInfo.isSuperCall(stat) || (result = this.translator.apply(stat)) == null) 354 super.visitExec(stat); 355 } 356 357 @Override 358 public void visitClassDef(JCClassDecl tree) { 359 // don't descend any further 360 result = tree; 361 } 362 363 @Override 364 public void visitLambda(JCLambda tree) { 365 // don't descend any further 366 result = tree; 367 } 368 } 369 370 /** Return true if a tree represents a diamond new expr. */ 371 public static boolean isDiamond(JCTree tree) { 372 switch(tree.getTag()) { 373 case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty(); 374 case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz); 375 case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType); 376 default: return false; 377 } 378 } 379 380 public static boolean isEnumInit(JCTree tree) { 381 switch (tree.getTag()) { 382 case VARDEF: 383 return (((JCVariableDecl)tree).mods.flags & ENUM) != 0; 384 default: 385 return false; 386 } 387 } 388 389 /** set 'polyKind' on given tree */ 390 public static void setPolyKind(JCTree tree, PolyKind pkind) { 391 switch (tree.getTag()) { 392 case APPLY: 393 ((JCMethodInvocation)tree).polyKind = pkind; 394 break; 395 case NEWCLASS: 396 ((JCNewClass)tree).polyKind = pkind; 397 break; 398 case REFERENCE: 399 ((JCMemberReference)tree).refPolyKind = pkind; 400 break; 401 default: 402 throw new AssertionError("Unexpected tree: " + tree); 403 } 404 } 405 406 /** set 'varargsElement' on given tree */ 407 public static void setVarargsElement(JCTree tree, Type varargsElement) { 408 switch (tree.getTag()) { 409 case APPLY: 410 ((JCMethodInvocation)tree).varargsElement = varargsElement; 411 break; 412 case NEWCLASS: 413 ((JCNewClass)tree).varargsElement = varargsElement; 414 break; 415 case REFERENCE: 416 ((JCMemberReference)tree).varargsElement = varargsElement; 417 break; 418 default: 419 throw new AssertionError("Unexpected tree: " + tree); 420 } 421 } 422 423 /** Return true if the tree corresponds to an expression statement */ 424 public static boolean isExpressionStatement(JCExpression tree) { 425 switch(tree.getTag()) { 426 case PREINC: case PREDEC: 427 case POSTINC: case POSTDEC: 428 case ASSIGN: 429 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: 430 case SL_ASG: case SR_ASG: case USR_ASG: 431 case PLUS_ASG: case MINUS_ASG: 432 case MUL_ASG: case DIV_ASG: case MOD_ASG: 433 case APPLY: case NEWCLASS: 434 case ERRONEOUS: 435 return true; 436 default: 437 return false; 438 } 439 } 440 441 /** Return true if the tree corresponds to a statement */ 442 public static boolean isStatement(JCTree tree) { 443 return (tree instanceof JCStatement) && 444 !tree.hasTag(CLASSDEF) && 445 !tree.hasTag(Tag.BLOCK) && 446 !tree.hasTag(METHODDEF); 447 } 448 449 /** 450 * Return true if the AST corresponds to a static select of the kind A.B 451 */ 452 public static boolean isStaticSelector(JCTree base, Names names) { 453 if (base == null) 454 return false; 455 switch (base.getTag()) { 456 case IDENT: 457 JCIdent id = (JCIdent)base; 458 return id.name != names._this && 459 id.name != names._super && 460 isStaticSym(base); 461 case SELECT: 462 return isStaticSym(base) && 463 isStaticSelector(((JCFieldAccess)base).selected, names); 464 case TYPEAPPLY: 465 case TYPEARRAY: 466 return true; 467 case ANNOTATED_TYPE: 468 return isStaticSelector(((JCAnnotatedType)base).underlyingType, names); 469 default: 470 return false; 471 } 472 } 473 //where 474 private static boolean isStaticSym(JCTree tree) { 475 Symbol sym = symbol(tree); 476 return (sym.kind == TYP || sym.kind == PCK); 477 } 478 479 /** Return true if a tree represents the null literal. */ 480 public static boolean isNull(JCTree tree) { 481 if (!tree.hasTag(LITERAL)) 482 return false; 483 JCLiteral lit = (JCLiteral) tree; 484 return (lit.typetag == BOT); 485 } 486 487 /** Return true iff this tree is a child of some annotation. */ 488 public static boolean isInAnnotation(Env<?> env, JCTree tree) { 489 TreePath tp = TreePath.getPath(env.toplevel, tree); 490 if (tp != null) { 491 for (Tree t : tp) { 492 if (t.getKind() == Tree.Kind.ANNOTATION) 493 return true; 494 } 495 } 496 return false; 497 } 498 499 public static String getCommentText(Env<?> env, JCTree tree) { 500 DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL)) 501 ? ((JCCompilationUnit) tree).docComments 502 : env.toplevel.docComments; 503 return (docComments == null) ? null : docComments.getCommentText(tree); 504 } 505 506 /** The position of the first statement in a block, or the position of 507 * the block itself if it is empty. 508 */ 509 public static int firstStatPos(JCTree tree) { 510 if (tree.hasTag(BLOCK) && ((JCBlock) tree).stats.nonEmpty()) 511 return ((JCBlock) tree).stats.head.pos; 512 else 513 return tree.pos; 514 } 515 516 /** The end position of given tree, if it is a block with 517 * defined endpos. 518 */ 519 public static int endPos(JCTree tree) { 520 if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS) 521 return ((JCBlock) tree).endpos; 522 else if (tree.hasTag(SYNCHRONIZED)) 523 return endPos(((JCSynchronized) tree).body); 524 else if (tree.hasTag(TRY)) { 525 JCTry t = (JCTry) tree; 526 return endPos((t.finalizer != null) ? t.finalizer 527 : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body)); 528 } else if (tree.hasTag(SWITCH) && 529 ((JCSwitch) tree).endpos != Position.NOPOS) { 530 return ((JCSwitch) tree).endpos; 531 } else if (tree.hasTag(SWITCH_EXPRESSION) && 532 ((JCSwitchExpression) tree).endpos != Position.NOPOS) { 533 return ((JCSwitchExpression) tree).endpos; 534 } else 535 return tree.pos; 536 } 537 538 539 /** Get the start position for a tree node. The start position is 540 * defined to be the position of the first character of the first 541 * token of the node's source text. 542 * @param tree The tree node 543 */ 544 public static int getStartPos(JCTree tree) { 545 if (tree == null) 546 return Position.NOPOS; 547 548 switch(tree.getTag()) { 549 case MODULEDEF: { 550 JCModuleDecl md = (JCModuleDecl)tree; 551 return md.mods.annotations.isEmpty() ? md.pos : 552 md.mods.annotations.head.pos; 553 } 554 case PACKAGEDEF: { 555 JCPackageDecl pd = (JCPackageDecl)tree; 556 return pd.annotations.isEmpty() ? pd.pos : 557 pd.annotations.head.pos; 558 } 559 case APPLY: 560 return getStartPos(((JCMethodInvocation) tree).meth); 561 case ASSIGN: 562 return getStartPos(((JCAssign) tree).lhs); 563 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: 564 case SL_ASG: case SR_ASG: case USR_ASG: 565 case PLUS_ASG: case MINUS_ASG: case MUL_ASG: 566 case DIV_ASG: case MOD_ASG: 567 case OR: case AND: case BITOR: 568 case BITXOR: case BITAND: case EQ: 569 case NE: case LT: case GT: 570 case LE: case GE: case SL: 571 case SR: case USR: case PLUS: 572 case MINUS: case MUL: case DIV: 573 case MOD: 574 case POSTINC: 575 case POSTDEC: 576 return getStartPos(((JCOperatorExpression) tree).getOperand(LEFT)); 577 case CLASSDEF: { 578 JCClassDecl node = (JCClassDecl)tree; 579 if (node.mods.pos != Position.NOPOS) 580 return node.mods.pos; 581 break; 582 } 583 case CONDEXPR: 584 return getStartPos(((JCConditional) tree).cond); 585 case EXEC: 586 return getStartPos(((JCExpressionStatement) tree).expr); 587 case INDEXED: 588 return getStartPos(((JCArrayAccess) tree).indexed); 589 case METHODDEF: { 590 JCMethodDecl node = (JCMethodDecl)tree; 591 if (node.mods.pos != Position.NOPOS) 592 return node.mods.pos; 593 if (node.typarams.nonEmpty()) // List.nil() used for no typarams 594 return getStartPos(node.typarams.head); 595 return node.restype == null ? node.pos : getStartPos(node.restype); 596 } 597 case SELECT: 598 return getStartPos(((JCFieldAccess) tree).selected); 599 case TYPEAPPLY: 600 return getStartPos(((JCTypeApply) tree).clazz); 601 case TYPEARRAY: 602 return getStartPos(((JCArrayTypeTree) tree).elemtype); 603 case TYPETEST: 604 return getStartPos(((JCInstanceOf) tree).expr); 605 case ANNOTATED_TYPE: { 606 JCAnnotatedType node = (JCAnnotatedType) tree; 607 if (node.annotations.nonEmpty()) { 608 if (node.underlyingType.hasTag(TYPEARRAY) || 609 node.underlyingType.hasTag(SELECT)) { 610 return getStartPos(node.underlyingType); 611 } else { 612 return getStartPos(node.annotations.head); 613 } 614 } else { 615 return getStartPos(node.underlyingType); 616 } 617 } 618 case NEWCLASS: { 619 JCNewClass node = (JCNewClass)tree; 620 if (node.encl != null) 621 return getStartPos(node.encl); 622 break; 623 } 624 case VARDEF: { 625 JCVariableDecl node = (JCVariableDecl)tree; 626 if (node.startPos != Position.NOPOS) { 627 return node.startPos; 628 } else if (node.mods.pos != Position.NOPOS) { 629 return node.mods.pos; 630 } else if (node.vartype == null || node.vartype.pos == Position.NOPOS) { 631 //if there's no type (partially typed lambda parameter) 632 //simply return node position 633 return node.pos; 634 } else { 635 return getStartPos(node.vartype); 636 } 637 } 638 case BINDINGPATTERN: { 639 JCBindingPattern node = (JCBindingPattern)tree; 640 return getStartPos(node.var); 641 } 642 case ERRONEOUS: { 643 JCErroneous node = (JCErroneous)tree; 644 if (node.errs != null && node.errs.nonEmpty()) { 645 int pos = getStartPos(node.errs.head); 646 if (pos != Position.NOPOS) { 647 return pos; 648 } 649 } 650 break; 651 } 652 } 653 return tree.pos; 654 } 655 656 /** The end position of given tree, given a table of end positions generated by the parser 657 */ 658 public static int getEndPos(JCTree tree, EndPosTable endPosTable) { 659 if (tree == null) 660 return Position.NOPOS; 661 662 if (endPosTable == null) { 663 // fall back on limited info in the tree 664 return endPos(tree); 665 } 666 667 int mapPos = endPosTable.getEndPos(tree); 668 if (mapPos != Position.NOPOS) 669 return mapPos; 670 671 switch(tree.getTag()) { 672 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: 673 case SL_ASG: case SR_ASG: case USR_ASG: 674 case PLUS_ASG: case MINUS_ASG: case MUL_ASG: 675 case DIV_ASG: case MOD_ASG: 676 case OR: case AND: case BITOR: 677 case BITXOR: case BITAND: case EQ: 678 case NE: case LT: case GT: 679 case LE: case GE: case SL: 680 case SR: case USR: case PLUS: 681 case MINUS: case MUL: case DIV: 682 case MOD: 683 case POS: 684 case NEG: 685 case NOT: 686 case COMPL: 687 case PREINC: 688 case PREDEC: 689 return getEndPos(((JCOperatorExpression) tree).getOperand(RIGHT), endPosTable); 690 case CASE: 691 return getEndPos(((JCCase) tree).stats.last(), endPosTable); 692 case CATCH: 693 return getEndPos(((JCCatch) tree).body, endPosTable); 694 case CONDEXPR: 695 return getEndPos(((JCConditional) tree).falsepart, endPosTable); 696 case FORLOOP: 697 return getEndPos(((JCForLoop) tree).body, endPosTable); 698 case FOREACHLOOP: 699 return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable); 700 case IF: { 701 JCIf node = (JCIf)tree; 702 if (node.elsepart == null) { 703 return getEndPos(node.thenpart, endPosTable); 704 } else { 705 return getEndPos(node.elsepart, endPosTable); 706 } 707 } 708 case LABELLED: 709 return getEndPos(((JCLabeledStatement) tree).body, endPosTable); 710 case MODIFIERS: 711 return getEndPos(((JCModifiers) tree).annotations.last(), endPosTable); 712 case SYNCHRONIZED: 713 return getEndPos(((JCSynchronized) tree).body, endPosTable); 714 case TOPLEVEL: 715 return getEndPos(((JCCompilationUnit) tree).defs.last(), endPosTable); 716 case TRY: { 717 JCTry node = (JCTry)tree; 718 if (node.finalizer != null) { 719 return getEndPos(node.finalizer, endPosTable); 720 } else if (!node.catchers.isEmpty()) { 721 return getEndPos(node.catchers.last(), endPosTable); 722 } else { 723 return getEndPos(node.body, endPosTable); 724 } 725 } 726 case WILDCARD: 727 return getEndPos(((JCWildcard) tree).inner, endPosTable); 728 case TYPECAST: 729 return getEndPos(((JCTypeCast) tree).expr, endPosTable); 730 case TYPETEST: 731 return getEndPos(((JCInstanceOf) tree).pattern, endPosTable); 732 case WHILELOOP: 733 return getEndPos(((JCWhileLoop) tree).body, endPosTable); 734 case ANNOTATED_TYPE: 735 return getEndPos(((JCAnnotatedType) tree).underlyingType, endPosTable); 736 case ERRONEOUS: { 737 JCErroneous node = (JCErroneous)tree; 738 if (node.errs != null && node.errs.nonEmpty()) 739 return getEndPos(node.errs.last(), endPosTable); 740 } 741 } 742 return Position.NOPOS; 743 } 744 745 746 /** A DiagnosticPosition with the preferred position set to the 747 * end position of given tree, if it is a block with 748 * defined endpos. 749 */ 750 public static DiagnosticPosition diagEndPos(final JCTree tree) { 751 final int endPos = TreeInfo.endPos(tree); 752 return new DiagnosticPosition() { 753 public JCTree getTree() { return tree; } 754 public int getStartPosition() { return TreeInfo.getStartPos(tree); } 755 public int getPreferredPosition() { return endPos; } 756 public int getEndPosition(EndPosTable endPosTable) { 757 return TreeInfo.getEndPos(tree, endPosTable); 758 } 759 }; 760 } 761 762 public enum PosKind { 763 START_POS(TreeInfo::getStartPos), 764 FIRST_STAT_POS(TreeInfo::firstStatPos), 765 END_POS(TreeInfo::endPos); 766 767 final ToIntFunction<JCTree> posFunc; 768 769 PosKind(ToIntFunction<JCTree> posFunc) { 770 this.posFunc = posFunc; 771 } 772 773 int toPos(JCTree tree) { 774 return posFunc.applyAsInt(tree); 775 } 776 } 777 778 /** The position of the finalizer of given try/synchronized statement. 779 */ 780 public static int finalizerPos(JCTree tree, PosKind posKind) { 781 if (tree.hasTag(TRY)) { 782 JCTry t = (JCTry) tree; 783 Assert.checkNonNull(t.finalizer); 784 return posKind.toPos(t.finalizer); 785 } else if (tree.hasTag(SYNCHRONIZED)) { 786 return endPos(((JCSynchronized) tree).body); 787 } else { 788 throw new AssertionError(); 789 } 790 } 791 792 /** Find the position for reporting an error about a symbol, where 793 * that symbol is defined somewhere in the given tree. */ 794 public static int positionFor(final Symbol sym, final JCTree tree) { 795 JCTree decl = declarationFor(sym, tree); 796 return ((decl != null) ? decl : tree).pos; 797 } 798 799 /** Find the position for reporting an error about a symbol, where 800 * that symbol is defined somewhere in the given tree. */ 801 public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) { 802 return diagnosticPositionFor(sym, tree, false); 803 } 804 805 public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree, boolean returnNullIfNotFound) { 806 return diagnosticPositionFor(sym, tree, returnNullIfNotFound, null); 807 } 808 809 public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree, boolean returnNullIfNotFound, 810 Predicate<? super JCTree> filter) { 811 class DiagScanner extends DeclScanner { 812 DiagScanner(Symbol sym, Predicate<? super JCTree> filter) { 813 super(sym, filter); 814 } 815 816 public void visitIdent(JCIdent that) { 817 if (!checkMatch(that, that.sym)) 818 super.visitIdent(that); 819 } 820 public void visitSelect(JCFieldAccess that) { 821 if (!checkMatch(that, that.sym)) 822 super.visitSelect(that); 823 } 824 } 825 DiagScanner s = new DiagScanner(sym, filter); 826 tree.accept(s); 827 JCTree decl = s.result; 828 if (decl == null && returnNullIfNotFound) { return null; } 829 return ((decl != null) ? decl : tree).pos(); 830 } 831 832 public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final List<? extends JCTree> trees) { 833 return trees.stream().map(t -> TreeInfo.diagnosticPositionFor(sym, t)).filter(t -> t != null).findFirst().get(); 834 } 835 836 private static class DeclScanner extends TreeScanner { 837 final Symbol sym; 838 final Predicate<? super JCTree> filter; 839 840 DeclScanner(final Symbol sym) { 841 this(sym, null); 842 } 843 DeclScanner(final Symbol sym, Predicate<? super JCTree> filter) { 844 this.sym = sym; 845 this.filter = filter; 846 } 847 848 JCTree result = null; 849 public void scan(JCTree tree) { 850 if (tree!=null && result==null) 851 tree.accept(this); 852 } 853 public void visitTopLevel(JCCompilationUnit that) { 854 if (!checkMatch(that, that.packge)) 855 super.visitTopLevel(that); 856 } 857 public void visitModuleDef(JCModuleDecl that) { 858 checkMatch(that, that.sym); 859 // no need to scan within module declaration 860 } 861 public void visitPackageDef(JCPackageDecl that) { 862 if (!checkMatch(that, that.packge)) 863 super.visitPackageDef(that); 864 } 865 public void visitClassDef(JCClassDecl that) { 866 if (!checkMatch(that, that.sym)) 867 super.visitClassDef(that); 868 } 869 public void visitMethodDef(JCMethodDecl that) { 870 if (!checkMatch(that, that.sym)) 871 super.visitMethodDef(that); 872 } 873 public void visitVarDef(JCVariableDecl that) { 874 if (!checkMatch(that, that.sym)) 875 super.visitVarDef(that); 876 } 877 public void visitTypeParameter(JCTypeParameter that) { 878 if (that.type == null || !checkMatch(that, that.type.tsym)) 879 super.visitTypeParameter(that); 880 } 881 882 protected boolean checkMatch(JCTree that, Symbol thatSym) { 883 if (thatSym == this.sym && (filter == null || filter.test(that))) { 884 result = that; 885 return true; 886 } 887 if (this.sym.getKind() == ElementKind.RECORD_COMPONENT) { 888 if (thatSym != null && thatSym.getKind() == ElementKind.FIELD && (thatSym.flags_field & RECORD) != 0) { 889 RecordComponent rc = thatSym.enclClass().getRecordComponent((VarSymbol)thatSym); 890 return checkMatch(rc.declarationFor(), rc); 891 } 892 } 893 return false; 894 } 895 } 896 897 /** Find the declaration for a symbol, where 898 * that symbol is defined somewhere in the given tree. */ 899 public static JCTree declarationFor(final Symbol sym, final JCTree tree) { 900 DeclScanner s = new DeclScanner(sym); 901 tree.accept(s); 902 return s.result; 903 } 904 905 /** Return the statement referenced by a label. 906 * If the label refers to a loop or switch, return that switch 907 * otherwise return the labelled statement itself 908 */ 909 public static JCTree referencedStatement(JCLabeledStatement tree) { 910 JCTree t = tree; 911 do t = ((JCLabeledStatement) t).body; 912 while (t.hasTag(LABELLED)); 913 switch (t.getTag()) { 914 case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH: 915 return t; 916 default: 917 return tree; 918 } 919 } 920 921 /** Skip parens and return the enclosed expression 922 */ 923 public static JCExpression skipParens(JCExpression tree) { 924 while (tree.hasTag(PARENS)) { 925 tree = ((JCParens) tree).expr; 926 } 927 return tree; 928 } 929 930 /** Skip parens and return the enclosed expression 931 */ 932 public static JCTree skipParens(JCTree tree) { 933 if (tree.hasTag(PARENS)) 934 return skipParens((JCParens)tree); 935 else 936 return tree; 937 } 938 939 /** Return the types of a list of trees. 940 */ 941 public static List<Type> types(List<? extends JCTree> trees) { 942 ListBuffer<Type> ts = new ListBuffer<>(); 943 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 944 ts.append(l.head.type); 945 return ts.toList(); 946 } 947 948 /** If this tree is an identifier or a field or a parameterized type, 949 * return its name, otherwise return null. 950 */ 951 public static Name name(JCTree tree) { 952 switch (tree.getTag()) { 953 case IDENT: 954 return ((JCIdent) tree).name; 955 case SELECT: 956 return ((JCFieldAccess) tree).name; 957 case TYPEAPPLY: 958 return name(((JCTypeApply) tree).clazz); 959 default: 960 return null; 961 } 962 } 963 964 /** If this tree is a qualified identifier, its return fully qualified name, 965 * otherwise return null. 966 */ 967 public static Name fullName(JCTree tree) { 968 tree = skipParens(tree); 969 switch (tree.getTag()) { 970 case IDENT: 971 return ((JCIdent) tree).name; 972 case SELECT: 973 Name sname = fullName(((JCFieldAccess) tree).selected); 974 return sname == null ? null : sname.append('.', name(tree)); 975 default: 976 return null; 977 } 978 } 979 980 public static Symbol symbolFor(JCTree node) { 981 Symbol sym = symbolForImpl(node); 982 983 return sym != null ? sym.baseSymbol() : null; 984 } 985 986 private static Symbol symbolForImpl(JCTree node) { 987 node = skipParens(node); 988 switch (node.getTag()) { 989 case TOPLEVEL: 990 JCCompilationUnit cut = (JCCompilationUnit) node; 991 JCModuleDecl moduleDecl = cut.getModuleDecl(); 992 if (isModuleInfo(cut) && moduleDecl != null) 993 return symbolFor(moduleDecl); 994 return cut.packge; 995 case MODULEDEF: 996 return ((JCModuleDecl) node).sym; 997 case PACKAGEDEF: 998 return ((JCPackageDecl) node).packge; 999 case CLASSDEF: 1000 return ((JCClassDecl) node).sym; 1001 case METHODDEF: 1002 return ((JCMethodDecl) node).sym; 1003 case VARDEF: 1004 return ((JCVariableDecl) node).sym; 1005 case IDENT: 1006 return ((JCIdent) node).sym; 1007 case SELECT: 1008 return ((JCFieldAccess) node).sym; 1009 case REFERENCE: 1010 return ((JCMemberReference) node).sym; 1011 case NEWCLASS: 1012 return ((JCNewClass) node).constructor; 1013 case APPLY: 1014 return symbolFor(((JCMethodInvocation) node).meth); 1015 case TYPEAPPLY: 1016 return symbolFor(((JCTypeApply) node).clazz); 1017 case ANNOTATION: 1018 case TYPE_ANNOTATION: 1019 case TYPEPARAMETER: 1020 if (node.type != null) 1021 return node.type.tsym; 1022 return null; 1023 default: 1024 return null; 1025 } 1026 } 1027 1028 public static boolean isDeclaration(JCTree node) { 1029 node = skipParens(node); 1030 switch (node.getTag()) { 1031 case PACKAGEDEF: 1032 case CLASSDEF: 1033 case METHODDEF: 1034 case VARDEF: 1035 return true; 1036 default: 1037 return false; 1038 } 1039 } 1040 1041 /** If this tree is an identifier or a field, return its symbol, 1042 * otherwise return null. 1043 */ 1044 public static Symbol symbol(JCTree tree) { 1045 tree = skipParens(tree); 1046 switch (tree.getTag()) { 1047 case IDENT: 1048 return ((JCIdent) tree).sym; 1049 case SELECT: 1050 return ((JCFieldAccess) tree).sym; 1051 case TYPEAPPLY: 1052 return symbol(((JCTypeApply) tree).clazz); 1053 case ANNOTATED_TYPE: 1054 return symbol(((JCAnnotatedType) tree).underlyingType); 1055 case REFERENCE: 1056 return ((JCMemberReference) tree).sym; 1057 case CLASSDEF: 1058 return ((JCClassDecl) tree).sym; 1059 default: 1060 return null; 1061 } 1062 } 1063 1064 /** If this tree has a modifiers field, return it otherwise return null 1065 */ 1066 public static JCModifiers getModifiers(JCTree tree) { 1067 tree = skipParens(tree); 1068 switch (tree.getTag()) { 1069 case VARDEF: 1070 return ((JCVariableDecl) tree).mods; 1071 case METHODDEF: 1072 return ((JCMethodDecl) tree).mods; 1073 case CLASSDEF: 1074 return ((JCClassDecl) tree).mods; 1075 case MODULEDEF: 1076 return ((JCModuleDecl) tree).mods; 1077 default: 1078 return null; 1079 } 1080 } 1081 1082 /** Return true if this is a nonstatic selection. */ 1083 public static boolean nonstaticSelect(JCTree tree) { 1084 tree = skipParens(tree); 1085 if (!tree.hasTag(SELECT)) return false; 1086 JCFieldAccess s = (JCFieldAccess) tree; 1087 Symbol e = symbol(s.selected); 1088 return e == null || (e.kind != PCK && e.kind != TYP); 1089 } 1090 1091 /** If this tree is an identifier or a field, set its symbol, otherwise skip. 1092 */ 1093 public static void setSymbol(JCTree tree, Symbol sym) { 1094 tree = skipParens(tree); 1095 switch (tree.getTag()) { 1096 case IDENT: 1097 ((JCIdent) tree).sym = sym; break; 1098 case SELECT: 1099 ((JCFieldAccess) tree).sym = sym; break; 1100 default: 1101 } 1102 } 1103 1104 /** If this tree is a declaration or a block, return its flags field, 1105 * otherwise return 0. 1106 */ 1107 public static long flags(JCTree tree) { 1108 switch (tree.getTag()) { 1109 case VARDEF: 1110 return ((JCVariableDecl) tree).mods.flags; 1111 case METHODDEF: 1112 return ((JCMethodDecl) tree).mods.flags; 1113 case CLASSDEF: 1114 return ((JCClassDecl) tree).mods.flags; 1115 case BLOCK: 1116 return ((JCBlock) tree).flags; 1117 default: 1118 return 0; 1119 } 1120 } 1121 1122 /** Return first (smallest) flag in `flags': 1123 * pre: flags != 0 1124 */ 1125 public static long firstFlag(long flags) { 1126 long flag = 1; 1127 while ((flag & flags) == 0) 1128 flag = flag << 1; 1129 return flag; 1130 } 1131 1132 /** Return flags as a string, separated by " ". 1133 */ 1134 public static String flagNames(long flags) { 1135 return Flags.toString(flags & ExtendedStandardFlags).trim(); 1136 } 1137 1138 /** Operator precedences values. 1139 */ 1140 public static final int 1141 notExpression = -1, // not an expression 1142 noPrec = 0, // no enclosing expression 1143 assignPrec = 1, 1144 assignopPrec = 2, 1145 condPrec = 3, 1146 orPrec = 4, 1147 andPrec = 5, 1148 bitorPrec = 6, 1149 bitxorPrec = 7, 1150 bitandPrec = 8, 1151 eqPrec = 9, 1152 ordPrec = 10, 1153 shiftPrec = 11, 1154 addPrec = 12, 1155 mulPrec = 13, 1156 prefixPrec = 14, 1157 postfixPrec = 15, 1158 precCount = 16; 1159 1160 1161 /** Map operators to their precedence levels. 1162 */ 1163 public static int opPrec(JCTree.Tag op) { 1164 switch(op) { 1165 case POS: 1166 case NEG: 1167 case NOT: 1168 case COMPL: 1169 case PREINC: 1170 case PREDEC: return prefixPrec; 1171 case POSTINC: 1172 case POSTDEC: 1173 case NULLCHK: return postfixPrec; 1174 case ASSIGN: return assignPrec; 1175 case BITOR_ASG: 1176 case BITXOR_ASG: 1177 case BITAND_ASG: 1178 case SL_ASG: 1179 case SR_ASG: 1180 case USR_ASG: 1181 case PLUS_ASG: 1182 case MINUS_ASG: 1183 case MUL_ASG: 1184 case DIV_ASG: 1185 case MOD_ASG: return assignopPrec; 1186 case OR: return orPrec; 1187 case AND: return andPrec; 1188 case EQ: 1189 case NE: return eqPrec; 1190 case LT: 1191 case GT: 1192 case LE: 1193 case GE: return ordPrec; 1194 case BITOR: return bitorPrec; 1195 case BITXOR: return bitxorPrec; 1196 case BITAND: return bitandPrec; 1197 case SL: 1198 case SR: 1199 case USR: return shiftPrec; 1200 case PLUS: 1201 case MINUS: return addPrec; 1202 case MUL: 1203 case DIV: 1204 case MOD: return mulPrec; 1205 case TYPETEST: return ordPrec; 1206 default: throw new AssertionError(); 1207 } 1208 } 1209 1210 static Tree.Kind tagToKind(JCTree.Tag tag) { 1211 switch (tag) { 1212 // Postfix expressions 1213 case POSTINC: // _ ++ 1214 return Tree.Kind.POSTFIX_INCREMENT; 1215 case POSTDEC: // _ -- 1216 return Tree.Kind.POSTFIX_DECREMENT; 1217 1218 // Unary operators 1219 case PREINC: // ++ _ 1220 return Tree.Kind.PREFIX_INCREMENT; 1221 case PREDEC: // -- _ 1222 return Tree.Kind.PREFIX_DECREMENT; 1223 case POS: // + 1224 return Tree.Kind.UNARY_PLUS; 1225 case NEG: // - 1226 return Tree.Kind.UNARY_MINUS; 1227 case COMPL: // ~ 1228 return Tree.Kind.BITWISE_COMPLEMENT; 1229 case NOT: // ! 1230 return Tree.Kind.LOGICAL_COMPLEMENT; 1231 1232 // Binary operators 1233 1234 // Multiplicative operators 1235 case MUL: // * 1236 return Tree.Kind.MULTIPLY; 1237 case DIV: // / 1238 return Tree.Kind.DIVIDE; 1239 case MOD: // % 1240 return Tree.Kind.REMAINDER; 1241 1242 // Additive operators 1243 case PLUS: // + 1244 return Tree.Kind.PLUS; 1245 case MINUS: // - 1246 return Tree.Kind.MINUS; 1247 1248 // Shift operators 1249 case SL: // << 1250 return Tree.Kind.LEFT_SHIFT; 1251 case SR: // >> 1252 return Tree.Kind.RIGHT_SHIFT; 1253 case USR: // >>> 1254 return Tree.Kind.UNSIGNED_RIGHT_SHIFT; 1255 1256 // Relational operators 1257 case LT: // < 1258 return Tree.Kind.LESS_THAN; 1259 case GT: // > 1260 return Tree.Kind.GREATER_THAN; 1261 case LE: // <= 1262 return Tree.Kind.LESS_THAN_EQUAL; 1263 case GE: // >= 1264 return Tree.Kind.GREATER_THAN_EQUAL; 1265 1266 // Equality operators 1267 case EQ: // == 1268 return Tree.Kind.EQUAL_TO; 1269 case NE: // != 1270 return Tree.Kind.NOT_EQUAL_TO; 1271 1272 // Bitwise and logical operators 1273 case BITAND: // & 1274 return Tree.Kind.AND; 1275 case BITXOR: // ^ 1276 return Tree.Kind.XOR; 1277 case BITOR: // | 1278 return Tree.Kind.OR; 1279 1280 // Conditional operators 1281 case AND: // && 1282 return Tree.Kind.CONDITIONAL_AND; 1283 case OR: // || 1284 return Tree.Kind.CONDITIONAL_OR; 1285 1286 // Assignment operators 1287 case MUL_ASG: // *= 1288 return Tree.Kind.MULTIPLY_ASSIGNMENT; 1289 case DIV_ASG: // /= 1290 return Tree.Kind.DIVIDE_ASSIGNMENT; 1291 case MOD_ASG: // %= 1292 return Tree.Kind.REMAINDER_ASSIGNMENT; 1293 case PLUS_ASG: // += 1294 return Tree.Kind.PLUS_ASSIGNMENT; 1295 case MINUS_ASG: // -= 1296 return Tree.Kind.MINUS_ASSIGNMENT; 1297 case SL_ASG: // <<= 1298 return Tree.Kind.LEFT_SHIFT_ASSIGNMENT; 1299 case SR_ASG: // >>= 1300 return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT; 1301 case USR_ASG: // >>>= 1302 return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT; 1303 case BITAND_ASG: // &= 1304 return Tree.Kind.AND_ASSIGNMENT; 1305 case BITXOR_ASG: // ^= 1306 return Tree.Kind.XOR_ASSIGNMENT; 1307 case BITOR_ASG: // |= 1308 return Tree.Kind.OR_ASSIGNMENT; 1309 1310 // Null check (implementation detail), for example, __.getClass() 1311 case NULLCHK: 1312 return Tree.Kind.OTHER; 1313 1314 case ANNOTATION: 1315 return Tree.Kind.ANNOTATION; 1316 case TYPE_ANNOTATION: 1317 return Tree.Kind.TYPE_ANNOTATION; 1318 1319 case EXPORTS: 1320 return Tree.Kind.EXPORTS; 1321 case OPENS: 1322 return Tree.Kind.OPENS; 1323 1324 default: 1325 return null; 1326 } 1327 } 1328 1329 /** 1330 * Returns the underlying type of the tree if it is an annotated type, 1331 * or the tree itself otherwise. 1332 */ 1333 public static JCExpression typeIn(JCExpression tree) { 1334 switch (tree.getTag()) { 1335 case ANNOTATED_TYPE: 1336 return ((JCAnnotatedType)tree).underlyingType; 1337 case IDENT: /* simple names */ 1338 case TYPEIDENT: /* primitive name */ 1339 case SELECT: /* qualified name */ 1340 case TYPEARRAY: /* array types */ 1341 case WILDCARD: /* wild cards */ 1342 case TYPEPARAMETER: /* type parameters */ 1343 case TYPEAPPLY: /* parameterized types */ 1344 case ERRONEOUS: /* error tree TODO: needed for BadCast JSR308 test case. Better way? */ 1345 return tree; 1346 default: 1347 throw new AssertionError("Unexpected type tree: " + tree); 1348 } 1349 } 1350 1351 /* Return the inner-most type of a type tree. 1352 * For an array that contains an annotated type, return that annotated type. 1353 * TODO: currently only used by Pretty. Describe behavior better. 1354 */ 1355 public static JCTree innermostType(JCTree type, boolean skipAnnos) { 1356 JCTree lastAnnotatedType = null; 1357 JCTree cur = type; 1358 loop: while (true) { 1359 switch (cur.getTag()) { 1360 case TYPEARRAY: 1361 lastAnnotatedType = null; 1362 cur = ((JCArrayTypeTree)cur).elemtype; 1363 break; 1364 case WILDCARD: 1365 lastAnnotatedType = null; 1366 cur = ((JCWildcard)cur).inner; 1367 break; 1368 case ANNOTATED_TYPE: 1369 lastAnnotatedType = cur; 1370 cur = ((JCAnnotatedType)cur).underlyingType; 1371 break; 1372 default: 1373 break loop; 1374 } 1375 } 1376 if (!skipAnnos && lastAnnotatedType!=null) { 1377 return lastAnnotatedType; 1378 } else { 1379 return cur; 1380 } 1381 } 1382 1383 private static class TypeAnnotationFinder extends TreeScanner { 1384 public boolean foundTypeAnno = false; 1385 1386 @Override 1387 public void scan(JCTree tree) { 1388 if (foundTypeAnno || tree == null) 1389 return; 1390 super.scan(tree); 1391 } 1392 1393 public void visitAnnotation(JCAnnotation tree) { 1394 foundTypeAnno = foundTypeAnno || tree.hasTag(TYPE_ANNOTATION); 1395 } 1396 } 1397 1398 public static boolean containsTypeAnnotation(JCTree e) { 1399 TypeAnnotationFinder finder = new TypeAnnotationFinder(); 1400 finder.scan(e); 1401 return finder.foundTypeAnno; 1402 } 1403 1404 public static boolean isModuleInfo(JCCompilationUnit tree) { 1405 return tree.sourcefile.isNameCompatible("module-info", JavaFileObject.Kind.SOURCE) 1406 && tree.getModuleDecl() != null; 1407 } 1408 1409 public static boolean isPackageInfo(JCCompilationUnit tree) { 1410 return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); 1411 } 1412 1413 public static boolean isErrorEnumSwitch(JCExpression selector, List<JCCase> cases) { 1414 return selector.type.tsym.kind == Kinds.Kind.ERR && 1415 cases.stream().flatMap(c -> c.labels.stream()) 1416 .filter(l -> l.hasTag(CONSTANTCASELABEL)) 1417 .map(l -> ((JCConstantCaseLabel) l).expr) 1418 .allMatch(p -> p.hasTag(IDENT)); 1419 } 1420 1421 public static Type primaryPatternType(JCTree pat) { 1422 return switch (pat.getTag()) { 1423 case BINDINGPATTERN -> pat.type; 1424 case RECORDPATTERN -> ((JCRecordPattern) pat).type; 1425 case ANYPATTERN -> ((JCAnyPattern) pat).type; 1426 default -> throw new AssertionError(); 1427 }; 1428 } 1429 1430 public static JCTree primaryPatternTypeTree(JCTree pat) { 1431 return switch (pat.getTag()) { 1432 case BINDINGPATTERN -> ((JCBindingPattern) pat).var.vartype; 1433 case RECORDPATTERN -> ((JCRecordPattern) pat).deconstructor; 1434 default -> throw new AssertionError(); 1435 }; 1436 } 1437 1438 public static boolean expectedExhaustive(JCSwitch tree) { 1439 return tree.patternSwitch || 1440 tree.cases.stream() 1441 .flatMap(c -> c.labels.stream()) 1442 .anyMatch(l -> TreeInfo.isNullCaseLabel(l)); 1443 } 1444 1445 public static boolean unguardedCase(JCCase cse) { 1446 JCExpression guard = cse.guard; 1447 if (guard == null) { 1448 return true; 1449 } 1450 return isBooleanWithValue(guard, 1); 1451 } 1452 1453 public static boolean isBooleanWithValue(JCExpression guard, int value) { 1454 var constValue = guard.type.constValue(); 1455 return constValue != null && 1456 guard.type.hasTag(BOOLEAN) && 1457 ((int) constValue) == value; 1458 } 1459 1460 public static boolean isNullCaseLabel(JCCaseLabel label) { 1461 return label.hasTag(CONSTANTCASELABEL) && 1462 TreeInfo.isNull(((JCConstantCaseLabel) label).expr); 1463 } 1464 }