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