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