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