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