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