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