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