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