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