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