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