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