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