TreeInfo.java revision 2758:3c1b5fcf6fad
1/*
2 * Copyright (c) 1999, 2014, 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
26package com.sun.tools.javac.tree;
27
28
29
30import com.sun.source.tree.Tree;
31import com.sun.source.util.TreePath;
32import com.sun.tools.javac.code.*;
33import com.sun.tools.javac.comp.AttrContext;
34import com.sun.tools.javac.comp.Env;
35import com.sun.tools.javac.tree.JCTree.*;
36import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
37import com.sun.tools.javac.util.*;
38import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
39import static com.sun.tools.javac.code.Flags.*;
40import static com.sun.tools.javac.code.Kinds.Kind.*;
41import static com.sun.tools.javac.code.TypeTag.BOT;
42import static com.sun.tools.javac.tree.JCTree.Tag.*;
43import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK;
44import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
45
46/** Utility class containing inspector methods for trees.
47 *
48 *  <p><b>This is NOT part of any supported API.
49 *  If you write code that depends on this, you do so at your own risk.
50 *  This code and its internal interfaces are subject to change or
51 *  deletion without notice.</b>
52 */
53public class TreeInfo {
54    protected static final Context.Key<TreeInfo> treeInfoKey = new Context.Key<>();
55
56    public static TreeInfo instance(Context context) {
57        TreeInfo instance = context.get(treeInfoKey);
58        if (instance == null)
59            instance = new TreeInfo(context);
60        return instance;
61    }
62
63    /** The names of all operators.
64     */
65    private Name[] opname = new Name[Tag.getNumberOfOperators()];
66
67    private void setOpname(Tag tag, String name, Names names) {
68         setOpname(tag, names.fromString(name));
69     }
70     private void setOpname(Tag tag, Name name) {
71         opname[tag.operatorIndex()] = name;
72     }
73
74    private TreeInfo(Context context) {
75        context.put(treeInfoKey, this);
76
77        Names names = Names.instance(context);
78        /*  Internally we use +++, --- for unary +, - to reduce +, - operators
79         *  overloading
80         */
81        setOpname(POS, "+++", names);
82        setOpname(NEG, "---", names);
83        setOpname(NOT, "!", names);
84        setOpname(COMPL, "~", names);
85        setOpname(PREINC, "++", names);
86        setOpname(PREDEC, "--", names);
87        setOpname(POSTINC, "++", names);
88        setOpname(POSTDEC, "--", names);
89        setOpname(NULLCHK, "<*nullchk*>", names);
90        setOpname(OR, "||", names);
91        setOpname(AND, "&&", names);
92        setOpname(EQ, "==", names);
93        setOpname(NE, "!=", names);
94        setOpname(LT, "<", names);
95        setOpname(GT, ">", names);
96        setOpname(LE, "<=", names);
97        setOpname(GE, ">=", names);
98        setOpname(BITOR, "|", names);
99        setOpname(BITXOR, "^", names);
100        setOpname(BITAND, "&", names);
101        setOpname(SL, "<<", names);
102        setOpname(SR, ">>", names);
103        setOpname(USR, ">>>", names);
104        setOpname(PLUS, "+", names);
105        setOpname(MINUS, names.hyphen);
106        setOpname(MUL, names.asterisk);
107        setOpname(DIV, names.slash);
108        setOpname(MOD, "%", names);
109    }
110
111    public static List<JCExpression> args(JCTree t) {
112        switch (t.getTag()) {
113            case APPLY:
114                return ((JCMethodInvocation)t).args;
115            case NEWCLASS:
116                return ((JCNewClass)t).args;
117            default:
118                return null;
119        }
120    }
121
122    /** Return name of operator with given tree tag.
123     */
124    public Name operatorName(JCTree.Tag tag) {
125        return opname[tag.operatorIndex()];
126    }
127
128    /** Is tree a constructor declaration?
129     */
130    public static boolean isConstructor(JCTree tree) {
131        if (tree.hasTag(METHODDEF)) {
132            Name name = ((JCMethodDecl) tree).name;
133            return name == name.table.names.init;
134        } else {
135            return false;
136        }
137    }
138
139    public static boolean isReceiverParam(JCTree tree) {
140        if (tree.hasTag(VARDEF)) {
141            return ((JCVariableDecl)tree).nameexpr != null;
142        } else {
143            return false;
144        }
145    }
146
147    /** Is there a constructor declaration in the given list of trees?
148     */
149    public static boolean hasConstructors(List<JCTree> trees) {
150        for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
151            if (isConstructor(l.head)) return true;
152        return false;
153    }
154
155    public static boolean isMultiCatch(JCCatch catchClause) {
156        return catchClause.param.vartype.hasTag(TYPEUNION);
157    }
158
159    /** Is statement an initializer for a synthetic field?
160     */
161    public static boolean isSyntheticInit(JCTree stat) {
162        if (stat.hasTag(EXEC)) {
163            JCExpressionStatement exec = (JCExpressionStatement)stat;
164            if (exec.expr.hasTag(ASSIGN)) {
165                JCAssign assign = (JCAssign)exec.expr;
166                if (assign.lhs.hasTag(SELECT)) {
167                    JCFieldAccess select = (JCFieldAccess)assign.lhs;
168                    if (select.sym != null &&
169                        (select.sym.flags() & SYNTHETIC) != 0) {
170                        Name selected = name(select.selected);
171                        if (selected != null && selected == selected.table.names._this)
172                            return true;
173                    }
174                }
175            }
176        }
177        return false;
178    }
179
180    /** If the expression is a method call, return the method name, null
181     *  otherwise. */
182    public static Name calledMethodName(JCTree tree) {
183        if (tree.hasTag(EXEC)) {
184            JCExpressionStatement exec = (JCExpressionStatement)tree;
185            if (exec.expr.hasTag(APPLY)) {
186                Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
187                return mname;
188            }
189        }
190        return null;
191    }
192
193    /** Is this a call to this or super?
194     */
195    public static boolean isSelfCall(JCTree tree) {
196        Name name = calledMethodName(tree);
197        if (name != null) {
198            Names names = name.table.names;
199            return name==names._this || name==names._super;
200        } else {
201            return false;
202        }
203    }
204
205    /** Is this a call to super?
206     */
207    public static boolean isSuperCall(JCTree tree) {
208        Name name = calledMethodName(tree);
209        if (name != null) {
210            Names names = name.table.names;
211            return name==names._super;
212        } else {
213            return false;
214        }
215    }
216
217    /** Is this a constructor whose first (non-synthetic) statement is not
218     *  of the form this(...)?
219     */
220    public static boolean isInitialConstructor(JCTree tree) {
221        JCMethodInvocation app = firstConstructorCall(tree);
222        if (app == null) return false;
223        Name meth = name(app.meth);
224        return meth == null || meth != meth.table.names._this;
225    }
226
227    /** Return the first call in a constructor definition. */
228    public static JCMethodInvocation firstConstructorCall(JCTree tree) {
229        if (!tree.hasTag(METHODDEF)) return null;
230        JCMethodDecl md = (JCMethodDecl) tree;
231        Names names = md.name.table.names;
232        if (md.name != names.init) return null;
233        if (md.body == null) return null;
234        List<JCStatement> stats = md.body.stats;
235        // Synthetic initializations can appear before the super call.
236        while (stats.nonEmpty() && isSyntheticInit(stats.head))
237            stats = stats.tail;
238        if (stats.isEmpty()) return null;
239        if (!stats.head.hasTag(EXEC)) return null;
240        JCExpressionStatement exec = (JCExpressionStatement) stats.head;
241        if (!exec.expr.hasTag(APPLY)) return null;
242        return (JCMethodInvocation)exec.expr;
243    }
244
245    /** Return true if a tree represents a diamond new expr. */
246    public static boolean isDiamond(JCTree tree) {
247        switch(tree.getTag()) {
248            case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
249            case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
250            case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
251            default: return false;
252        }
253    }
254
255    public static boolean isEnumInit(JCTree tree) {
256        switch (tree.getTag()) {
257            case VARDEF:
258                return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
259            default:
260                return false;
261        }
262    }
263
264    /** set 'polyKind' on given tree */
265    public static void setPolyKind(JCTree tree, PolyKind pkind) {
266        switch (tree.getTag()) {
267            case APPLY:
268                ((JCMethodInvocation)tree).polyKind = pkind;
269                break;
270            case NEWCLASS:
271                ((JCNewClass)tree).polyKind = pkind;
272                break;
273            case REFERENCE:
274                ((JCMemberReference)tree).refPolyKind = pkind;
275                break;
276            default:
277                throw new AssertionError("Unexpected tree: " + tree);
278        }
279    }
280
281    /** set 'varargsElement' on given tree */
282    public static void setVarargsElement(JCTree tree, Type varargsElement) {
283        switch (tree.getTag()) {
284            case APPLY:
285                ((JCMethodInvocation)tree).varargsElement = varargsElement;
286                break;
287            case NEWCLASS:
288                ((JCNewClass)tree).varargsElement = varargsElement;
289                break;
290            case REFERENCE:
291                ((JCMemberReference)tree).varargsElement = varargsElement;
292                break;
293            default:
294                throw new AssertionError("Unexpected tree: " + tree);
295        }
296    }
297
298    /** Return true if the tree corresponds to an expression statement */
299    public static boolean isExpressionStatement(JCExpression tree) {
300        switch(tree.getTag()) {
301            case PREINC: case PREDEC:
302            case POSTINC: case POSTDEC:
303            case ASSIGN:
304            case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
305            case SL_ASG: case SR_ASG: case USR_ASG:
306            case PLUS_ASG: case MINUS_ASG:
307            case MUL_ASG: case DIV_ASG: case MOD_ASG:
308            case APPLY: case NEWCLASS:
309            case ERRONEOUS:
310                return true;
311            default:
312                return false;
313        }
314    }
315
316    /** Return true if the tree corresponds to a statement */
317    public static boolean isStatement(JCTree tree) {
318        return (tree instanceof JCStatement) &&
319                !tree.hasTag(CLASSDEF) &&
320                !tree.hasTag(Tag.BLOCK) &&
321                !tree.hasTag(METHODDEF);
322    }
323
324    /**
325     * Return true if the AST corresponds to a static select of the kind A.B
326     */
327    public static boolean isStaticSelector(JCTree base, Names names) {
328        if (base == null)
329            return false;
330        switch (base.getTag()) {
331            case IDENT:
332                JCIdent id = (JCIdent)base;
333                return id.name != names._this &&
334                        id.name != names._super &&
335                        isStaticSym(base);
336            case SELECT:
337                return isStaticSym(base) &&
338                    isStaticSelector(((JCFieldAccess)base).selected, names);
339            case TYPEAPPLY:
340            case TYPEARRAY:
341                return true;
342            case ANNOTATED_TYPE:
343                return isStaticSelector(((JCAnnotatedType)base).underlyingType, names);
344            default:
345                return false;
346        }
347    }
348    //where
349        private static boolean isStaticSym(JCTree tree) {
350            Symbol sym = symbol(tree);
351            return (sym.kind == TYP || sym.kind == PCK);
352        }
353
354    /** Return true if a tree represents the null literal. */
355    public static boolean isNull(JCTree tree) {
356        if (!tree.hasTag(LITERAL))
357            return false;
358        JCLiteral lit = (JCLiteral) tree;
359        return (lit.typetag == BOT);
360    }
361
362    /** Return true iff this tree is a child of some annotation. */
363    public static boolean isInAnnotation(Env<?> env, JCTree tree) {
364        TreePath tp = TreePath.getPath(env.toplevel, tree);
365        if (tp != null) {
366            for (Tree t : tp) {
367                if (t.getKind() == Tree.Kind.ANNOTATION)
368                    return true;
369            }
370        }
371        return false;
372    }
373
374    public static String getCommentText(Env<?> env, JCTree tree) {
375        DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
376                ? ((JCCompilationUnit) tree).docComments
377                : env.toplevel.docComments;
378        return (docComments == null) ? null : docComments.getCommentText(tree);
379    }
380
381    public static DCTree.DCDocComment getCommentTree(Env<?> env, JCTree tree) {
382        DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
383                ? ((JCCompilationUnit) tree).docComments
384                : env.toplevel.docComments;
385        return (docComments == null) ? null : docComments.getCommentTree(tree);
386    }
387
388    /** The position of the first statement in a block, or the position of
389     *  the block itself if it is empty.
390     */
391    public static int firstStatPos(JCTree tree) {
392        if (tree.hasTag(BLOCK) && ((JCBlock) tree).stats.nonEmpty())
393            return ((JCBlock) tree).stats.head.pos;
394        else
395            return tree.pos;
396    }
397
398    /** The end position of given tree, if it is a block with
399     *  defined endpos.
400     */
401    public static int endPos(JCTree tree) {
402        if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS)
403            return ((JCBlock) tree).endpos;
404        else if (tree.hasTag(SYNCHRONIZED))
405            return endPos(((JCSynchronized) tree).body);
406        else if (tree.hasTag(TRY)) {
407            JCTry t = (JCTry) tree;
408            return endPos((t.finalizer != null) ? t.finalizer
409                          : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body));
410        } else
411            return tree.pos;
412    }
413
414
415    /** Get the start position for a tree node.  The start position is
416     * defined to be the position of the first character of the first
417     * token of the node's source text.
418     * @param tree  The tree node
419     */
420    public static int getStartPos(JCTree tree) {
421        if (tree == null)
422            return Position.NOPOS;
423
424        switch(tree.getTag()) {
425            case PACKAGEDEF: {
426                JCPackageDecl pd = (JCPackageDecl)tree;
427                return pd.annotations.isEmpty() ? pd.pos :
428                       pd.annotations.head.pos;
429            }
430            case APPLY:
431                return getStartPos(((JCMethodInvocation) tree).meth);
432            case ASSIGN:
433                return getStartPos(((JCAssign) tree).lhs);
434            case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
435            case SL_ASG: case SR_ASG: case USR_ASG:
436            case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
437            case DIV_ASG: case MOD_ASG:
438                return getStartPos(((JCAssignOp) tree).lhs);
439            case OR: case AND: case BITOR:
440            case BITXOR: case BITAND: case EQ:
441            case NE: case LT: case GT:
442            case LE: case GE: case SL:
443            case SR: case USR: case PLUS:
444            case MINUS: case MUL: case DIV:
445            case MOD:
446                return getStartPos(((JCBinary) tree).lhs);
447            case CLASSDEF: {
448                JCClassDecl node = (JCClassDecl)tree;
449                if (node.mods.pos != Position.NOPOS)
450                    return node.mods.pos;
451                break;
452            }
453            case CONDEXPR:
454                return getStartPos(((JCConditional) tree).cond);
455            case EXEC:
456                return getStartPos(((JCExpressionStatement) tree).expr);
457            case INDEXED:
458                return getStartPos(((JCArrayAccess) tree).indexed);
459            case METHODDEF: {
460                JCMethodDecl node = (JCMethodDecl)tree;
461                if (node.mods.pos != Position.NOPOS)
462                    return node.mods.pos;
463                if (node.typarams.nonEmpty()) // List.nil() used for no typarams
464                    return getStartPos(node.typarams.head);
465                return node.restype == null ? node.pos : getStartPos(node.restype);
466            }
467            case SELECT:
468                return getStartPos(((JCFieldAccess) tree).selected);
469            case TYPEAPPLY:
470                return getStartPos(((JCTypeApply) tree).clazz);
471            case TYPEARRAY:
472                return getStartPos(((JCArrayTypeTree) tree).elemtype);
473            case TYPETEST:
474                return getStartPos(((JCInstanceOf) tree).expr);
475            case POSTINC:
476            case POSTDEC:
477                return getStartPos(((JCUnary) tree).arg);
478            case ANNOTATED_TYPE: {
479                JCAnnotatedType node = (JCAnnotatedType) tree;
480                if (node.annotations.nonEmpty()) {
481                    if (node.underlyingType.hasTag(TYPEARRAY) ||
482                            node.underlyingType.hasTag(SELECT)) {
483                        return getStartPos(node.underlyingType);
484                    } else {
485                        return getStartPos(node.annotations.head);
486                    }
487                } else {
488                    return getStartPos(node.underlyingType);
489                }
490            }
491            case NEWCLASS: {
492                JCNewClass node = (JCNewClass)tree;
493                if (node.encl != null)
494                    return getStartPos(node.encl);
495                break;
496            }
497            case VARDEF: {
498                JCVariableDecl node = (JCVariableDecl)tree;
499                if (node.mods.pos != Position.NOPOS) {
500                    return node.mods.pos;
501                } else if (node.vartype == null) {
502                    //if there's no type (partially typed lambda parameter)
503                    //simply return node position
504                    return node.pos;
505                } else {
506                    return getStartPos(node.vartype);
507                }
508            }
509            case ERRONEOUS: {
510                JCErroneous node = (JCErroneous)tree;
511                if (node.errs != null && node.errs.nonEmpty())
512                    return getStartPos(node.errs.head);
513            }
514        }
515        return tree.pos;
516    }
517
518    /** The end position of given tree, given  a table of end positions generated by the parser
519     */
520    public static int getEndPos(JCTree tree, EndPosTable endPosTable) {
521        if (tree == null)
522            return Position.NOPOS;
523
524        if (endPosTable == null) {
525            // fall back on limited info in the tree
526            return endPos(tree);
527        }
528
529        int mapPos = endPosTable.getEndPos(tree);
530        if (mapPos != Position.NOPOS)
531            return mapPos;
532
533        switch(tree.getTag()) {
534            case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
535            case SL_ASG: case SR_ASG: case USR_ASG:
536            case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
537            case DIV_ASG: case MOD_ASG:
538                return getEndPos(((JCAssignOp) tree).rhs, endPosTable);
539            case OR: case AND: case BITOR:
540            case BITXOR: case BITAND: case EQ:
541            case NE: case LT: case GT:
542            case LE: case GE: case SL:
543            case SR: case USR: case PLUS:
544            case MINUS: case MUL: case DIV:
545            case MOD:
546                return getEndPos(((JCBinary) tree).rhs, endPosTable);
547            case CASE:
548                return getEndPos(((JCCase) tree).stats.last(), endPosTable);
549            case CATCH:
550                return getEndPos(((JCCatch) tree).body, endPosTable);
551            case CONDEXPR:
552                return getEndPos(((JCConditional) tree).falsepart, endPosTable);
553            case FORLOOP:
554                return getEndPos(((JCForLoop) tree).body, endPosTable);
555            case FOREACHLOOP:
556                return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable);
557            case IF: {
558                JCIf node = (JCIf)tree;
559                if (node.elsepart == null) {
560                    return getEndPos(node.thenpart, endPosTable);
561                } else {
562                    return getEndPos(node.elsepart, endPosTable);
563                }
564            }
565            case LABELLED:
566                return getEndPos(((JCLabeledStatement) tree).body, endPosTable);
567            case MODIFIERS:
568                return getEndPos(((JCModifiers) tree).annotations.last(), endPosTable);
569            case SYNCHRONIZED:
570                return getEndPos(((JCSynchronized) tree).body, endPosTable);
571            case TOPLEVEL:
572                return getEndPos(((JCCompilationUnit) tree).defs.last(), endPosTable);
573            case TRY: {
574                JCTry node = (JCTry)tree;
575                if (node.finalizer != null) {
576                    return getEndPos(node.finalizer, endPosTable);
577                } else if (!node.catchers.isEmpty()) {
578                    return getEndPos(node.catchers.last(), endPosTable);
579                } else {
580                    return getEndPos(node.body, endPosTable);
581                }
582            }
583            case WILDCARD:
584                return getEndPos(((JCWildcard) tree).inner, endPosTable);
585            case TYPECAST:
586                return getEndPos(((JCTypeCast) tree).expr, endPosTable);
587            case TYPETEST:
588                return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
589            case POS:
590            case NEG:
591            case NOT:
592            case COMPL:
593            case PREINC:
594            case PREDEC:
595                return getEndPos(((JCUnary) tree).arg, endPosTable);
596            case WHILELOOP:
597                return getEndPos(((JCWhileLoop) tree).body, endPosTable);
598            case ANNOTATED_TYPE:
599                return getEndPos(((JCAnnotatedType) tree).underlyingType, endPosTable);
600            case ERRONEOUS: {
601                JCErroneous node = (JCErroneous)tree;
602                if (node.errs != null && node.errs.nonEmpty())
603                    return getEndPos(node.errs.last(), endPosTable);
604            }
605        }
606        return Position.NOPOS;
607    }
608
609
610    /** A DiagnosticPosition with the preferred position set to the
611     *  end position of given tree, if it is a block with
612     *  defined endpos.
613     */
614    public static DiagnosticPosition diagEndPos(final JCTree tree) {
615        final int endPos = TreeInfo.endPos(tree);
616        return new DiagnosticPosition() {
617            public JCTree getTree() { return tree; }
618            public int getStartPosition() { return TreeInfo.getStartPos(tree); }
619            public int getPreferredPosition() { return endPos; }
620            public int getEndPosition(EndPosTable endPosTable) {
621                return TreeInfo.getEndPos(tree, endPosTable);
622            }
623        };
624    }
625
626    /** The position of the finalizer of given try/synchronized statement.
627     */
628    public static int finalizerPos(JCTree tree) {
629        if (tree.hasTag(TRY)) {
630            JCTry t = (JCTry) tree;
631            Assert.checkNonNull(t.finalizer);
632            return firstStatPos(t.finalizer);
633        } else if (tree.hasTag(SYNCHRONIZED)) {
634            return endPos(((JCSynchronized) tree).body);
635        } else {
636            throw new AssertionError();
637        }
638    }
639
640    /** Find the position for reporting an error about a symbol, where
641     *  that symbol is defined somewhere in the given tree. */
642    public static int positionFor(final Symbol sym, final JCTree tree) {
643        JCTree decl = declarationFor(sym, tree);
644        return ((decl != null) ? decl : tree).pos;
645    }
646
647    /** Find the position for reporting an error about a symbol, where
648     *  that symbol is defined somewhere in the given tree. */
649    public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
650        JCTree decl = declarationFor(sym, tree);
651        return ((decl != null) ? decl : tree).pos();
652    }
653
654    /** Find the declaration for a symbol, where
655     *  that symbol is defined somewhere in the given tree. */
656    public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
657        class DeclScanner extends TreeScanner {
658            JCTree result = null;
659            public void scan(JCTree tree) {
660                if (tree!=null && result==null)
661                    tree.accept(this);
662            }
663            public void visitTopLevel(JCCompilationUnit that) {
664                if (that.packge == sym) result = that;
665                else super.visitTopLevel(that);
666            }
667            public void visitPackageDef(JCPackageDecl that) {
668                if (that.packge == sym) result = that;
669                else super.visitPackageDef(that);
670            }
671            public void visitClassDef(JCClassDecl that) {
672                if (that.sym == sym) result = that;
673                else super.visitClassDef(that);
674            }
675            public void visitMethodDef(JCMethodDecl that) {
676                if (that.sym == sym) result = that;
677                else super.visitMethodDef(that);
678            }
679            public void visitVarDef(JCVariableDecl that) {
680                if (that.sym == sym) result = that;
681                else super.visitVarDef(that);
682            }
683            public void visitTypeParameter(JCTypeParameter that) {
684                if (that.type != null && that.type.tsym == sym) result = that;
685                else super.visitTypeParameter(that);
686            }
687        }
688        DeclScanner s = new DeclScanner();
689        tree.accept(s);
690        return s.result;
691    }
692
693    public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
694        return scopeFor(pathFor(node, unit));
695    }
696
697    public static Env<AttrContext> scopeFor(List<JCTree> path) {
698        // TODO: not implemented yet
699        throw new UnsupportedOperationException("not implemented yet");
700    }
701
702    public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
703        class Result extends Error {
704            static final long serialVersionUID = -5942088234594905625L;
705            List<JCTree> path;
706            Result(List<JCTree> path) {
707                this.path = path;
708            }
709        }
710        class PathFinder extends TreeScanner {
711            List<JCTree> path = List.nil();
712            public void scan(JCTree tree) {
713                if (tree != null) {
714                    path = path.prepend(tree);
715                    if (tree == node)
716                        throw new Result(path);
717                    super.scan(tree);
718                    path = path.tail;
719                }
720            }
721        }
722        try {
723            new PathFinder().scan(unit);
724        } catch (Result result) {
725            return result.path;
726        }
727        return List.nil();
728    }
729
730    /** Return the statement referenced by a label.
731     *  If the label refers to a loop or switch, return that switch
732     *  otherwise return the labelled statement itself
733     */
734    public static JCTree referencedStatement(JCLabeledStatement tree) {
735        JCTree t = tree;
736        do t = ((JCLabeledStatement) t).body;
737        while (t.hasTag(LABELLED));
738        switch (t.getTag()) {
739        case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH:
740            return t;
741        default:
742            return tree;
743        }
744    }
745
746    /** Skip parens and return the enclosed expression
747     */
748    public static JCExpression skipParens(JCExpression tree) {
749        while (tree.hasTag(PARENS)) {
750            tree = ((JCParens) tree).expr;
751        }
752        return tree;
753    }
754
755    /** Skip parens and return the enclosed expression
756     */
757    public static JCTree skipParens(JCTree tree) {
758        if (tree.hasTag(PARENS))
759            return skipParens((JCParens)tree);
760        else
761            return tree;
762    }
763
764    /** Return the types of a list of trees.
765     */
766    public static List<Type> types(List<? extends JCTree> trees) {
767        ListBuffer<Type> ts = new ListBuffer<>();
768        for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
769            ts.append(l.head.type);
770        return ts.toList();
771    }
772
773    /** If this tree is an identifier or a field or a parameterized type,
774     *  return its name, otherwise return null.
775     */
776    public static Name name(JCTree tree) {
777        switch (tree.getTag()) {
778        case IDENT:
779            return ((JCIdent) tree).name;
780        case SELECT:
781            return ((JCFieldAccess) tree).name;
782        case TYPEAPPLY:
783            return name(((JCTypeApply) tree).clazz);
784        default:
785            return null;
786        }
787    }
788
789    /** If this tree is a qualified identifier, its return fully qualified name,
790     *  otherwise return null.
791     */
792    public static Name fullName(JCTree tree) {
793        tree = skipParens(tree);
794        switch (tree.getTag()) {
795        case IDENT:
796            return ((JCIdent) tree).name;
797        case SELECT:
798            Name sname = fullName(((JCFieldAccess) tree).selected);
799            return sname == null ? null : sname.append('.', name(tree));
800        default:
801            return null;
802        }
803    }
804
805    public static Symbol symbolFor(JCTree node) {
806        Symbol sym = symbolForImpl(node);
807
808        return sym != null ? sym.baseSymbol() : null;
809    }
810
811    private static Symbol symbolForImpl(JCTree node) {
812        node = skipParens(node);
813        switch (node.getTag()) {
814        case TOPLEVEL:
815            return ((JCCompilationUnit) node).packge;
816        case PACKAGEDEF:
817            return ((JCPackageDecl) node).packge;
818        case CLASSDEF:
819            return ((JCClassDecl) node).sym;
820        case METHODDEF:
821            return ((JCMethodDecl) node).sym;
822        case VARDEF:
823            return ((JCVariableDecl) node).sym;
824        case IDENT:
825            return ((JCIdent) node).sym;
826        case SELECT:
827            return ((JCFieldAccess) node).sym;
828        case REFERENCE:
829            return ((JCMemberReference) node).sym;
830        case NEWCLASS:
831            return ((JCNewClass) node).constructor;
832        case APPLY:
833            return symbolFor(((JCMethodInvocation) node).meth);
834        case TYPEAPPLY:
835            return symbolFor(((JCTypeApply) node).clazz);
836        case ANNOTATION:
837        case TYPE_ANNOTATION:
838        case TYPEPARAMETER:
839            if (node.type != null)
840                return node.type.tsym;
841            return null;
842        default:
843            return null;
844        }
845    }
846
847    public static boolean isDeclaration(JCTree node) {
848        node = skipParens(node);
849        switch (node.getTag()) {
850        case PACKAGEDEF:
851        case CLASSDEF:
852        case METHODDEF:
853        case VARDEF:
854            return true;
855        default:
856            return false;
857        }
858    }
859
860    /** If this tree is an identifier or a field, return its symbol,
861     *  otherwise return null.
862     */
863    public static Symbol symbol(JCTree tree) {
864        tree = skipParens(tree);
865        switch (tree.getTag()) {
866        case IDENT:
867            return ((JCIdent) tree).sym;
868        case SELECT:
869            return ((JCFieldAccess) tree).sym;
870        case TYPEAPPLY:
871            return symbol(((JCTypeApply) tree).clazz);
872        case ANNOTATED_TYPE:
873            return symbol(((JCAnnotatedType) tree).underlyingType);
874        case REFERENCE:
875            return ((JCMemberReference) tree).sym;
876        default:
877            return null;
878        }
879    }
880
881    /** Return true if this is a nonstatic selection. */
882    public static boolean nonstaticSelect(JCTree tree) {
883        tree = skipParens(tree);
884        if (!tree.hasTag(SELECT)) return false;
885        JCFieldAccess s = (JCFieldAccess) tree;
886        Symbol e = symbol(s.selected);
887        return e == null || (e.kind != PCK && e.kind != TYP);
888    }
889
890    /** If this tree is an identifier or a field, set its symbol, otherwise skip.
891     */
892    public static void setSymbol(JCTree tree, Symbol sym) {
893        tree = skipParens(tree);
894        switch (tree.getTag()) {
895        case IDENT:
896            ((JCIdent) tree).sym = sym; break;
897        case SELECT:
898            ((JCFieldAccess) tree).sym = sym; break;
899        default:
900        }
901    }
902
903    /** If this tree is a declaration or a block, return its flags field,
904     *  otherwise return 0.
905     */
906    public static long flags(JCTree tree) {
907        switch (tree.getTag()) {
908        case VARDEF:
909            return ((JCVariableDecl) tree).mods.flags;
910        case METHODDEF:
911            return ((JCMethodDecl) tree).mods.flags;
912        case CLASSDEF:
913            return ((JCClassDecl) tree).mods.flags;
914        case BLOCK:
915            return ((JCBlock) tree).flags;
916        default:
917            return 0;
918        }
919    }
920
921    /** Return first (smallest) flag in `flags':
922     *  pre: flags != 0
923     */
924    public static long firstFlag(long flags) {
925        long flag = 1;
926        while ((flag & flags & ExtendedStandardFlags) == 0)
927            flag = flag << 1;
928        return flag;
929    }
930
931    /** Return flags as a string, separated by " ".
932     */
933    public static String flagNames(long flags) {
934        return Flags.toString(flags & ExtendedStandardFlags).trim();
935    }
936
937    /** Operator precedences values.
938     */
939    public static final int
940        notExpression = -1,   // not an expression
941        noPrec = 0,           // no enclosing expression
942        assignPrec = 1,
943        assignopPrec = 2,
944        condPrec = 3,
945        orPrec = 4,
946        andPrec = 5,
947        bitorPrec = 6,
948        bitxorPrec = 7,
949        bitandPrec = 8,
950        eqPrec = 9,
951        ordPrec = 10,
952        shiftPrec = 11,
953        addPrec = 12,
954        mulPrec = 13,
955        prefixPrec = 14,
956        postfixPrec = 15,
957        precCount = 16;
958
959
960    /** Map operators to their precedence levels.
961     */
962    public static int opPrec(JCTree.Tag op) {
963        switch(op) {
964        case POS:
965        case NEG:
966        case NOT:
967        case COMPL:
968        case PREINC:
969        case PREDEC: return prefixPrec;
970        case POSTINC:
971        case POSTDEC:
972        case NULLCHK: return postfixPrec;
973        case ASSIGN: return assignPrec;
974        case BITOR_ASG:
975        case BITXOR_ASG:
976        case BITAND_ASG:
977        case SL_ASG:
978        case SR_ASG:
979        case USR_ASG:
980        case PLUS_ASG:
981        case MINUS_ASG:
982        case MUL_ASG:
983        case DIV_ASG:
984        case MOD_ASG: return assignopPrec;
985        case OR: return orPrec;
986        case AND: return andPrec;
987        case EQ:
988        case NE: return eqPrec;
989        case LT:
990        case GT:
991        case LE:
992        case GE: return ordPrec;
993        case BITOR: return bitorPrec;
994        case BITXOR: return bitxorPrec;
995        case BITAND: return bitandPrec;
996        case SL:
997        case SR:
998        case USR: return shiftPrec;
999        case PLUS:
1000        case MINUS: return addPrec;
1001        case MUL:
1002        case DIV:
1003        case MOD: return mulPrec;
1004        case TYPETEST: return ordPrec;
1005        default: throw new AssertionError();
1006        }
1007    }
1008
1009    static Tree.Kind tagToKind(JCTree.Tag tag) {
1010        switch (tag) {
1011        // Postfix expressions
1012        case POSTINC:           // _ ++
1013            return Tree.Kind.POSTFIX_INCREMENT;
1014        case POSTDEC:           // _ --
1015            return Tree.Kind.POSTFIX_DECREMENT;
1016
1017        // Unary operators
1018        case PREINC:            // ++ _
1019            return Tree.Kind.PREFIX_INCREMENT;
1020        case PREDEC:            // -- _
1021            return Tree.Kind.PREFIX_DECREMENT;
1022        case POS:               // +
1023            return Tree.Kind.UNARY_PLUS;
1024        case NEG:               // -
1025            return Tree.Kind.UNARY_MINUS;
1026        case COMPL:             // ~
1027            return Tree.Kind.BITWISE_COMPLEMENT;
1028        case NOT:               // !
1029            return Tree.Kind.LOGICAL_COMPLEMENT;
1030
1031        // Binary operators
1032
1033        // Multiplicative operators
1034        case MUL:               // *
1035            return Tree.Kind.MULTIPLY;
1036        case DIV:               // /
1037            return Tree.Kind.DIVIDE;
1038        case MOD:               // %
1039            return Tree.Kind.REMAINDER;
1040
1041        // Additive operators
1042        case PLUS:              // +
1043            return Tree.Kind.PLUS;
1044        case MINUS:             // -
1045            return Tree.Kind.MINUS;
1046
1047        // Shift operators
1048        case SL:                // <<
1049            return Tree.Kind.LEFT_SHIFT;
1050        case SR:                // >>
1051            return Tree.Kind.RIGHT_SHIFT;
1052        case USR:               // >>>
1053            return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
1054
1055        // Relational operators
1056        case LT:                // <
1057            return Tree.Kind.LESS_THAN;
1058        case GT:                // >
1059            return Tree.Kind.GREATER_THAN;
1060        case LE:                // <=
1061            return Tree.Kind.LESS_THAN_EQUAL;
1062        case GE:                // >=
1063            return Tree.Kind.GREATER_THAN_EQUAL;
1064
1065        // Equality operators
1066        case EQ:                // ==
1067            return Tree.Kind.EQUAL_TO;
1068        case NE:                // !=
1069            return Tree.Kind.NOT_EQUAL_TO;
1070
1071        // Bitwise and logical operators
1072        case BITAND:            // &
1073            return Tree.Kind.AND;
1074        case BITXOR:            // ^
1075            return Tree.Kind.XOR;
1076        case BITOR:             // |
1077            return Tree.Kind.OR;
1078
1079        // Conditional operators
1080        case AND:               // &&
1081            return Tree.Kind.CONDITIONAL_AND;
1082        case OR:                // ||
1083            return Tree.Kind.CONDITIONAL_OR;
1084
1085        // Assignment operators
1086        case MUL_ASG:           // *=
1087            return Tree.Kind.MULTIPLY_ASSIGNMENT;
1088        case DIV_ASG:           // /=
1089            return Tree.Kind.DIVIDE_ASSIGNMENT;
1090        case MOD_ASG:           // %=
1091            return Tree.Kind.REMAINDER_ASSIGNMENT;
1092        case PLUS_ASG:          // +=
1093            return Tree.Kind.PLUS_ASSIGNMENT;
1094        case MINUS_ASG:         // -=
1095            return Tree.Kind.MINUS_ASSIGNMENT;
1096        case SL_ASG:            // <<=
1097            return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
1098        case SR_ASG:            // >>=
1099            return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
1100        case USR_ASG:           // >>>=
1101            return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
1102        case BITAND_ASG:        // &=
1103            return Tree.Kind.AND_ASSIGNMENT;
1104        case BITXOR_ASG:        // ^=
1105            return Tree.Kind.XOR_ASSIGNMENT;
1106        case BITOR_ASG:         // |=
1107            return Tree.Kind.OR_ASSIGNMENT;
1108
1109        // Null check (implementation detail), for example, __.getClass()
1110        case NULLCHK:
1111            return Tree.Kind.OTHER;
1112
1113        case ANNOTATION:
1114            return Tree.Kind.ANNOTATION;
1115        case TYPE_ANNOTATION:
1116            return Tree.Kind.TYPE_ANNOTATION;
1117
1118        default:
1119            return null;
1120        }
1121    }
1122
1123    /**
1124     * Returns the underlying type of the tree if it is an annotated type,
1125     * or the tree itself otherwise.
1126     */
1127    public static JCExpression typeIn(JCExpression tree) {
1128        switch (tree.getTag()) {
1129        case ANNOTATED_TYPE:
1130            return ((JCAnnotatedType)tree).underlyingType;
1131        case IDENT: /* simple names */
1132        case TYPEIDENT: /* primitive name */
1133        case SELECT: /* qualified name */
1134        case TYPEARRAY: /* array types */
1135        case WILDCARD: /* wild cards */
1136        case TYPEPARAMETER: /* type parameters */
1137        case TYPEAPPLY: /* parameterized types */
1138        case ERRONEOUS: /* error tree TODO: needed for BadCast JSR308 test case. Better way? */
1139            return tree;
1140        default:
1141            throw new AssertionError("Unexpected type tree: " + tree);
1142        }
1143    }
1144
1145    /* Return the inner-most type of a type tree.
1146     * For an array that contains an annotated type, return that annotated type.
1147     * TODO: currently only used by Pretty. Describe behavior better.
1148     */
1149    public static JCTree innermostType(JCTree type) {
1150        JCTree lastAnnotatedType = null;
1151        JCTree cur = type;
1152        loop: while (true) {
1153            switch (cur.getTag()) {
1154            case TYPEARRAY:
1155                lastAnnotatedType = null;
1156                cur = ((JCArrayTypeTree)cur).elemtype;
1157                break;
1158            case WILDCARD:
1159                lastAnnotatedType = null;
1160                cur = ((JCWildcard)cur).inner;
1161                break;
1162            case ANNOTATED_TYPE:
1163                lastAnnotatedType = cur;
1164                cur = ((JCAnnotatedType)cur).underlyingType;
1165                break;
1166            default:
1167                break loop;
1168            }
1169        }
1170        if (lastAnnotatedType!=null) {
1171            return lastAnnotatedType;
1172        } else {
1173            return cur;
1174        }
1175    }
1176
1177    private static class TypeAnnotationFinder extends TreeScanner {
1178        public boolean foundTypeAnno = false;
1179
1180        @Override
1181        public void scan(JCTree tree) {
1182            if (foundTypeAnno || tree == null)
1183                return;
1184            super.scan(tree);
1185        }
1186
1187        public void visitAnnotation(JCAnnotation tree) {
1188            foundTypeAnno = foundTypeAnno || tree.hasTag(TYPE_ANNOTATION);
1189        }
1190    }
1191
1192    public static boolean containsTypeAnnotation(JCTree e) {
1193        TypeAnnotationFinder finder = new TypeAnnotationFinder();
1194        finder.scan(e);
1195        return finder.foundTypeAnno;
1196    }
1197}
1198