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