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