001    /*
002     * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.tree;
027    
028    import com.sun.source.tree.Tree;
029    import com.sun.tools.javac.comp.AttrContext;
030    import com.sun.tools.javac.comp.Env;
031    import java.util.Map;
032    import com.sun.tools.javac.util.*;
033    import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
034    import com.sun.tools.javac.code.*;
035    import com.sun.tools.javac.tree.JCTree.*;
036    
037    import static com.sun.tools.javac.code.Flags.*;
038    
039    /** Utility class containing inspector methods for trees.
040     *
041     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
042     *  you write code that depends on this, you do so at your own risk.
043     *  This code and its internal interfaces are subject to change or
044     *  deletion without notice.</b>
045     */
046    public class TreeInfo {
047        protected static final Context.Key<TreeInfo> treeInfoKey =
048            new Context.Key<TreeInfo>();
049    
050        public static TreeInfo instance(Context context) {
051            TreeInfo instance = context.get(treeInfoKey);
052            if (instance == null)
053                instance = new TreeInfo(context);
054            return instance;
055        }
056    
057        /** The names of all operators.
058         */
059        private Name[] opname = new Name[JCTree.MOD - JCTree.POS + 1];
060    
061        private TreeInfo(Context context) {
062            context.put(treeInfoKey, this);
063    
064            Names names = Names.instance(context);
065            opname[JCTree.POS     - JCTree.POS] = names.fromString("+");
066            opname[JCTree.NEG     - JCTree.POS] = names.hyphen;
067            opname[JCTree.NOT     - JCTree.POS] = names.fromString("!");
068            opname[JCTree.COMPL   - JCTree.POS] = names.fromString("~");
069            opname[JCTree.PREINC  - JCTree.POS] = names.fromString("++");
070            opname[JCTree.PREDEC  - JCTree.POS] = names.fromString("--");
071            opname[JCTree.POSTINC - JCTree.POS] = names.fromString("++");
072            opname[JCTree.POSTDEC - JCTree.POS] = names.fromString("--");
073            opname[JCTree.NULLCHK - JCTree.POS] = names.fromString("<*nullchk*>");
074            opname[JCTree.OR      - JCTree.POS] = names.fromString("||");
075            opname[JCTree.AND     - JCTree.POS] = names.fromString("&&");
076            opname[JCTree.EQ      - JCTree.POS] = names.fromString("==");
077            opname[JCTree.NE      - JCTree.POS] = names.fromString("!=");
078            opname[JCTree.LT      - JCTree.POS] = names.fromString("<");
079            opname[JCTree.GT      - JCTree.POS] = names.fromString(">");
080            opname[JCTree.LE      - JCTree.POS] = names.fromString("<=");
081            opname[JCTree.GE      - JCTree.POS] = names.fromString(">=");
082            opname[JCTree.BITOR   - JCTree.POS] = names.fromString("|");
083            opname[JCTree.BITXOR  - JCTree.POS] = names.fromString("^");
084            opname[JCTree.BITAND  - JCTree.POS] = names.fromString("&");
085            opname[JCTree.SL      - JCTree.POS] = names.fromString("<<");
086            opname[JCTree.SR      - JCTree.POS] = names.fromString(">>");
087            opname[JCTree.USR     - JCTree.POS] = names.fromString(">>>");
088            opname[JCTree.PLUS    - JCTree.POS] = names.fromString("+");
089            opname[JCTree.MINUS   - JCTree.POS] = names.hyphen;
090            opname[JCTree.MUL     - JCTree.POS] = names.asterisk;
091            opname[JCTree.DIV     - JCTree.POS] = names.slash;
092            opname[JCTree.MOD     - JCTree.POS] = names.fromString("%");
093        }
094    
095    
096        /** Return name of operator with given tree tag.
097         */
098        public Name operatorName(int tag) {
099            return opname[tag - JCTree.POS];
100        }
101    
102        /** Is tree a constructor declaration?
103         */
104        public static boolean isConstructor(JCTree tree) {
105            if (tree.getTag() == JCTree.METHODDEF) {
106                Name name = ((JCMethodDecl) tree).name;
107                return name == name.table.names.init;
108            } else {
109                return false;
110            }
111        }
112    
113        /** Is there a constructor declaration in the given list of trees?
114         */
115        public static boolean hasConstructors(List<JCTree> trees) {
116            for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
117                if (isConstructor(l.head)) return true;
118            return false;
119        }
120    
121        /** Is statement an initializer for a synthetic field?
122         */
123        public static boolean isSyntheticInit(JCTree stat) {
124            if (stat.getTag() == JCTree.EXEC) {
125                JCExpressionStatement exec = (JCExpressionStatement)stat;
126                if (exec.expr.getTag() == JCTree.ASSIGN) {
127                    JCAssign assign = (JCAssign)exec.expr;
128                    if (assign.lhs.getTag() == JCTree.SELECT) {
129                        JCFieldAccess select = (JCFieldAccess)assign.lhs;
130                        if (select.sym != null &&
131                            (select.sym.flags() & SYNTHETIC) != 0) {
132                            Name selected = name(select.selected);
133                            if (selected != null && selected == selected.table.names._this)
134                                return true;
135                        }
136                    }
137                }
138            }
139            return false;
140        }
141    
142        /** If the expression is a method call, return the method name, null
143         *  otherwise. */
144        public static Name calledMethodName(JCTree tree) {
145            if (tree.getTag() == JCTree.EXEC) {
146                JCExpressionStatement exec = (JCExpressionStatement)tree;
147                if (exec.expr.getTag() == JCTree.APPLY) {
148                    Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
149                    return mname;
150                }
151            }
152            return null;
153        }
154    
155        /** Is this a call to this or super?
156         */
157        public static boolean isSelfCall(JCTree tree) {
158            Name name = calledMethodName(tree);
159            if (name != null) {
160                Names names = name.table.names;
161                return name==names._this || name==names._super;
162            } else {
163                return false;
164            }
165        }
166    
167        /** Is this a call to super?
168         */
169        public static boolean isSuperCall(JCTree tree) {
170            Name name = calledMethodName(tree);
171            if (name != null) {
172                Names names = name.table.names;
173                return name==names._super;
174            } else {
175                return false;
176            }
177        }
178    
179        /** Is this a constructor whose first (non-synthetic) statement is not
180         *  of the form this(...)?
181         */
182        public static boolean isInitialConstructor(JCTree tree) {
183            JCMethodInvocation app = firstConstructorCall(tree);
184            if (app == null) return false;
185            Name meth = name(app.meth);
186            return meth == null || meth != meth.table.names._this;
187        }
188    
189        /** Return the first call in a constructor definition. */
190        public static JCMethodInvocation firstConstructorCall(JCTree tree) {
191            if (tree.getTag() != JCTree.METHODDEF) return null;
192            JCMethodDecl md = (JCMethodDecl) tree;
193            Names names = md.name.table.names;
194            if (md.name != names.init) return null;
195            if (md.body == null) return null;
196            List<JCStatement> stats = md.body.stats;
197            // Synthetic initializations can appear before the super call.
198            while (stats.nonEmpty() && isSyntheticInit(stats.head))
199                stats = stats.tail;
200            if (stats.isEmpty()) return null;
201            if (stats.head.getTag() != JCTree.EXEC) return null;
202            JCExpressionStatement exec = (JCExpressionStatement) stats.head;
203            if (exec.expr.getTag() != JCTree.APPLY) return null;
204            return (JCMethodInvocation)exec.expr;
205        }
206    
207        /** Return true if a tree represents the null literal. */
208        public static boolean isNull(JCTree tree) {
209            if (tree.getTag() != JCTree.LITERAL)
210                return false;
211            JCLiteral lit = (JCLiteral) tree;
212            return (lit.typetag == TypeTags.BOT);
213        }
214    
215        /** The position of the first statement in a block, or the position of
216         *  the block itself if it is empty.
217         */
218        public static int firstStatPos(JCTree tree) {
219            if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).stats.nonEmpty())
220                return ((JCBlock) tree).stats.head.pos;
221            else
222                return tree.pos;
223        }
224    
225        /** The end position of given tree, if it is a block with
226         *  defined endpos.
227         */
228        public static int endPos(JCTree tree) {
229            if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).endpos != Position.NOPOS)
230                return ((JCBlock) tree).endpos;
231            else if (tree.getTag() == JCTree.SYNCHRONIZED)
232                return endPos(((JCSynchronized) tree).body);
233            else if (tree.getTag() == JCTree.TRY) {
234                JCTry t = (JCTry) tree;
235                return endPos((t.finalizer != null)
236                              ? t.finalizer
237                              : t.catchers.last().body);
238            } else
239                return tree.pos;
240        }
241    
242    
243        /** Get the start position for a tree node.  The start position is
244         * defined to be the position of the first character of the first
245         * token of the node's source text.
246         * @param tree  The tree node
247         */
248        public static int getStartPos(JCTree tree) {
249            if (tree == null)
250                return Position.NOPOS;
251    
252            switch(tree.getTag()) {
253            case(JCTree.APPLY):
254                return getStartPos(((JCMethodInvocation) tree).meth);
255            case(JCTree.ASSIGN):
256                return getStartPos(((JCAssign) tree).lhs);
257            case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
258            case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
259            case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
260            case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
261                return getStartPos(((JCAssignOp) tree).lhs);
262            case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
263            case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
264            case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
265            case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
266            case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
267            case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
268            case(JCTree.MOD):
269                return getStartPos(((JCBinary) tree).lhs);
270            case(JCTree.CLASSDEF): {
271                JCClassDecl node = (JCClassDecl)tree;
272                if (node.mods.pos != Position.NOPOS)
273                    return node.mods.pos;
274                break;
275            }
276            case(JCTree.CONDEXPR):
277                return getStartPos(((JCConditional) tree).cond);
278            case(JCTree.EXEC):
279                return getStartPos(((JCExpressionStatement) tree).expr);
280            case(JCTree.INDEXED):
281                return getStartPos(((JCArrayAccess) tree).indexed);
282            case(JCTree.METHODDEF): {
283                JCMethodDecl node = (JCMethodDecl)tree;
284                if (node.mods.pos != Position.NOPOS)
285                    return node.mods.pos;
286                if (node.typarams.nonEmpty()) // List.nil() used for no typarams
287                    return getStartPos(node.typarams.head);
288                return node.restype == null ? node.pos : getStartPos(node.restype);
289            }
290            case(JCTree.SELECT):
291                return getStartPos(((JCFieldAccess) tree).selected);
292            case(JCTree.TYPEAPPLY):
293                return getStartPos(((JCTypeApply) tree).clazz);
294            case(JCTree.TYPEARRAY):
295                return getStartPos(((JCArrayTypeTree) tree).elemtype);
296            case(JCTree.TYPETEST):
297                return getStartPos(((JCInstanceOf) tree).expr);
298            case(JCTree.POSTINC):
299            case(JCTree.POSTDEC):
300                return getStartPos(((JCUnary) tree).arg);
301            case(JCTree.VARDEF): {
302                JCVariableDecl node = (JCVariableDecl)tree;
303                if (node.mods.pos != Position.NOPOS) {
304                    return node.mods.pos;
305                } else {
306                    return getStartPos(node.vartype);
307                }
308            }
309            case(JCTree.ERRONEOUS): {
310                JCErroneous node = (JCErroneous)tree;
311                if (node.errs != null && node.errs.nonEmpty())
312                    return getStartPos(node.errs.head);
313            }
314            }
315            return tree.pos;
316        }
317    
318        /** The end position of given tree, given  a table of end positions generated by the parser
319         */
320        public static int getEndPos(JCTree tree, Map<JCTree, Integer> endPositions) {
321            if (tree == null)
322                return Position.NOPOS;
323    
324            if (endPositions == null) {
325                // fall back on limited info in the tree
326                return endPos(tree);
327            }
328    
329            Integer mapPos = endPositions.get(tree);
330            if (mapPos != null)
331                return mapPos;
332    
333            switch(tree.getTag()) {
334            case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
335            case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
336            case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
337            case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
338                return getEndPos(((JCAssignOp) tree).rhs, endPositions);
339            case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
340            case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
341            case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
342            case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
343            case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
344            case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
345            case(JCTree.MOD):
346                return getEndPos(((JCBinary) tree).rhs, endPositions);
347            case(JCTree.CASE):
348                return getEndPos(((JCCase) tree).stats.last(), endPositions);
349            case(JCTree.CATCH):
350                return getEndPos(((JCCatch) tree).body, endPositions);
351            case(JCTree.CONDEXPR):
352                return getEndPos(((JCConditional) tree).falsepart, endPositions);
353            case(JCTree.FORLOOP):
354                return getEndPos(((JCForLoop) tree).body, endPositions);
355            case(JCTree.FOREACHLOOP):
356                return getEndPos(((JCEnhancedForLoop) tree).body, endPositions);
357            case(JCTree.IF): {
358                JCIf node = (JCIf)tree;
359                if (node.elsepart == null) {
360                    return getEndPos(node.thenpart, endPositions);
361                } else {
362                    return getEndPos(node.elsepart, endPositions);
363                }
364            }
365            case(JCTree.LABELLED):
366                return getEndPos(((JCLabeledStatement) tree).body, endPositions);
367            case(JCTree.MODIFIERS):
368                return getEndPos(((JCModifiers) tree).annotations.last(), endPositions);
369            case(JCTree.SYNCHRONIZED):
370                return getEndPos(((JCSynchronized) tree).body, endPositions);
371            case(JCTree.TOPLEVEL):
372                return getEndPos(((JCCompilationUnit) tree).defs.last(), endPositions);
373            case(JCTree.TRY): {
374                JCTry node = (JCTry)tree;
375                if (node.finalizer != null) {
376                    return getEndPos(node.finalizer, endPositions);
377                } else if (!node.catchers.isEmpty()) {
378                    return getEndPos(node.catchers.last(), endPositions);
379                } else {
380                    return getEndPos(node.body, endPositions);
381                }
382            }
383            case(JCTree.WILDCARD):
384                return getEndPos(((JCWildcard) tree).inner, endPositions);
385            case(JCTree.TYPECAST):
386                return getEndPos(((JCTypeCast) tree).expr, endPositions);
387            case(JCTree.TYPETEST):
388                return getEndPos(((JCInstanceOf) tree).clazz, endPositions);
389            case(JCTree.POS):
390            case(JCTree.NEG):
391            case(JCTree.NOT):
392            case(JCTree.COMPL):
393            case(JCTree.PREINC):
394            case(JCTree.PREDEC):
395                return getEndPos(((JCUnary) tree).arg, endPositions);
396            case(JCTree.WHILELOOP):
397                return getEndPos(((JCWhileLoop) tree).body, endPositions);
398            case(JCTree.ERRONEOUS): {
399                JCErroneous node = (JCErroneous)tree;
400                if (node.errs != null && node.errs.nonEmpty())
401                    return getEndPos(node.errs.last(), endPositions);
402            }
403            }
404            return Position.NOPOS;
405        }
406    
407    
408        /** A DiagnosticPosition with the preferred position set to the
409         *  end position of given tree, if it is a block with
410         *  defined endpos.
411         */
412        public static DiagnosticPosition diagEndPos(final JCTree tree) {
413            final int endPos = TreeInfo.endPos(tree);
414            return new DiagnosticPosition() {
415                public JCTree getTree() { return tree; }
416                public int getStartPosition() { return TreeInfo.getStartPos(tree); }
417                public int getPreferredPosition() { return endPos; }
418                public int getEndPosition(Map<JCTree, Integer> endPosTable) {
419                    return TreeInfo.getEndPos(tree, endPosTable);
420                }
421            };
422        }
423    
424        /** The position of the finalizer of given try/synchronized statement.
425         */
426        public static int finalizerPos(JCTree tree) {
427            if (tree.getTag() == JCTree.TRY) {
428                JCTry t = (JCTry) tree;
429                assert t.finalizer != null;
430                return firstStatPos(t.finalizer);
431            } else if (tree.getTag() == JCTree.SYNCHRONIZED) {
432                return endPos(((JCSynchronized) tree).body);
433            } else {
434                throw new AssertionError();
435            }
436        }
437    
438        /** Find the position for reporting an error about a symbol, where
439         *  that symbol is defined somewhere in the given tree. */
440        public static int positionFor(final Symbol sym, final JCTree tree) {
441            JCTree decl = declarationFor(sym, tree);
442            return ((decl != null) ? decl : tree).pos;
443        }
444    
445        /** Find the position for reporting an error about a symbol, where
446         *  that symbol is defined somewhere in the given tree. */
447        public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
448            JCTree decl = declarationFor(sym, tree);
449            return ((decl != null) ? decl : tree).pos();
450        }
451    
452        /** Find the declaration for a symbol, where
453         *  that symbol is defined somewhere in the given tree. */
454        public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
455            class DeclScanner extends TreeScanner {
456                JCTree result = null;
457                public void scan(JCTree tree) {
458                    if (tree!=null && result==null)
459                        tree.accept(this);
460                }
461                public void visitTopLevel(JCCompilationUnit that) {
462                    if (that.packge == sym) result = that;
463                    else super.visitTopLevel(that);
464                }
465                public void visitClassDef(JCClassDecl that) {
466                    if (that.sym == sym) result = that;
467                    else super.visitClassDef(that);
468                }
469                public void visitMethodDef(JCMethodDecl that) {
470                    if (that.sym == sym) result = that;
471                    else super.visitMethodDef(that);
472                }
473                public void visitVarDef(JCVariableDecl that) {
474                    if (that.sym == sym) result = that;
475                    else super.visitVarDef(that);
476                }
477            }
478            DeclScanner s = new DeclScanner();
479            tree.accept(s);
480            return s.result;
481        }
482    
483        public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
484            return scopeFor(pathFor(node, unit));
485        }
486    
487        public static Env<AttrContext> scopeFor(List<JCTree> path) {
488            // TODO: not implemented yet
489            throw new UnsupportedOperationException("not implemented yet");
490        }
491    
492        public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
493            class Result extends Error {
494                static final long serialVersionUID = -5942088234594905625L;
495                List<JCTree> path;
496                Result(List<JCTree> path) {
497                    this.path = path;
498                }
499            }
500            class PathFinder extends TreeScanner {
501                List<JCTree> path = List.nil();
502                public void scan(JCTree tree) {
503                    if (tree != null) {
504                        path = path.prepend(tree);
505                        if (tree == node)
506                            throw new Result(path);
507                        super.scan(tree);
508                        path = path.tail;
509                    }
510                }
511            }
512            try {
513                new PathFinder().scan(unit);
514            } catch (Result result) {
515                return result.path;
516            }
517            return List.nil();
518        }
519    
520        /** Return the statement referenced by a label.
521         *  If the label refers to a loop or switch, return that switch
522         *  otherwise return the labelled statement itself
523         */
524        public static JCTree referencedStatement(JCLabeledStatement tree) {
525            JCTree t = tree;
526            do t = ((JCLabeledStatement) t).body;
527            while (t.getTag() == JCTree.LABELLED);
528            switch (t.getTag()) {
529            case JCTree.DOLOOP: case JCTree.WHILELOOP: case JCTree.FORLOOP: case JCTree.FOREACHLOOP: case JCTree.SWITCH:
530                return t;
531            default:
532                return tree;
533            }
534        }
535    
536        /** Skip parens and return the enclosed expression
537         */
538        public static JCExpression skipParens(JCExpression tree) {
539            while (tree.getTag() == JCTree.PARENS) {
540                tree = ((JCParens) tree).expr;
541            }
542            return tree;
543        }
544    
545        /** Skip parens and return the enclosed expression
546         */
547        public static JCTree skipParens(JCTree tree) {
548            if (tree.getTag() == JCTree.PARENS)
549                return skipParens((JCParens)tree);
550            else
551                return tree;
552        }
553    
554        /** Return the types of a list of trees.
555         */
556        public static List<Type> types(List<? extends JCTree> trees) {
557            ListBuffer<Type> ts = new ListBuffer<Type>();
558            for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
559                ts.append(l.head.type);
560            return ts.toList();
561        }
562    
563        /** If this tree is an identifier or a field or a parameterized type,
564         *  return its name, otherwise return null.
565         */
566        public static Name name(JCTree tree) {
567            switch (tree.getTag()) {
568            case JCTree.IDENT:
569                return ((JCIdent) tree).name;
570            case JCTree.SELECT:
571                return ((JCFieldAccess) tree).name;
572            case JCTree.TYPEAPPLY:
573                return name(((JCTypeApply) tree).clazz);
574            default:
575                return null;
576            }
577        }
578    
579        /** If this tree is a qualified identifier, its return fully qualified name,
580         *  otherwise return null.
581         */
582        public static Name fullName(JCTree tree) {
583            tree = skipParens(tree);
584            switch (tree.getTag()) {
585            case JCTree.IDENT:
586                return ((JCIdent) tree).name;
587            case JCTree.SELECT:
588                Name sname = fullName(((JCFieldAccess) tree).selected);
589                return sname == null ? null : sname.append('.', name(tree));
590            default:
591                return null;
592            }
593        }
594    
595        public static Symbol symbolFor(JCTree node) {
596            node = skipParens(node);
597            switch (node.getTag()) {
598            case JCTree.CLASSDEF:
599                return ((JCClassDecl) node).sym;
600            case JCTree.METHODDEF:
601                return ((JCMethodDecl) node).sym;
602            case JCTree.VARDEF:
603                return ((JCVariableDecl) node).sym;
604            default:
605                return null;
606            }
607        }
608    
609        /** If this tree is an identifier or a field, return its symbol,
610         *  otherwise return null.
611         */
612        public static Symbol symbol(JCTree tree) {
613            tree = skipParens(tree);
614            switch (tree.getTag()) {
615            case JCTree.IDENT:
616                return ((JCIdent) tree).sym;
617            case JCTree.SELECT:
618                return ((JCFieldAccess) tree).sym;
619            case JCTree.TYPEAPPLY:
620                return symbol(((JCTypeApply) tree).clazz);
621            default:
622                return null;
623            }
624        }
625    
626        /** Return true if this is a nonstatic selection. */
627        public static boolean nonstaticSelect(JCTree tree) {
628            tree = skipParens(tree);
629            if (tree.getTag() != JCTree.SELECT) return false;
630            JCFieldAccess s = (JCFieldAccess) tree;
631            Symbol e = symbol(s.selected);
632            return e == null || (e.kind != Kinds.PCK && e.kind != Kinds.TYP);
633        }
634    
635        /** If this tree is an identifier or a field, set its symbol, otherwise skip.
636         */
637        public static void setSymbol(JCTree tree, Symbol sym) {
638            tree = skipParens(tree);
639            switch (tree.getTag()) {
640            case JCTree.IDENT:
641                ((JCIdent) tree).sym = sym; break;
642            case JCTree.SELECT:
643                ((JCFieldAccess) tree).sym = sym; break;
644            default:
645            }
646        }
647    
648        /** If this tree is a declaration or a block, return its flags field,
649         *  otherwise return 0.
650         */
651        public static long flags(JCTree tree) {
652            switch (tree.getTag()) {
653            case JCTree.VARDEF:
654                return ((JCVariableDecl) tree).mods.flags;
655            case JCTree.METHODDEF:
656                return ((JCMethodDecl) tree).mods.flags;
657            case JCTree.CLASSDEF:
658                return ((JCClassDecl) tree).mods.flags;
659            case JCTree.BLOCK:
660                return ((JCBlock) tree).flags;
661            default:
662                return 0;
663            }
664        }
665    
666        /** Return first (smallest) flag in `flags':
667         *  pre: flags != 0
668         */
669        public static long firstFlag(long flags) {
670            int flag = 1;
671            while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
672                flag = flag << 1;
673            return flag;
674        }
675    
676        /** Return flags as a string, separated by " ".
677         */
678        public static String flagNames(long flags) {
679            return Flags.toString(flags & StandardFlags).trim();
680        }
681    
682        /** Operator precedences values.
683         */
684        public static final int
685            notExpression = -1,   // not an expression
686            noPrec = 0,           // no enclosing expression
687            assignPrec = 1,
688            assignopPrec = 2,
689            condPrec = 3,
690            orPrec = 4,
691            andPrec = 5,
692            bitorPrec = 6,
693            bitxorPrec = 7,
694            bitandPrec = 8,
695            eqPrec = 9,
696            ordPrec = 10,
697            shiftPrec = 11,
698            addPrec = 12,
699            mulPrec = 13,
700            prefixPrec = 14,
701            postfixPrec = 15,
702            precCount = 16;
703    
704    
705        /** Map operators to their precedence levels.
706         */
707        public static int opPrec(int op) {
708            switch(op) {
709            case JCTree.POS:
710            case JCTree.NEG:
711            case JCTree.NOT:
712            case JCTree.COMPL:
713            case JCTree.PREINC:
714            case JCTree.PREDEC: return prefixPrec;
715            case JCTree.POSTINC:
716            case JCTree.POSTDEC:
717            case JCTree.NULLCHK: return postfixPrec;
718            case JCTree.ASSIGN: return assignPrec;
719            case JCTree.BITOR_ASG:
720            case JCTree.BITXOR_ASG:
721            case JCTree.BITAND_ASG:
722            case JCTree.SL_ASG:
723            case JCTree.SR_ASG:
724            case JCTree.USR_ASG:
725            case JCTree.PLUS_ASG:
726            case JCTree.MINUS_ASG:
727            case JCTree.MUL_ASG:
728            case JCTree.DIV_ASG:
729            case JCTree.MOD_ASG: return assignopPrec;
730            case JCTree.OR: return orPrec;
731            case JCTree.AND: return andPrec;
732            case JCTree.EQ:
733            case JCTree.NE: return eqPrec;
734            case JCTree.LT:
735            case JCTree.GT:
736            case JCTree.LE:
737            case JCTree.GE: return ordPrec;
738            case JCTree.BITOR: return bitorPrec;
739            case JCTree.BITXOR: return bitxorPrec;
740            case JCTree.BITAND: return bitandPrec;
741            case JCTree.SL:
742            case JCTree.SR:
743            case JCTree.USR: return shiftPrec;
744            case JCTree.PLUS:
745            case JCTree.MINUS: return addPrec;
746            case JCTree.MUL:
747            case JCTree.DIV:
748            case JCTree.MOD: return mulPrec;
749            case JCTree.TYPETEST: return ordPrec;
750            default: throw new AssertionError();
751            }
752        }
753    
754        static Tree.Kind tagToKind(int tag) {
755            switch (tag) {
756            // Postfix expressions
757            case JCTree.POSTINC:           // _ ++
758                return Tree.Kind.POSTFIX_INCREMENT;
759            case JCTree.POSTDEC:           // _ --
760                return Tree.Kind.POSTFIX_DECREMENT;
761    
762            // Unary operators
763            case JCTree.PREINC:            // ++ _
764                return Tree.Kind.PREFIX_INCREMENT;
765            case JCTree.PREDEC:            // -- _
766                return Tree.Kind.PREFIX_DECREMENT;
767            case JCTree.POS:               // +
768                return Tree.Kind.UNARY_PLUS;
769            case JCTree.NEG:               // -
770                return Tree.Kind.UNARY_MINUS;
771            case JCTree.COMPL:             // ~
772                return Tree.Kind.BITWISE_COMPLEMENT;
773            case JCTree.NOT:               // !
774                return Tree.Kind.LOGICAL_COMPLEMENT;
775    
776            // Binary operators
777    
778            // Multiplicative operators
779            case JCTree.MUL:               // *
780                return Tree.Kind.MULTIPLY;
781            case JCTree.DIV:               // /
782                return Tree.Kind.DIVIDE;
783            case JCTree.MOD:               // %
784                return Tree.Kind.REMAINDER;
785    
786            // Additive operators
787            case JCTree.PLUS:              // +
788                return Tree.Kind.PLUS;
789            case JCTree.MINUS:             // -
790                return Tree.Kind.MINUS;
791    
792            // Shift operators
793            case JCTree.SL:                // <<
794                return Tree.Kind.LEFT_SHIFT;
795            case JCTree.SR:                // >>
796                return Tree.Kind.RIGHT_SHIFT;
797            case JCTree.USR:               // >>>
798                return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
799    
800            // Relational operators
801            case JCTree.LT:                // <
802                return Tree.Kind.LESS_THAN;
803            case JCTree.GT:                // >
804                return Tree.Kind.GREATER_THAN;
805            case JCTree.LE:                // <=
806                return Tree.Kind.LESS_THAN_EQUAL;
807            case JCTree.GE:                // >=
808                return Tree.Kind.GREATER_THAN_EQUAL;
809    
810            // Equality operators
811            case JCTree.EQ:                // ==
812                return Tree.Kind.EQUAL_TO;
813            case JCTree.NE:                // !=
814                return Tree.Kind.NOT_EQUAL_TO;
815    
816            // Bitwise and logical operators
817            case JCTree.BITAND:            // &
818                return Tree.Kind.AND;
819            case JCTree.BITXOR:            // ^
820                return Tree.Kind.XOR;
821            case JCTree.BITOR:             // |
822                return Tree.Kind.OR;
823    
824            // Conditional operators
825            case JCTree.AND:               // &&
826                return Tree.Kind.CONDITIONAL_AND;
827            case JCTree.OR:                // ||
828                return Tree.Kind.CONDITIONAL_OR;
829    
830            // Assignment operators
831            case JCTree.MUL_ASG:           // *=
832                return Tree.Kind.MULTIPLY_ASSIGNMENT;
833            case JCTree.DIV_ASG:           // /=
834                return Tree.Kind.DIVIDE_ASSIGNMENT;
835            case JCTree.MOD_ASG:           // %=
836                return Tree.Kind.REMAINDER_ASSIGNMENT;
837            case JCTree.PLUS_ASG:          // +=
838                return Tree.Kind.PLUS_ASSIGNMENT;
839            case JCTree.MINUS_ASG:         // -=
840                return Tree.Kind.MINUS_ASSIGNMENT;
841            case JCTree.SL_ASG:            // <<=
842                return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
843            case JCTree.SR_ASG:            // >>=
844                return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
845            case JCTree.USR_ASG:           // >>>=
846                return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
847            case JCTree.BITAND_ASG:        // &=
848                return Tree.Kind.AND_ASSIGNMENT;
849            case JCTree.BITXOR_ASG:        // ^=
850                return Tree.Kind.XOR_ASSIGNMENT;
851            case JCTree.BITOR_ASG:         // |=
852                return Tree.Kind.OR_ASSIGNMENT;
853    
854            // Null check (implementation detail), for example, __.getClass()
855            case JCTree.NULLCHK:
856                return Tree.Kind.OTHER;
857    
858            default:
859                return null;
860            }
861        }
862    }