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