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