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