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