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