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