DPrinter.java revision 3560:bbf4cfc235bd
1/*
2 * Copyright (c) 2013, 2016, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/* @test
25 * @bug 8043484 8007307
26 * @summary Make sure DPrinter.java compiles
27 * @modules jdk.compiler/com.sun.tools.javac.api
28 *          jdk.compiler/com.sun.tools.javac.code
29 *          jdk.compiler/com.sun.tools.javac.tree
30 *          jdk.compiler/com.sun.tools.javac.util
31 * @compile DPrinter.java
32 */
33
34import java.io.File;
35import java.io.IOException;
36import java.io.PrintWriter;
37import java.lang.reflect.Field;
38import java.lang.reflect.Method;
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.Collection;
42import java.util.EnumSet;
43import java.util.HashMap;
44import java.util.List;
45import java.util.Locale;
46import java.util.Map;
47import java.util.Set;
48
49import javax.lang.model.element.Name;
50import javax.lang.model.element.TypeElement;
51import javax.tools.FileObject;
52import javax.tools.JavaCompiler;
53import javax.tools.JavaFileObject;
54import javax.tools.StandardJavaFileManager;
55import javax.tools.StandardLocation;
56import javax.tools.ToolProvider;
57
58import com.sun.source.doctree.*;
59import com.sun.source.util.JavacTask;
60import com.sun.source.util.TaskEvent;
61import com.sun.source.util.TaskListener;
62import com.sun.source.util.Trees;
63import com.sun.tools.javac.api.JavacTrees;
64import com.sun.tools.javac.code.SymbolMetadata;
65import com.sun.tools.javac.code.Attribute;
66import com.sun.tools.javac.code.Flags;
67import com.sun.tools.javac.code.Kinds;
68import com.sun.tools.javac.code.Printer;
69import com.sun.tools.javac.code.Scope;
70import com.sun.tools.javac.code.Scope.CompoundScope;
71import com.sun.tools.javac.code.Symbol;
72import com.sun.tools.javac.code.Symbol.*;
73import com.sun.tools.javac.code.Type;
74import com.sun.tools.javac.code.Type.*;
75import com.sun.tools.javac.code.TypeTag;
76import com.sun.tools.javac.tree.JCTree;
77import com.sun.tools.javac.tree.JCTree.*;
78import com.sun.tools.javac.tree.Pretty;
79import com.sun.tools.javac.tree.TreeInfo;
80import com.sun.tools.javac.tree.TreeScanner;
81import com.sun.tools.javac.util.Assert;
82import com.sun.tools.javac.util.Context;
83import com.sun.tools.javac.util.Convert;
84import com.sun.tools.javac.util.Log;
85
86
87/**
88 * Debug printer for javac internals, for when toString() just isn't enough.
89 *
90 * <p>
91 * The printer provides an API to generate structured views of javac objects,
92 * such as AST nodes, symbol, types and annotations. Various aspects of the
93 * output can be configured, such as whether to show nulls, empty lists, or
94 * a compressed representation of the source code. Visitors are used to walk
95 * object hierarchies, and can be replaced with custom visitors if the default
96 * visitors are not flexible enough.
97 *
98 * <p>
99 * In general, nodes are printed with an initial line identifying the node
100 * followed by indented lines for the child nodes. Currently, graphs are
101 * represented by printing a spanning subtree.
102 *
103 * <p>
104 * The printer can be accessed via a simple command-line utility,
105 * which makes it easy to see the internal representation of source code,
106 * such as simple test programs, during the compilation pipeline.
107 *
108 *  <p><b>This is NOT part of any supported API.
109 *  If you write code that depends on this, you do so at your own risk.
110 *  This code and its internal interfaces are subject to change or
111 *  deletion without notice.</b>
112 */
113
114public class DPrinter {
115    protected final PrintWriter out;
116    protected final Trees trees;
117    protected Printer printer;
118    protected boolean showEmptyItems = true;
119    protected boolean showNulls = true;
120    protected boolean showPositions = false;
121    protected boolean showSrc;
122    protected boolean showTreeSymbols;
123    protected boolean showTreeTypes;
124    protected int maxSrcLength = 32;
125    protected Locale locale = Locale.getDefault();
126    protected static final String NULL = "#null";
127
128    // <editor-fold defaultstate="collapsed" desc="Configuration">
129
130    public static DPrinter instance(Context context) {
131        DPrinter dp = context.get(DPrinter.class);
132        if (dp == null) {
133            dp = new DPrinter(context);
134        }
135        return dp;
136
137    }
138
139    protected DPrinter(Context context) {
140        context.put(DPrinter.class, this);
141        out = context.get(Log.logKey).getWriter(Log.WriterKind.STDERR);
142        trees = JavacTrees.instance(context);
143    }
144
145    public DPrinter(PrintWriter out, Trees trees) {
146        this.out = out;
147        this.trees = trees;
148    }
149
150    public DPrinter emptyItems(boolean showEmptyItems) {
151        this.showEmptyItems = showEmptyItems;
152        return this;
153    }
154
155    public DPrinter nulls(boolean showNulls) {
156        this.showNulls = showNulls;
157        return this;
158    }
159
160    public DPrinter positions(boolean showPositions) {
161        this.showPositions = showPositions;
162        return this;
163    }
164
165    public DPrinter source(boolean showSrc) {
166        this.showSrc = showSrc;
167        return this;
168    }
169
170    public DPrinter source(int maxSrcLength) {
171        this.showSrc = true;
172        this.maxSrcLength = maxSrcLength;
173        return this;
174    }
175
176    public DPrinter treeSymbols(boolean showTreeSymbols) {
177        this.showTreeSymbols = showTreeSymbols;
178        return this;
179    }
180
181    public DPrinter treeTypes(boolean showTreeTypes) {
182        this.showTreeTypes = showTreeTypes;
183        return this;
184    }
185
186    public DPrinter typeSymbolPrinter(Printer p) {
187        printer = p;
188        return this;
189    }
190
191    // </editor-fold>
192
193    // <editor-fold defaultstate="collapsed" desc="Printing">
194
195    protected enum Details {
196        /** A one-line non-recursive summary */
197        SUMMARY,
198        /** Multi-line, possibly recursive. */
199        FULL
200    };
201
202    public void printAnnotations(String label, SymbolMetadata annotations) {
203        printAnnotations(label, annotations, Details.FULL);
204    }
205
206    protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
207        if (annotations == null) {
208            printNull(label);
209        } else {
210            // no SUMMARY format currently available to use
211
212            // use reflection to get at private fields
213            Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
214            Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
215            Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
216            Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
217
218            if (!showEmptyItems) {
219                if (attributes instanceof List && ((List) attributes).isEmpty()
220                        && attributes != DECL_NOT_STARTED
221                        && attributes != DECL_IN_PROGRESS
222                        && type_attributes instanceof List && ((List) type_attributes).isEmpty())
223                    return;
224            }
225
226            printString(label, hashString(annotations));
227
228            indent(+1);
229            if (attributes == DECL_NOT_STARTED)
230                printString("attributes", "DECL_NOT_STARTED");
231            else if (attributes == DECL_IN_PROGRESS)
232                printString("attributes", "DECL_IN_PROGRESS");
233            else if (attributes instanceof List)
234                printList("attributes", (List) attributes);
235            else
236                printObject("attributes", attributes, Details.SUMMARY);
237
238            if (attributes instanceof List)
239                printList("type_attributes", (List) type_attributes);
240            else
241                printObject("type_attributes", type_attributes, Details.SUMMARY);
242            indent(-1);
243        }
244    }
245
246    public void printAttribute(String label, Attribute attr) {
247        if (attr == null) {
248            printNull(label);
249        } else {
250            printString(label, attr.getClass().getSimpleName());
251
252            indent(+1);
253            attr.accept(attrVisitor);
254            indent(-1);
255        }
256    }
257
258    public void printDocTree(String label, DocTree tree) {
259        if (tree == null) {
260             printNull(label);
261        } else {
262            indent();
263            out.print(label);
264            out.println(": " + tree.getClass().getSimpleName() + "," + tree.getKind());
265
266            indent(+1);
267            tree.accept(docTreeVisitor, null);
268            indent(-1);
269        }
270    }
271
272    public void printFileObject(String label, FileObject fo) {
273        if (fo == null) {
274            printNull(label);
275        } else {
276            printString(label, fo.getName());
277        }
278    }
279
280    protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
281        if (item.getClass() != stdImplClass)
282            printString("impl", item.getClass().getName());
283    }
284
285    public void printInt(String label, int i) {
286        printString(label, String.valueOf(i));
287    }
288
289    public void printLimitedEscapedString(String label, String text) {
290        String s = Convert.quote(text);
291        if (s.length() > maxSrcLength) {
292            String trim = "[...]";
293            int head = (maxSrcLength - trim.length()) * 2 / 3;
294            int tail = maxSrcLength - trim.length() - head;
295            s = s.substring(0, head) + trim + s.substring(s.length() - tail);
296        }
297        printString(label, s);
298    }
299
300    public void printList(String label, List<?> list) {
301        if (list == null) {
302             printNull(label);
303        } else if (!list.isEmpty() || showEmptyItems) {
304            printString(label, "[" + list.size() + "]");
305
306            indent(+1);
307            int i = 0;
308            for (Object item: list) {
309                printObject(String.valueOf(i++), item, Details.FULL);
310            }
311            indent(-1);
312        }
313    }
314
315    public void printName(String label, Name name) {
316        if (name == null) {
317            printNull(label);
318        } else {
319            printString(label, name.toString());
320        }
321    }
322
323    public void printNull(String label) {
324        if (showNulls)
325            printString(label, NULL);
326    }
327
328    protected void printObject(String label, Object item, Details details) {
329        if (item == null) {
330            printNull(label);
331        } else if (item instanceof Attribute) {
332            printAttribute(label, (Attribute) item);
333        } else if (item instanceof Symbol) {
334            printSymbol(label, (Symbol) item, details);
335        } else if (item instanceof Type) {
336            printType(label, (Type) item, details);
337        } else if (item instanceof JCTree) {
338            printTree(label, (JCTree) item);
339        } else if (item instanceof DocTree) {
340            printDocTree(label, (DocTree) item);
341        } else if (item instanceof List) {
342            printList(label, (List) item);
343        } else if (item instanceof Name) {
344            printName(label, (Name) item);
345        } else if (item instanceof Scope) {
346            printScope(label, (Scope) item);
347        } else {
348            printString(label, String.valueOf(item));
349        }
350    }
351
352    public void printScope(String label, Scope scope) {
353        printScope(label, scope, Details.FULL);
354    }
355
356    public void printScope(String label, Scope scope, Details details) {
357        if (scope == null) {
358            printNull(label);
359        } else {
360            switch (details) {
361                case SUMMARY: {
362                    indent();
363                    out.print(label);
364                    out.print(": [");
365                    String sep = "";
366                    for (Symbol sym: scope.getSymbols()) {
367                        out.print(sep);
368                        out.print(sym.name);
369                        sep = ",";
370                    }
371                    out.println("]");
372                    break;
373                }
374
375                case FULL: {
376                    indent();
377                    out.println(label);
378
379                    indent(+1);
380                    printFullScopeImpl(scope);
381                    indent(-1);
382                    break;
383                }
384            }
385        }
386    }
387
388    void printFullScopeImpl(Scope scope) {
389        indent();
390        out.println(scope.getClass().getName());
391        printSymbol("owner", scope.owner, Details.SUMMARY);
392        if (SCOPE_IMPL_CLASS.equals(scope.getClass().getName())) {
393            printScope("next", (Scope) getField(scope, scope.getClass(), "next"), Details.SUMMARY);
394            printObject("shared", getField(scope, scope.getClass(), "shared"), Details.SUMMARY);
395            Object[] table = (Object[]) getField(scope, scope.getClass(), "table");
396            for (int i = 0; i < table.length; i++) {
397                if (i > 0)
398                    out.print(", ");
399                else
400                    indent();
401                out.print(i + ":" + entryToString(table[i], table, false));
402            }
403            out.println();
404        } else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) {
405            printScope("origin",
406                    (Scope) getField(scope, scope.getClass(), "origin"), Details.FULL);
407        } else if (scope instanceof CompoundScope) {
408            printList("delegates", (List<?>) getField(scope, CompoundScope.class, "subScopes"));
409        } else {
410            for (Symbol sym : scope.getSymbols()) {
411                printSymbol(sym.name.toString(), sym, Details.SUMMARY);
412            }
413        }
414    }
415        //where:
416        static final String SCOPE_IMPL_CLASS = "com.sun.tools.javac.code.Scope$ScopeImpl";
417        static final String FILTER_SCOPE_CLASS = "com.sun.tools.javac.code.Scope$FilterImportScope";
418
419    /**
420     * Create a string showing the contents of an entry, using the table
421     * to help identify cross-references to other entries in the table.
422     * @param e the entry to be shown
423     * @param table the table containing the other entries
424     */
425    String entryToString(Object e, Object[] table, boolean ref) {
426        if (e == null)
427            return "null";
428        Symbol sym = (Symbol) getField(e, e.getClass(), "sym");
429        if (sym == null)
430            return "sent"; // sentinel
431        if (ref) {
432            int index = indexOf(table, e);
433            if (index != -1)
434                return String.valueOf(index);
435        }
436        Scope scope = (Scope) getField(e, e.getClass(), "scope");
437        return "(" + sym.name + ":" + sym
438                + ",shdw:" + entryToString(callMethod(e, e.getClass(), "next"), table, true)
439                + ",sibl:" + entryToString(getField(e, e.getClass(), "sibling"), table, true)
440                + ((sym.owner != scope.owner)
441                    ? (",BOGUS[" + sym.owner + "," + scope.owner + "]")
442                    : "")
443                + ")";
444    }
445
446    <T> int indexOf(T[] array, T item) {
447        for (int i = 0; i < array.length; i++) {
448            if (array[i] == item)
449                return i;
450        }
451        return -1;
452    }
453
454    public void printSource(String label, JCTree tree) {
455        printString(label, Pretty.toSimpleString(tree, maxSrcLength));
456    }
457
458    public void printString(String label, String text) {
459        indent();
460        out.print(label);
461        out.print(": ");
462        out.print(text);
463        out.println();
464    }
465
466    public void printSymbol(String label, Symbol symbol) {
467        printSymbol(label, symbol, Details.FULL);
468    }
469
470    protected void printSymbol(String label, Symbol sym, Details details) {
471        if (sym == null) {
472            printNull(label);
473        } else {
474            switch (details) {
475            case SUMMARY:
476                printString(label, toString(sym));
477                break;
478
479            case FULL:
480                indent();
481                out.print(label);
482                out.println(": " +
483                        info(sym.getClass(),
484                            String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
485                            sym.getKind())
486                        + " " + sym.name
487                        + " " + hashString(sym));
488
489                indent(+1);
490                if (showSrc) {
491                    JCTree tree = (JCTree) trees.getTree(sym);
492                    if (tree != null)
493                        printSource("src", tree);
494                }
495                printString("flags", String.format("0x%x--%s",
496                        sym.flags_field, Flags.toString(sym.flags_field)));
497                printObject("completer", sym.completer, Details.SUMMARY); // what if too long?
498                printSymbol("owner", sym.owner, Details.SUMMARY);
499                printType("type", sym.type, Details.SUMMARY);
500                printType("erasure", sym.erasure_field, Details.SUMMARY);
501                sym.accept(symVisitor, null);
502                printAnnotations("annotations", sym.getMetadata(), Details.SUMMARY);
503                indent(-1);
504            }
505        }
506    }
507
508    protected String toString(Symbol sym) {
509        return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
510    }
511
512    protected void printTree(String label, JCTree tree) {
513        if (tree == null) {
514            printNull(label);
515        } else {
516            indent();
517            String ext;
518            try {
519                ext = tree.getKind().name();
520            } catch (Throwable t) {
521                ext = "n/a";
522            }
523            out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
524            if (showPositions) {
525                // We can always get start position, but to get end position
526                // and/or line+offset, we would need a JCCompilationUnit
527                out.print(" pos:" + tree.pos);
528            }
529            if (showTreeTypes && tree.type != null)
530                out.print(" type:" + toString(tree.type));
531            Symbol sym;
532            if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
533                out.print(" sym:" + toString(sym));
534            out.println();
535
536            indent(+1);
537            if (showSrc) {
538                indent();
539                out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
540            }
541            tree.accept(treeVisitor);
542            indent(-1);
543        }
544    }
545
546    public void printType(String label, Type type) {
547        printType(label, type, Details.FULL);
548    }
549
550    protected void printType(String label, Type type, Details details) {
551        if (type == null)
552            printNull(label);
553        else {
554            switch (details) {
555                case SUMMARY:
556                    printString(label, toString(type));
557                    break;
558
559                case FULL:
560                    indent();
561                    out.print(label);
562                    out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
563                            + " " + hashString(type));
564
565                    indent(+1);
566                    printSymbol("tsym", type.tsym, Details.SUMMARY);
567                    printObject("constValue", type.constValue(), Details.SUMMARY);
568                    printObject("annotations", type.getAnnotationMirrors(), Details.SUMMARY);
569                    type.accept(typeVisitor, null);
570                    indent(-1);
571            }
572        }
573    }
574
575    protected String toString(Type type) {
576        return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
577    }
578
579    protected String hashString(Object obj) {
580        return String.format("#%x", obj.hashCode());
581    }
582
583    protected String info(Class<?> clazz, Object internal, Object external) {
584        return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
585    }
586
587    private int indent = 0;
588
589    protected void indent() {
590        for (int i = 0; i < indent; i++) {
591            out.print("  ");
592        }
593    }
594
595    protected void indent(int n) {
596        indent += n;
597    }
598
599    protected Object getField(Object o, Class<?> clazz, String name) {
600        try {
601            Field f = clazz.getDeclaredField(name);
602            boolean prev = f.isAccessible();
603            f.setAccessible(true);
604            try {
605                return f.get(o);
606            } finally {
607                f.setAccessible(prev);
608            }
609        } catch (ReflectiveOperationException e) {
610            return e;
611        } catch (SecurityException e) {
612            return e;
613        }
614    }
615
616    protected Object callMethod(Object o, Class<?> clazz, String name) {
617        try {
618            Method m = clazz.getDeclaredMethod(name);
619            boolean prev = m.isAccessible();
620            m.setAccessible(true);
621            try {
622                return m.invoke(o);
623            } finally {
624                m.setAccessible(prev);
625            }
626        } catch (ReflectiveOperationException e) {
627            return e;
628        } catch (SecurityException e) {
629            return e;
630        }
631    }
632
633    // </editor-fold>
634
635    // <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
636
637    protected JCTree.Visitor treeVisitor = new TreeVisitor();
638
639    /**
640     * Default visitor class for JCTree (AST) objects.
641     */
642    public class TreeVisitor extends JCTree.Visitor {
643        @Override
644        public void visitTopLevel(JCCompilationUnit tree) {
645            printList("packageAnnotations", tree.getPackageAnnotations());
646            printList("defs", tree.defs);
647        }
648
649        @Override
650        public void visitPackageDef(JCPackageDecl tree) {
651            printTree("pid", tree.pid);
652        }
653
654        @Override
655        public void visitImport(JCImport tree) {
656            printTree("qualid", tree.qualid);
657        }
658
659        @Override
660        public void visitClassDef(JCClassDecl tree) {
661            printName("name", tree.name);
662            printTree("mods", tree.mods);
663            printList("typarams", tree.typarams);
664            printTree("extending", tree.extending);
665            printList("implementing", tree.implementing);
666            printList("defs", tree.defs);
667        }
668
669        @Override
670        public void visitMethodDef(JCMethodDecl tree) {
671            printName("name", tree.name);
672            printTree("mods", tree.mods);
673            printTree("restype", tree.restype);
674            printList("typarams", tree.typarams);
675            printTree("recvparam", tree.recvparam);
676            printList("params", tree.params);
677            printList("thrown", tree.thrown);
678            printTree("defaultValue", tree.defaultValue);
679            printTree("body", tree.body);
680        }
681
682        @Override
683        public void visitVarDef(JCVariableDecl tree) {
684            printName("name", tree.name);
685            printTree("mods", tree.mods);
686            printTree("vartype", tree.vartype);
687            printTree("init", tree.init);
688        }
689
690        @Override
691        public void visitSkip(JCSkip tree) {
692        }
693
694        @Override
695        public void visitBlock(JCBlock tree) {
696            printList("stats", tree.stats);
697        }
698
699        @Override
700        public void visitDoLoop(JCDoWhileLoop tree) {
701            printTree("body", tree.body);
702            printTree("cond", tree.cond);
703        }
704
705        @Override
706        public void visitWhileLoop(JCWhileLoop tree) {
707            printTree("cond", tree.cond);
708            printTree("body", tree.body);
709        }
710
711        @Override
712        public void visitForLoop(JCForLoop tree) {
713            printList("init", tree.init);
714            printTree("cond", tree.cond);
715            printList("step", tree.step);
716            printTree("body", tree.body);
717        }
718
719        @Override
720        public void visitForeachLoop(JCEnhancedForLoop tree) {
721            printTree("var", tree.var);
722            printTree("expr", tree.expr);
723            printTree("body", tree.body);
724        }
725
726        @Override
727        public void visitLabelled(JCLabeledStatement tree) {
728            printTree("body", tree.body);
729        }
730
731        @Override
732        public void visitSwitch(JCSwitch tree) {
733            printTree("selector", tree.selector);
734            printList("cases", tree.cases);
735        }
736
737        @Override
738        public void visitCase(JCCase tree) {
739            printTree("pat", tree.pat);
740            printList("stats", tree.stats);
741        }
742
743        @Override
744        public void visitSynchronized(JCSynchronized tree) {
745            printTree("lock", tree.lock);
746            printTree("body", tree.body);
747        }
748
749        @Override
750        public void visitTry(JCTry tree) {
751            printList("resources", tree.resources);
752            printTree("body", tree.body);
753            printList("catchers", tree.catchers);
754            printTree("finalizer", tree.finalizer);
755        }
756
757        @Override
758        public void visitCatch(JCCatch tree) {
759            printTree("param", tree.param);
760            printTree("body", tree.body);
761        }
762
763        @Override
764        public void visitConditional(JCConditional tree) {
765            printTree("cond", tree.cond);
766            printTree("truepart", tree.truepart);
767            printTree("falsepart", tree.falsepart);
768        }
769
770        @Override
771        public void visitIf(JCIf tree) {
772            printTree("cond", tree.cond);
773            printTree("thenpart", tree.thenpart);
774            printTree("elsepart", tree.elsepart);
775        }
776
777        @Override
778        public void visitExec(JCExpressionStatement tree) {
779            printTree("expr", tree.expr);
780        }
781
782        @Override
783        public void visitBreak(JCBreak tree) {
784            printName("label", tree.label);
785        }
786
787        @Override
788        public void visitContinue(JCContinue tree) {
789            printName("label", tree.label);
790        }
791
792        @Override
793        public void visitReturn(JCReturn tree) {
794            printTree("expr", tree.expr);
795        }
796
797        @Override
798        public void visitThrow(JCThrow tree) {
799            printTree("expr", tree.expr);
800        }
801
802        @Override
803        public void visitAssert(JCAssert tree) {
804            printTree("cond", tree.cond);
805            printTree("detail", tree.detail);
806        }
807
808        @Override
809        public void visitApply(JCMethodInvocation tree) {
810            printList("typeargs", tree.typeargs);
811            printTree("meth", tree.meth);
812            printList("args", tree.args);
813        }
814
815        @Override
816        public void visitNewClass(JCNewClass tree) {
817            printTree("encl", tree.encl);
818            printList("typeargs", tree.typeargs);
819            printTree("clazz", tree.clazz);
820            printList("args", tree.args);
821            printTree("def", tree.def);
822        }
823
824        @Override
825        public void visitNewArray(JCNewArray tree) {
826            printList("annotations", tree.annotations);
827            printTree("elemtype", tree.elemtype);
828            printList("dims", tree.dims);
829            printList("dimAnnotations", tree.dimAnnotations);
830            printList("elems", tree.elems);
831        }
832
833        @Override
834        public void visitLambda(JCLambda tree) {
835            printTree("body", tree.body);
836            printList("params", tree.params);
837        }
838
839        @Override
840        public void visitParens(JCParens tree) {
841            printTree("expr", tree.expr);
842        }
843
844        @Override
845        public void visitAssign(JCAssign tree) {
846            printTree("lhs", tree.lhs);
847            printTree("rhs", tree.rhs);
848        }
849
850        @Override
851        public void visitAssignop(JCAssignOp tree) {
852            printTree("lhs", tree.lhs);
853            printTree("rhs", tree.rhs);
854        }
855
856        @Override
857        public void visitUnary(JCUnary tree) {
858            printTree("arg", tree.arg);
859        }
860
861        @Override
862        public void visitBinary(JCBinary tree) {
863            printTree("lhs", tree.lhs);
864            printTree("rhs", tree.rhs);
865        }
866
867        @Override
868        public void visitTypeCast(JCTypeCast tree) {
869            printTree("clazz", tree.clazz);
870            printTree("expr", tree.expr);
871        }
872
873        @Override
874        public void visitTypeTest(JCInstanceOf tree) {
875            printTree("expr", tree.expr);
876            printTree("clazz", tree.clazz);
877        }
878
879        @Override
880        public void visitIndexed(JCArrayAccess tree) {
881            printTree("indexed", tree.indexed);
882            printTree("index", tree.index);
883        }
884
885        @Override
886        public void visitSelect(JCFieldAccess tree) {
887            printTree("selected", tree.selected);
888        }
889
890        @Override
891        public void visitReference(JCMemberReference tree) {
892            printTree("expr", tree.expr);
893            printList("typeargs", tree.typeargs);
894        }
895
896        @Override
897        public void visitIdent(JCIdent tree) {
898            printName("name", tree.name);
899        }
900
901        @Override
902        public void visitLiteral(JCLiteral tree) {
903            printString("value", Pretty.toSimpleString(tree, 32));
904        }
905
906        @Override
907        public void visitTypeIdent(JCPrimitiveTypeTree tree) {
908            printString("typetag", tree.typetag.name());
909        }
910
911        @Override
912        public void visitTypeArray(JCArrayTypeTree tree) {
913            printTree("elemtype", tree.elemtype);
914        }
915
916        @Override
917        public void visitTypeApply(JCTypeApply tree) {
918            printTree("clazz", tree.clazz);
919            printList("arguments", tree.arguments);
920        }
921
922        @Override
923        public void visitTypeUnion(JCTypeUnion tree) {
924            printList("alternatives", tree.alternatives);
925        }
926
927        @Override
928        public void visitTypeIntersection(JCTypeIntersection tree) {
929            printList("bounds", tree.bounds);
930        }
931
932        @Override
933        public void visitTypeParameter(JCTypeParameter tree) {
934            printName("name", tree.name);
935            printList("annotations", tree.annotations);
936            printList("bounds", tree.bounds);
937        }
938
939        @Override
940        public void visitWildcard(JCWildcard tree) {
941            printTree("kind", tree.kind);
942            printTree("inner", tree.inner);
943        }
944
945        @Override
946        public void visitTypeBoundKind(TypeBoundKind tree) {
947            printString("kind", tree.kind.name());
948        }
949
950        @Override
951        public void visitModifiers(JCModifiers tree) {
952            printList("annotations", tree.annotations);
953            printString("flags", String.valueOf(Flags.asFlagSet(tree.flags)));
954        }
955
956        @Override
957        public void visitAnnotation(JCAnnotation tree) {
958            printTree("annotationType", tree.annotationType);
959            printList("args", tree.args);
960        }
961
962        @Override
963        public void visitAnnotatedType(JCAnnotatedType tree) {
964            printList("annotations", tree.annotations);
965            printTree("underlyingType", tree.underlyingType);
966        }
967
968        @Override
969        public void visitErroneous(JCErroneous tree) {
970            printList("errs", tree.errs);
971        }
972
973        @Override
974        public void visitLetExpr(LetExpr tree) {
975            printList("defs", tree.defs);
976            printTree("expr", tree.expr);
977        }
978
979        @Override
980        public void visitTree(JCTree tree) {
981            Assert.error();
982        }
983    }
984
985    // </editor-fold>
986
987    // <editor-fold defaultstate="collapsed" desc="DocTree visitor">
988
989    protected DocTreeVisitor<Void,Void> docTreeVisitor = new DefaultDocTreeVisitor();
990
991    /**
992     * Default visitor class for DocTree objects.
993     * Note: each visitXYZ method ends by calling the corresponding
994     * visit method for its superclass.
995     */
996    class DefaultDocTreeVisitor implements DocTreeVisitor<Void,Void> {
997
998        public Void visitAttribute(AttributeTree node, Void p) {
999            printName("name", node.getName());
1000            printString("vkind", node.getValueKind().name());
1001            printList("value", node.getValue());
1002            return visitTree(node, null);
1003        }
1004
1005        public Void visitAuthor(AuthorTree node, Void p) {
1006            printList("name", node.getName());
1007            return visitBlockTag(node, null);
1008        }
1009
1010        public Void visitComment(CommentTree node, Void p) {
1011            printLimitedEscapedString("body", node.getBody());
1012            return visitTree(node, null);
1013        }
1014
1015        public Void visitDeprecated(DeprecatedTree node, Void p) {
1016            printList("body", node.getBody());
1017            return visitBlockTag(node, null);
1018        }
1019
1020        public Void visitDocComment(DocCommentTree node, Void p) {
1021            printList("firstSentence", node.getFirstSentence());
1022            printList("body", node.getBody());
1023            printList("tags", node.getBlockTags());
1024            return visitTree(node, null);
1025        }
1026
1027        public Void visitDocRoot(DocRootTree node, Void p) {
1028            return visitInlineTag(node, null);
1029        }
1030
1031        public Void visitEndElement(EndElementTree node, Void p) {
1032            printName("name", node.getName());
1033            return visitTree(node, null);
1034        }
1035
1036        public Void visitEntity(EntityTree node, Void p) {
1037            printName("name", node.getName());
1038            return visitTree(node, null);
1039        }
1040
1041        public Void visitErroneous(ErroneousTree node, Void p) {
1042            printLimitedEscapedString("body", node.getBody());
1043            printString("diag", node.getDiagnostic().getMessage(Locale.getDefault()));
1044            return visitTree(node, null);
1045        }
1046
1047        public Void visitHidden(HiddenTree node, Void p) {
1048            printList("body", node.getBody());
1049            return visitBlockTag(node, null);
1050        }
1051
1052        public Void visitIdentifier(IdentifierTree node, Void p) {
1053            printName("name", node.getName());
1054            return visitTree(node, null);
1055        }
1056
1057        public Void visitIndex(IndexTree node, Void p) {
1058            printString("kind", node.getKind().name());
1059            printDocTree("term", node.getSearchTerm());
1060            printList("desc", node.getDescription());
1061            return visitInlineTag(node, p);
1062        }
1063
1064        public Void visitInheritDoc(InheritDocTree node, Void p) {
1065            return visitInlineTag(node, null);
1066        }
1067
1068        public Void visitLink(LinkTree node, Void p) {
1069            printString("kind", node.getKind().name());
1070            printDocTree("ref", node.getReference());
1071            printList("list", node.getLabel());
1072            return visitInlineTag(node, null);
1073        }
1074
1075        public Void visitLiteral(LiteralTree node, Void p) {
1076            printString("kind", node.getKind().name());
1077            printDocTree("body", node.getBody());
1078            return visitInlineTag(node, null);
1079        }
1080
1081        public Void visitParam(ParamTree node, Void p) {
1082            printString("isTypeParameter", String.valueOf(node.isTypeParameter()));
1083            printString("kind", node.getKind().name());
1084            printList("desc", node.getDescription());
1085            return visitBlockTag(node, null);
1086        }
1087
1088        public Void visitReference(ReferenceTree node, Void p) {
1089            printString("signature", node.getSignature());
1090            return visitTree(node, null);
1091        }
1092
1093        public Void visitReturn(ReturnTree node, Void p) {
1094            printList("desc", node.getDescription());
1095            return visitBlockTag(node, null);
1096        }
1097
1098        public Void visitSee(SeeTree node, Void p) {
1099            printList("ref", node.getReference());
1100            return visitBlockTag(node, null);
1101        }
1102
1103        public Void visitSerial(SerialTree node, Void p) {
1104            printList("desc", node.getDescription());
1105            return visitBlockTag(node, null);
1106        }
1107
1108        public Void visitSerialData(SerialDataTree node, Void p) {
1109            printList("desc", node.getDescription());
1110            return visitBlockTag(node, null);
1111        }
1112
1113        public Void visitSerialField(SerialFieldTree node, Void p) {
1114            printDocTree("name", node.getName());
1115            printDocTree("type", node.getType());
1116            printList("desc", node.getDescription());
1117            return visitBlockTag(node, null);
1118        }
1119
1120        public Void visitSince(SinceTree node, Void p) {
1121            printList("body", node.getBody());
1122            return visitBlockTag(node, null);
1123        }
1124
1125        public Void visitStartElement(StartElementTree node, Void p) {
1126            printName("name", node.getName());
1127            printList("attrs", node.getAttributes());
1128            printString("selfClosing", String.valueOf(node.isSelfClosing()));
1129            return visitBlockTag(node, null);
1130        }
1131
1132        public Void visitText(TextTree node, Void p) {
1133            printLimitedEscapedString("body", node.getBody());
1134            return visitTree(node, null);
1135        }
1136
1137        public Void visitThrows(ThrowsTree node, Void p) {
1138            printDocTree("name", node.getExceptionName());
1139            printList("desc", node.getDescription());
1140            return visitBlockTag(node, null);
1141        }
1142
1143        public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
1144            printString("name", node.getTagName());
1145            printList("content", node.getContent());
1146            return visitBlockTag(node, null);
1147        }
1148
1149        public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
1150            printString("name", node.getTagName());
1151            printList("content", node.getContent());
1152            return visitInlineTag(node, null);
1153        }
1154
1155        public Void visitValue(ValueTree node, Void p) {
1156            printDocTree("value", node.getReference());
1157            return visitInlineTag(node, null);
1158        }
1159
1160        public Void visitVersion(VersionTree node, Void p) {
1161            printList("body", node.getBody());
1162            return visitBlockTag(node, null);
1163        }
1164
1165        public Void visitOther(DocTree node, Void p) {
1166            return visitTree(node, null);
1167        }
1168
1169        public Void visitBlockTag(DocTree node, Void p) {
1170            return visitTree(node, null);
1171        }
1172
1173        public Void visitInlineTag(DocTree node, Void p) {
1174            return visitTree(node, null);
1175        }
1176
1177        public Void visitTree(DocTree node, Void p) {
1178            return null;
1179        }
1180    }
1181
1182    // </editor-fold>
1183
1184    // <editor-fold defaultstate="collapsed" desc="Symbol visitor">
1185
1186    protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
1187
1188    /**
1189     * Default visitor class for Symbol objects.
1190     * Note: each visitXYZ method ends by calling the corresponding
1191     * visit method for its superclass.
1192     */
1193    class SymbolVisitor implements Symbol.Visitor<Void,Void> {
1194        @Override
1195        public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
1196            printName("fullname", sym.fullname);
1197            printName("flatname", sym.flatname);
1198            printScope("members", sym.members_field);
1199            printFileObject("sourcefile", sym.sourcefile);
1200            printFileObject("classfile", sym.classfile);
1201            // trans-local?
1202            // pool?
1203            return visitTypeSymbol(sym, null);
1204        }
1205
1206        @Override
1207        public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
1208            // code
1209            printList("params", sym.params);
1210            printList("savedParameterNames", sym.savedParameterNames);
1211            return visitSymbol(sym, null);
1212        }
1213
1214        @Override
1215        public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
1216            printName("fullname", sym.fullname);
1217            printScope("members", sym.members_field);
1218            printSymbol("package-info", sym.package_info, Details.SUMMARY);
1219            return visitTypeSymbol(sym, null);
1220        }
1221
1222        @Override
1223        public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
1224            printInt("opcode", sym.opcode);
1225            return visitMethodSymbol(sym, null);
1226        }
1227
1228        @Override
1229        public Void visitVarSymbol(VarSymbol sym, Void ignore) {
1230            printInt("pos", sym.pos);
1231            printInt("adm", sym.adr);
1232            // data is a private field, and the standard accessors may
1233            // mutate it as part of lazy evaluation. Therefore, use
1234            // reflection to get the raw data.
1235            printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
1236            return visitSymbol(sym, null);
1237        }
1238
1239        @Override
1240        public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
1241            return visitSymbol(sym, null);
1242        }
1243
1244        @Override
1245        public Void visitSymbol(Symbol sym, Void ignore) {
1246            return null;
1247        }
1248    }
1249
1250    // </editor-fold>
1251
1252    // <editor-fold defaultstate="collapsed" desc="Type visitor">
1253
1254    protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
1255
1256    /**
1257     * Default visitor class for Type objects.
1258     * Note: each visitXYZ method ends by calling the corresponding
1259     * visit method for its superclass.
1260     */
1261    public class TypeVisitor implements Type.Visitor<Void,Void> {
1262        public Void visitArrayType(ArrayType type, Void ignore) {
1263            printType("elemType", type.elemtype, Details.FULL);
1264            return visitType(type, null);
1265        }
1266
1267        public Void visitCapturedType(CapturedType type, Void ignore) {
1268            printType("wildcard", type.wildcard, Details.FULL);
1269            return visitTypeVar(type, null);
1270        }
1271
1272        public Void visitClassType(ClassType type, Void ignore) {
1273            printType("outer", type.getEnclosingType(), Details.SUMMARY);
1274            printList("typarams", type.typarams_field);
1275            printList("allparams", type.allparams_field);
1276            printType("supertype", type.supertype_field, Details.SUMMARY);
1277            printList("interfaces", type.interfaces_field);
1278            printList("allinterfaces", type.all_interfaces_field);
1279            return visitType(type, null);
1280        }
1281
1282        public Void visitErrorType(ErrorType type, Void ignore) {
1283            printType("originalType", type.getOriginalType(), Details.FULL);
1284            return visitClassType(type, null);
1285        }
1286
1287        public Void visitForAll(ForAll type, Void ignore) {
1288            printList("tvars", type.tvars);
1289            return visitDelegatedType(type);
1290        }
1291
1292        public Void visitMethodType(MethodType type, Void ignore) {
1293            printList("argtypes", type.argtypes);
1294            printType("restype", type.restype, Details.FULL);
1295            printList("thrown", type.thrown);
1296            printType("recvtype", type.recvtype, Details.FULL);
1297            return visitType(type, null);
1298        }
1299
1300        public Void visitModuleType(ModuleType type, Void ignore) {
1301            return visitType(type, null);
1302        }
1303
1304        public Void visitPackageType(PackageType type, Void ignore) {
1305            return visitType(type, null);
1306        }
1307
1308        public Void visitTypeVar(TypeVar type, Void ignore) {
1309            // For TypeVars (and not subtypes), the bound should always be
1310            // null or bot. So, only print the bound for subtypes of TypeVar,
1311            // or if the bound is (erroneously) not null or bot.
1312            if (!type.hasTag(TypeTag.TYPEVAR)
1313                    || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) {
1314                printType("bound", type.bound, Details.FULL);
1315            }
1316            printType("lower", type.lower, Details.FULL);
1317            return visitType(type, null);
1318        }
1319
1320        public Void visitUndetVar(UndetVar type, Void ignore) {
1321            for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1322                printList("bounds." + ib, type.getBounds(ib));
1323            printInt("declaredCount", type.declaredCount);
1324            printType("inst", type.getInst(), Details.SUMMARY);
1325            return visitDelegatedType(type);
1326        }
1327
1328        public Void visitWildcardType(WildcardType type, Void ignore) {
1329            printType("type", type.type, Details.SUMMARY);
1330            printString("kind", type.kind.name());
1331            printType("bound", type.bound, Details.SUMMARY);
1332            return visitType(type, null);
1333        }
1334
1335        protected Void visitDelegatedType(DelegatedType type) {
1336            printType("qtype", type.qtype, Details.FULL);
1337            return visitType(type, null);
1338        }
1339
1340        public Void visitType(Type type, Void ignore) {
1341            return null;
1342        }
1343    }
1344
1345    // </editor-fold>
1346
1347    // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1348
1349    protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1350
1351    /**
1352     * Default visitor class for Attribute (annotation) objects.
1353     */
1354    public class AttributeVisitor implements Attribute.Visitor {
1355
1356        public void visitConstant(Attribute.Constant a) {
1357            printObject("value", a.value, Details.SUMMARY);
1358            visitAttribute(a);
1359        }
1360
1361        public void visitClass(Attribute.Class a) {
1362            printObject("classType", a.classType, Details.SUMMARY);
1363            visitAttribute(a);
1364        }
1365
1366        public void visitCompound(Attribute.Compound a) {
1367            if (a instanceof Attribute.TypeCompound) {
1368                Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1369                // consider a custom printer?
1370                printObject("position", ta.position, Details.SUMMARY);
1371            }
1372            printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1373            printList("values", a.values);
1374            visitAttribute(a);
1375        }
1376
1377        public void visitArray(Attribute.Array a) {
1378            printList("values", Arrays.asList(a.values));
1379            visitAttribute(a);
1380        }
1381
1382        public void visitEnum(Attribute.Enum a) {
1383            printSymbol("value", a.value, Details.SUMMARY);
1384            visitAttribute(a);
1385        }
1386
1387        public void visitError(Attribute.Error a) {
1388            visitAttribute(a);
1389        }
1390
1391        public void visitAttribute(Attribute a) {
1392            printType("type", a.type, Details.SUMMARY);
1393        }
1394
1395    }
1396    // </editor-fold>
1397
1398    // <editor-fold defaultstate="collapsed" desc="Utility front end">
1399
1400    /**
1401     * Utility class to invoke DPrinter from the command line.
1402     */
1403    static class Main {
1404        public static void main(String... args) throws IOException {
1405            Main m = new Main();
1406            PrintWriter out = new PrintWriter(System.out);
1407            try {
1408                if (args.length == 0)
1409                    m.usage(out);
1410                else
1411                    m.run(out, args);
1412            } finally {
1413                out.flush();
1414            }
1415        }
1416
1417        void usage(PrintWriter out) {
1418            out.println("Usage:");
1419            out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
1420            out.print("where mode is one of: ");
1421            String sep = "";
1422            for (Handler h: getHandlers().values()) {
1423                out.print(sep);
1424                out.print(h.name);
1425                sep = ", ";
1426            }
1427            out.println();
1428            out.println("and where options include:");
1429            out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1430            out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1431            out.println("  -showPositions");
1432            out.println("  -showSource");
1433            out.println("  -showTreeSymbols");
1434            out.println("  -showTreeTypes");
1435            out.println("  -hideEmptyItems");
1436            out.println("  -hideNulls");
1437        }
1438
1439        void run(PrintWriter out, String... args) throws IOException {
1440            JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1441            StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1442
1443            // DPrinter options
1444            final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1445            final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1446            boolean showPositions = false;
1447            boolean showSource = false;
1448            boolean showTreeSymbols = false;
1449            boolean showTreeTypes = false;
1450            boolean showEmptyItems = true;
1451            boolean showNulls = true;
1452
1453            // javac options
1454            Collection<String> options = new ArrayList<String>();
1455            Collection<File> files = new ArrayList<File>();
1456            String classpath = null;
1457            String classoutdir = null;
1458
1459            final Handler h = getHandlers().get(args[0]);
1460            if (h == null)
1461                throw new IllegalArgumentException(args[0]);
1462
1463            for (int i = 1; i < args.length; i++) {
1464                String arg = args[i];
1465                if (arg.equals("-before") && i + 1 < args.length) {
1466                    before.add(getKind(args[++i]));
1467                } else if (arg.equals("-after") && i + 1 < args.length) {
1468                    after.add(getKind(args[++i]));
1469                } else if (arg.equals("-showPositions")) {
1470                    showPositions = true;
1471                } else if (arg.equals("-showSource")) {
1472                    showSource = true;
1473                } else if (arg.equals("-showTreeSymbols")) {
1474                    showTreeSymbols = true;
1475                } else if (arg.equals("-showTreeTypes")) {
1476                    showTreeTypes = true;
1477                } else if (arg.equals("-hideEmptyLists")) {
1478                    showEmptyItems = false;
1479                } else if (arg.equals("-hideNulls")) {
1480                    showNulls = false;
1481                } else if (arg.equals("-classpath") && i + 1 < args.length) {
1482                    classpath = args[++i];
1483                } else if (arg.equals("-d") && i + 1 < args.length) {
1484                    classoutdir = args[++i];
1485                } else if (arg.startsWith("-")) {
1486                    int n = c.isSupportedOption(arg);
1487                    if (n < 0) throw new IllegalArgumentException(arg);
1488                    options.add(arg);
1489                    while (n > 0) options.add(args[++i]);
1490                } else if (arg.endsWith(".java")) {
1491                    files.add(new File(arg));
1492                }
1493            }
1494
1495            if (classoutdir != null) {
1496                fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1497            }
1498
1499            if (classpath != null) {
1500                Collection<File> path = new ArrayList<File>();
1501                for (String p: classpath.split(File.pathSeparator)) {
1502                    if (p.isEmpty()) continue;
1503                    File f = new File(p);
1504                    if (f.exists()) path.add(f);
1505                }
1506                fm.setLocation(StandardLocation.CLASS_PATH, path);
1507            }
1508            Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1509
1510            JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1511            final Trees trees = Trees.instance(task);
1512
1513            final DPrinter dprinter = new DPrinter(out, trees);
1514            dprinter.source(showSource)
1515                    .emptyItems(showEmptyItems)
1516                    .nulls(showNulls)
1517                    .positions(showPositions)
1518                    .treeSymbols(showTreeSymbols)
1519                    .treeTypes(showTreeTypes);
1520
1521            if (before.isEmpty() && after.isEmpty()) {
1522                if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1523                    after.add(TaskEvent.Kind.PARSE);
1524                else
1525                    after.add(TaskEvent.Kind.ANALYZE);
1526            }
1527
1528            task.addTaskListener(new TaskListener() {
1529                public void started(TaskEvent e) {
1530                    if (before.contains(e.getKind()))
1531                        handle(e);
1532                }
1533
1534                public void finished(TaskEvent e) {
1535                    if (after.contains(e.getKind()))
1536                        handle(e);
1537                }
1538
1539                private void handle(TaskEvent e) {
1540                    JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1541                     switch (e.getKind()) {
1542                         case PARSE:
1543                         case ENTER:
1544                             h.handle(e.getSourceFile().getName(),
1545                                     unit, unit,
1546                                     dprinter);
1547                             break;
1548
1549                         default:
1550                             TypeElement elem = e.getTypeElement();
1551                             h.handle(elem.toString(),
1552                                     unit, (JCTree) trees.getTree(elem),
1553                                     dprinter);
1554                             break;
1555                     }
1556                }
1557            });
1558
1559            task.call();
1560        }
1561
1562        TaskEvent.Kind getKind(String s) {
1563            return TaskEvent.Kind.valueOf(s.toUpperCase());
1564        }
1565
1566        static protected abstract class Handler {
1567            final String name;
1568            Handler(String name) {
1569                this.name = name;
1570            }
1571            abstract void handle(String label,
1572                    JCCompilationUnit unit, JCTree tree,
1573                    DPrinter dprinter);
1574        }
1575
1576        Map<String,Handler> getHandlers() {
1577            Map<String,Handler> map = new HashMap<String, Handler>();
1578            for (Handler h: defaultHandlers) {
1579                map.put(h.name, h);
1580            }
1581            return map;
1582        }
1583
1584        protected final Handler[] defaultHandlers = {
1585            new Handler("trees") {
1586                @Override
1587                void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1588                    dprinter.printTree(name, tree);
1589                    dprinter.out.println();
1590                }
1591            },
1592
1593            new Handler("doctrees") {
1594                @Override
1595                void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1596                    TreeScanner ds = new DeclScanner() {
1597                        public void visitDecl(JCTree tree, Symbol sym) {
1598                            DocTree dt = unit.docComments.getCommentTree(tree);
1599                            if (dt != null) {
1600                                String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1601                                dprinter.printDocTree(label, dt);
1602                                dprinter.out.println();
1603                            }
1604                        }
1605                    };
1606                    ds.scan(tree);
1607                }
1608            },
1609
1610            new Handler("symbols") {
1611                @Override
1612                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1613                    TreeScanner ds = new DeclScanner() {
1614                        public void visitDecl(JCTree tree, Symbol sym) {
1615                            String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1616                            dprinter.printSymbol(label, sym);
1617                            dprinter.out.println();
1618                        }
1619                    };
1620                    ds.scan(tree);
1621                }
1622            },
1623
1624            new Handler("types") {
1625                @Override
1626                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1627                    TreeScanner ts = new TreeScanner() {
1628                        @Override
1629                        public void scan(JCTree tree) {
1630                            if (tree == null) {
1631                                return;
1632                            }
1633                            if (tree.type != null) {
1634                                String label = Pretty.toSimpleString(tree);
1635                                dprinter.printType(label, tree.type);
1636                                dprinter.out.println();
1637                            }
1638                            super.scan(tree);
1639                        }
1640                    };
1641                    ts.scan(tree);
1642                }
1643            }
1644        };
1645    }
1646
1647    protected static abstract class DeclScanner extends TreeScanner {
1648        @Override
1649        public void visitClassDef(JCClassDecl tree) {
1650            visitDecl(tree, tree.sym);
1651            super.visitClassDef(tree);
1652        }
1653
1654        @Override
1655        public void visitMethodDef(JCMethodDecl tree) {
1656            visitDecl(tree, tree.sym);
1657            super.visitMethodDef(tree);
1658        }
1659
1660        @Override
1661        public void visitVarDef(JCVariableDecl tree) {
1662            visitDecl(tree, tree.sym);
1663            super.visitVarDef(tree);
1664        }
1665
1666        protected abstract void visitDecl(JCTree tree, Symbol sym);
1667    }
1668
1669    // </editor-fold>
1670
1671}
1672