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