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