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