2
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
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
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;
45
import java.util.Locale;
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;
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;
89
* Debug printer for javac internals, for when toString() just isn't enough.
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.
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.
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.
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>
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";
129
// <editor-fold defaultstate="collapsed" desc="Configuration">
131
public static DPrinter instance(Context context) {
132
DPrinter dp = context.get(DPrinter.class);
134
dp = new DPrinter(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);
146
public DPrinter(PrintWriter out, Trees trees) {
151
public DPrinter emptyItems(boolean showEmptyItems) {
152
this.showEmptyItems = showEmptyItems;
156
public DPrinter nulls(boolean showNulls) {
157
this.showNulls = showNulls;
161
public DPrinter positions(boolean showPositions) {
162
this.showPositions = showPositions;
166
public DPrinter source(boolean showSrc) {
167
this.showSrc = showSrc;
171
public DPrinter source(int maxSrcLength) {
173
this.maxSrcLength = maxSrcLength;
177
public DPrinter treeSymbols(boolean showTreeSymbols) {
178
this.showTreeSymbols = showTreeSymbols;
182
public DPrinter treeTypes(boolean showTreeTypes) {
183
this.showTreeTypes = showTreeTypes;
187
public DPrinter typeSymbolPrinter(Printer p) {
194
// <editor-fold defaultstate="collapsed" desc="Printing">
196
protected enum Details {
197
/** A one-line non-recursive summary */
199
/** Multi-line, possibly recursive. */
203
public void printAnnotations(String label, SymbolMetadata annotations) {
204
printAnnotations(label, annotations, Details.FULL);
207
protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
208
if (annotations == null) {
211
// no SUMMARY format currently available to use
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");
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())
227
printString(label, hashString(annotations));
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);
237
printObject("attributes", attributes, Details.SUMMARY);
239
if (attributes instanceof List)
240
printList("type_attributes", (List) type_attributes);
242
printObject("type_attributes", type_attributes, Details.SUMMARY);
247
public void printAttribute(String label, Attribute attr) {
251
printString(label, attr.getClass().getSimpleName());
254
attr.accept(attrVisitor);
259
public void printDocTree(String label, DocTree tree) {
265
out.println(": " + tree.getClass().getSimpleName() + "," + tree.getKind());
268
tree.accept(docTreeVisitor, null);
273
public void printFileObject(String label, FileObject fo) {
277
printString(label, fo.getName());
281
protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
282
if (item.getClass() != stdImplClass)
283
printString("impl", item.getClass().getName());
286
public void printInt(String label, int i) {
287
printString(label, String.valueOf(i));
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);
298
printString(label, s);
301
public void printList(String label, List<?> list) {
304
} else if (!list.isEmpty() || showEmptyItems) {
305
printString(label, "[" + list.size() + "]");
309
for (Object item: list) {
310
printObject(String.valueOf(i++), item, Details.FULL);
316
public void printName(String label, Name name) {
320
printString(label, name.toString());
324
public void printNull(String label) {
326
printString(label, NULL);
329
protected void printObject(String label, Object item, Details details) {
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);
349
printString(label, String.valueOf(item));
353
public void printScope(String label, Scope scope) {
354
printScope(label, scope, Details.FULL);
357
public void printScope(String label, Scope scope, Details details) {
367
for (Symbol sym: scope.getSymbols()) {
381
printFullScopeImpl(scope);
389
void printFullScopeImpl(Scope scope) {
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++) {
402
out.print(i + ":" + entryToString(table[i], table, false));
405
} else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) {
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());
411
for (Symbol sym : scope.getSymbols()) {
412
printSymbol(sym.name.toString(), sym, Details.SUMMARY);
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";
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
426
String entryToString(Object e, Object[] table, boolean ref) {
429
Symbol sym = (Symbol) getField(e, e.getClass(), "sym");
431
return "sent"; // sentinel
433
int index = indexOf(table, e);
435
return String.valueOf(index);
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 + "]")
448
<T> int indexOf(T[] array, T item) {
449
for (int i = 0; i < array.length; i++) {
450
if (array[i] == item)
456
public void printSource(String label, JCTree tree) {
457
printString(label, Pretty.toSimpleString(tree, maxSrcLength));
460
public void printString(String label, String text) {
468
public void printSymbol(String label, Symbol symbol) {
469
printSymbol(label, symbol, Details.FULL);
472
protected void printSymbol(String label, Symbol sym, Details details) {
478
printString(label, toString(sym));
486
String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
489
+ " " + hashString(sym));
493
JCTree tree = (JCTree) trees.getTree(sym);
495
printSource("src", tree);
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);
510
protected String toString(Symbol sym) {
511
return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
514
protected void printTree(String label, JCTree tree) {
521
ext = tree.getKind().name();
522
} catch (Throwable t) {
525
out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
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);
531
if (showTreeTypes && tree.type != null)
532
out.print(" type:" + toString(tree.type));
534
if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
535
out.print(" sym:" + toString(sym));
541
out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
543
tree.accept(treeVisitor);
548
public void printType(String label, Type type) {
549
printType(label, type, Details.FULL);
552
protected void printType(String label, Type type, Details details) {
558
printString(label, toString(type));
564
out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
565
+ " " + hashString(type));
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);
577
protected String toString(Type type) {
578
return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
581
protected String hashString(Object obj) {
582
return String.format("#%x", obj.hashCode());
585
protected String info(Class<?> clazz, Object internal, Object external) {
586
return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
589
private int indent = 0;
591
protected void indent() {
592
for (int i = 0; i < indent; i++) {
597
protected void indent(int n) {
601
protected Object getField(Object o, Class<?> clazz, String name) {
603
Field f = clazz.getDeclaredField(name);
604
@SuppressWarnings("deprecation")
605
boolean prev = f.isAccessible();
606
f.setAccessible(true);
610
f.setAccessible(prev);
612
} catch (ReflectiveOperationException e) {
614
} catch (SecurityException e) {
619
protected Object callMethod(Object o, Class<?> clazz, String name) {
621
Method m = clazz.getDeclaredMethod(name);
622
@SuppressWarnings("deprecation")
623
boolean prev = m.isAccessible();
624
m.setAccessible(true);
628
m.setAccessible(prev);
630
} catch (ReflectiveOperationException e) {
632
} catch (SecurityException e) {
639
// <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
641
protected JCTree.Visitor treeVisitor = new TreeVisitor();
644
* Default visitor class for JCTree (AST) objects.
646
public class TreeVisitor extends JCTree.Visitor {
648
public void visitTopLevel(JCCompilationUnit tree) {
649
printList("packageAnnotations", tree.getPackageAnnotations());
650
printList("defs", tree.defs);
654
public void visitPackageDef(JCPackageDecl tree) {
655
printTree("pid", tree.pid);
659
public void visitImport(JCImport tree) {
660
printTree("qualid", tree.qualid);
664
public void visitClassDef(JCClassDecl tree) {
665
printName("name", tree.name);
666
printTree("mods", tree.mods);
667
printList("typarams", tree.typarams);
668
printTree("extending", tree.extending);
669
printList("implementing", tree.implementing);
670
printList("defs", tree.defs);
674
public void visitMethodDef(JCMethodDecl tree) {
675
printName("name", tree.name);
676
printTree("mods", tree.mods);
677
printTree("restype", tree.restype);
678
printList("typarams", tree.typarams);
679
printTree("recvparam", tree.recvparam);
680
printList("params", tree.params);
681
printList("thrown", tree.thrown);
682
printTree("defaultValue", tree.defaultValue);
683
printTree("body", tree.body);
687
public void visitVarDef(JCVariableDecl tree) {
688
printName("name", tree.name);
689
printTree("mods", tree.mods);
690
printTree("vartype", tree.vartype);
691
printTree("init", tree.init);
695
public void visitSkip(JCSkip tree) {
699
public void visitBlock(JCBlock tree) {
700
printList("stats", tree.stats);
704
public void visitDoLoop(JCDoWhileLoop tree) {
705
printTree("body", tree.body);
706
printTree("cond", tree.cond);
710
public void visitWhileLoop(JCWhileLoop tree) {
711
printTree("cond", tree.cond);
712
printTree("body", tree.body);
716
public void visitForLoop(JCForLoop tree) {
717
printList("init", tree.init);
718
printTree("cond", tree.cond);
719
printList("step", tree.step);
720
printTree("body", tree.body);
724
public void visitForeachLoop(JCEnhancedForLoop tree) {
725
printTree("var", tree.var);
726
printTree("expr", tree.expr);
727
printTree("body", tree.body);
731
public void visitLabelled(JCLabeledStatement tree) {
732
printTree("body", tree.body);
736
public void visitSwitch(JCSwitch tree) {
737
printTree("selector", tree.selector);
738
printList("cases", tree.cases);
742
public void visitCase(JCCase tree) {
743
printList("labels", tree.labels);
744
printList("stats", tree.stats);
748
public void visitSynchronized(JCSynchronized tree) {
749
printTree("lock", tree.lock);
750
printTree("body", tree.body);
754
public void visitTry(JCTry tree) {
755
printList("resources", tree.resources);
756
printTree("body", tree.body);
757
printList("catchers", tree.catchers);
758
printTree("finalizer", tree.finalizer);
762
public void visitCatch(JCCatch tree) {
763
printTree("param", tree.param);
764
printTree("body", tree.body);
768
public void visitConditional(JCConditional tree) {
769
printTree("cond", tree.cond);
770
printTree("truepart", tree.truepart);
771
printTree("falsepart", tree.falsepart);
775
public void visitIf(JCIf tree) {
776
printTree("cond", tree.cond);
777
printTree("thenpart", tree.thenpart);
778
printTree("elsepart", tree.elsepart);
782
public void visitExec(JCExpressionStatement tree) {
783
printTree("expr", tree.expr);
787
public void visitBreak(JCBreak tree) {
788
printName("label", tree.label);
792
public void visitYield(JCYield tree) {
793
printTree("value", tree.value);
797
public void visitContinue(JCContinue tree) {
798
printName("label", tree.label);
802
public void visitReturn(JCReturn tree) {
803
printTree("expr", tree.expr);
807
public void visitThrow(JCThrow tree) {
808
printTree("expr", tree.expr);
812
public void visitAssert(JCAssert tree) {
813
printTree("cond", tree.cond);
814
printTree("detail", tree.detail);
818
public void visitApply(JCMethodInvocation tree) {
819
printList("typeargs", tree.typeargs);
820
printTree("meth", tree.meth);
821
printList("args", tree.args);
825
public void visitNewClass(JCNewClass tree) {
826
printTree("encl", tree.encl);
827
printList("typeargs", tree.typeargs);
828
printTree("clazz", tree.clazz);
829
printList("args", tree.args);
830
printTree("def", tree.def);
834
public void visitNewArray(JCNewArray tree) {
835
printList("annotations", tree.annotations);
836
printTree("elemtype", tree.elemtype);
837
printList("dims", tree.dims);
838
printList("dimAnnotations", tree.dimAnnotations);
839
printList("elems", tree.elems);
843
public void visitLambda(JCLambda tree) {
844
printTree("body", tree.body);
845
printList("params", tree.params);
849
public void visitParens(JCParens tree) {
850
printTree("expr", tree.expr);
854
public void visitAssign(JCAssign tree) {
855
printTree("lhs", tree.lhs);
856
printTree("rhs", tree.rhs);
860
public void visitAssignop(JCAssignOp tree) {
861
printTree("lhs", tree.lhs);
862
printTree("rhs", tree.rhs);
866
public void visitUnary(JCUnary tree) {
867
printTree("arg", tree.arg);
871
public void visitBinary(JCBinary tree) {
872
printTree("lhs", tree.lhs);
873
printTree("rhs", tree.rhs);
877
public void visitTypeCast(JCTypeCast tree) {
878
printTree("clazz", tree.clazz);
879
printTree("expr", tree.expr);
883
public void visitTypeTest(JCInstanceOf tree) {
884
printTree("expr", tree.expr);
885
printTree("pattern", tree.pattern);
889
public void visitIndexed(JCArrayAccess tree) {
890
printTree("indexed", tree.indexed);
891
printTree("index", tree.index);
895
public void visitSelect(JCFieldAccess tree) {
896
printTree("selected", tree.selected);
900
public void visitReference(JCMemberReference tree) {
901
printTree("expr", tree.expr);
902
printList("typeargs", tree.typeargs);
906
public void visitIdent(JCIdent tree) {
907
printName("name", tree.name);
911
public void visitLiteral(JCLiteral tree) {
912
printString("value", Pretty.toSimpleString(tree, 32));
916
public void visitTypeIdent(JCPrimitiveTypeTree tree) {
917
printString("typetag", tree.typetag.name());
921
public void visitTypeArray(JCArrayTypeTree tree) {
922
printTree("elemtype", tree.elemtype);
926
public void visitTypeApply(JCTypeApply tree) {
927
printTree("clazz", tree.clazz);
928
printList("arguments", tree.arguments);
932
public void visitTypeUnion(JCTypeUnion tree) {
933
printList("alternatives", tree.alternatives);
937
public void visitTypeIntersection(JCTypeIntersection tree) {
938
printList("bounds", tree.bounds);
942
public void visitTypeParameter(JCTypeParameter tree) {
943
printName("name", tree.name);
944
printList("annotations", tree.annotations);
945
printList("bounds", tree.bounds);
949
public void visitWildcard(JCWildcard tree) {
950
printTree("kind", tree.kind);
951
printTree("inner", tree.inner);
955
public void visitTypeBoundKind(TypeBoundKind tree) {
956
printString("kind", tree.kind.name());
960
public void visitModifiers(JCModifiers tree) {
961
printList("annotations", tree.annotations);
962
printString("flags", String.valueOf(Flags.asFlagSet(tree.flags)));
966
public void visitAnnotation(JCAnnotation tree) {
967
printTree("annotationType", tree.annotationType);
968
printList("args", tree.args);
972
public void visitAnnotatedType(JCAnnotatedType tree) {
973
printList("annotations", tree.annotations);
974
printTree("underlyingType", tree.underlyingType);
978
public void visitErroneous(JCErroneous tree) {
979
printList("errs", tree.errs);
983
public void visitLetExpr(LetExpr tree) {
984
printList("defs", tree.defs);
985
printTree("expr", tree.expr);
989
public void visitTree(JCTree tree) {
996
// <editor-fold defaultstate="collapsed" desc="DocTree visitor">
998
protected DocTreeVisitor<Void,Void> docTreeVisitor = new DefaultDocTreeVisitor();
1001
* Default visitor class for DocTree objects.
1002
* Note: each visitXYZ method ends by calling the corresponding
1003
* visit method for its superclass.
1005
class DefaultDocTreeVisitor implements DocTreeVisitor<Void,Void> {
1007
public Void visitAttribute(AttributeTree node, Void p) {
1008
printName("name", node.getName());
1009
printString("vkind", node.getValueKind().name());
1010
printList("value", node.getValue());
1011
return visitTree(node, null);
1014
public Void visitAuthor(AuthorTree node, Void p) {
1015
printList("name", node.getName());
1016
return visitBlockTag(node, null);
1019
public Void visitComment(CommentTree node, Void p) {
1020
printLimitedEscapedString("body", node.getBody());
1021
return visitTree(node, null);
1024
public Void visitDeprecated(DeprecatedTree node, Void p) {
1025
printList("body", node.getBody());
1026
return visitBlockTag(node, null);
1029
public Void visitDocComment(DocCommentTree node, Void p) {
1030
printList("firstSentence", node.getFirstSentence());
1031
printList("body", node.getBody());
1032
printList("tags", node.getBlockTags());
1033
return visitTree(node, null);
1036
public Void visitDocRoot(DocRootTree node, Void p) {
1037
return visitInlineTag(node, null);
1041
public Void visitDocType(DocTypeTree node, Void aVoid) {
1042
printLimitedEscapedString("body", node.getText());
1043
return visitTree(node, null);
1046
public Void visitEndElement(EndElementTree node, Void p) {
1047
printName("name", node.getName());
1048
return visitTree(node, null);
1051
public Void visitEntity(EntityTree node, Void p) {
1052
printName("name", node.getName());
1053
return visitTree(node, null);
1056
public Void visitErroneous(ErroneousTree node, Void p) {
1057
printLimitedEscapedString("body", node.getBody());
1058
printString("diag", node.getDiagnostic().getMessage(Locale.getDefault()));
1059
return visitTree(node, null);
1062
public Void visitHidden(HiddenTree node, Void p) {
1063
printList("body", node.getBody());
1064
return visitBlockTag(node, null);
1067
public Void visitIdentifier(IdentifierTree node, Void p) {
1068
printName("name", node.getName());
1069
return visitTree(node, null);
1072
public Void visitIndex(IndexTree node, Void p) {
1073
printString("kind", node.getKind().name());
1074
printDocTree("term", node.getSearchTerm());
1075
printList("desc", node.getDescription());
1076
return visitInlineTag(node, p);
1079
public Void visitInheritDoc(InheritDocTree node, Void p) {
1080
return visitInlineTag(node, null);
1083
public Void visitLink(LinkTree node, Void p) {
1084
printString("kind", node.getKind().name());
1085
printDocTree("ref", node.getReference());
1086
printList("list", node.getLabel());
1087
return visitInlineTag(node, null);
1090
public Void visitLiteral(LiteralTree node, Void p) {
1091
printString("kind", node.getKind().name());
1092
printDocTree("body", node.getBody());
1093
return visitInlineTag(node, null);
1096
public Void visitParam(ParamTree node, Void p) {
1097
printString("isTypeParameter", String.valueOf(node.isTypeParameter()));
1098
printString("kind", node.getKind().name());
1099
printList("desc", node.getDescription());
1100
return visitBlockTag(node, null);
1103
public Void visitProvides(ProvidesTree node, Void p) {
1104
printString("kind", node.getKind().name());
1105
printDocTree("serviceType", node.getServiceType());
1106
printList("description", node.getDescription());
1107
return visitBlockTag(node, null);
1110
public Void visitRawText(RawTextTree node, Void p) {
1111
printLimitedEscapedString("content", node.getContent());
1112
return visitTree(node, null);
1115
public Void visitReference(ReferenceTree node, Void p) {
1116
printString("signature", node.getSignature());
1117
return visitTree(node, null);
1120
public Void visitReturn(ReturnTree node, Void p) {
1121
printList("desc", node.getDescription());
1122
return visitBlockTag(node, null);
1125
public Void visitSee(SeeTree node, Void p) {
1126
printList("ref", node.getReference());
1127
return visitBlockTag(node, null);
1130
public Void visitSerial(SerialTree node, Void p) {
1131
printList("desc", node.getDescription());
1132
return visitBlockTag(node, null);
1135
public Void visitSerialData(SerialDataTree node, Void p) {
1136
printList("desc", node.getDescription());
1137
return visitBlockTag(node, null);
1140
public Void visitSerialField(SerialFieldTree node, Void p) {
1141
printDocTree("name", node.getName());
1142
printDocTree("type", node.getType());
1143
printList("desc", node.getDescription());
1144
return visitBlockTag(node, null);
1147
public Void visitSince(SinceTree node, Void p) {
1148
printList("body", node.getBody());
1149
return visitBlockTag(node, null);
1152
public Void visitSpec(SpecTree node, Void p) {
1153
printDocTree("url", node.getURL());
1154
printList("title", node.getTitle());
1155
return visitBlockTag(node, null);
1158
public Void visitStartElement(StartElementTree node, Void p) {
1159
printName("name", node.getName());
1160
printList("attrs", node.getAttributes());
1161
printString("selfClosing", String.valueOf(node.isSelfClosing()));
1162
return visitBlockTag(node, null);
1165
public Void visitSummary(SummaryTree node, Void p) {
1166
printString("name", node.getTagName());
1167
printList("summary", node.getSummary());
1168
return visitInlineTag(node, null);
1171
public Void visitText(TextTree node, Void p) {
1172
printLimitedEscapedString("body", node.getBody());
1173
return visitTree(node, null);
1176
public Void visitThrows(ThrowsTree node, Void p) {
1177
printDocTree("name", node.getExceptionName());
1178
printList("desc", node.getDescription());
1179
return visitBlockTag(node, null);
1182
public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
1183
printString("name", node.getTagName());
1184
printList("content", node.getContent());
1185
return visitBlockTag(node, null);
1188
public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
1189
printString("name", node.getTagName());
1190
printList("content", node.getContent());
1191
return visitInlineTag(node, null);
1194
public Void visitUses(UsesTree node, Void p) {
1195
printString("kind", node.getKind().name());
1196
printDocTree("serviceType", node.getServiceType());
1197
printList("description", node.getDescription());
1198
return visitBlockTag(node, null);
1201
public Void visitValue(ValueTree node, Void p) {
1202
printDocTree("format", node.getFormat());
1203
printDocTree("value", node.getReference());
1204
return visitInlineTag(node, null);
1207
public Void visitVersion(VersionTree node, Void p) {
1208
printList("body", node.getBody());
1209
return visitBlockTag(node, null);
1212
public Void visitOther(DocTree node, Void p) {
1213
return visitTree(node, null);
1216
public Void visitBlockTag(DocTree node, Void p) {
1217
return visitTree(node, null);
1220
public Void visitInlineTag(DocTree node, Void p) {
1221
return visitTree(node, null);
1224
public Void visitTree(DocTree node, Void p) {
1231
// <editor-fold defaultstate="collapsed" desc="Symbol visitor">
1233
protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
1236
* Default visitor class for Symbol objects.
1237
* Note: each visitXYZ method ends by calling the corresponding
1238
* visit method for its superclass.
1240
class SymbolVisitor implements Symbol.Visitor<Void,Void> {
1242
public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
1243
printName("fullname", sym.fullname);
1244
printName("flatname", sym.flatname);
1245
printScope("members", sym.members_field);
1246
printFileObject("sourcefile", sym.sourcefile);
1247
printFileObject("classfile", sym.classfile);
1250
return visitTypeSymbol(sym, null);
1254
public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
1256
printList("params", sym.params);
1257
return visitSymbol(sym, null);
1261
public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
1262
printName("fullname", sym.fullname);
1263
printScope("members", sym.members_field);
1264
printSymbol("package-info", sym.package_info, Details.SUMMARY);
1265
return visitTypeSymbol(sym, null);
1269
public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
1270
printInt("opcode", sym.opcode);
1271
return visitMethodSymbol(sym, null);
1275
public Void visitVarSymbol(VarSymbol sym, Void ignore) {
1276
printInt("pos", sym.pos);
1277
printInt("adm", sym.adr);
1278
// data is a private field, and the standard accessors may
1279
// mutate it as part of lazy evaluation. Therefore, use
1280
// reflection to get the raw data.
1281
printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
1282
return visitSymbol(sym, null);
1286
public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
1287
return visitSymbol(sym, null);
1291
public Void visitSymbol(Symbol sym, Void ignore) {
1298
// <editor-fold defaultstate="collapsed" desc="Type visitor">
1300
protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
1303
* Default visitor class for Type objects.
1304
* Note: each visitXYZ method ends by calling the corresponding
1305
* visit method for its superclass.
1307
public class TypeVisitor implements Type.Visitor<Void,Void> {
1308
public Void visitArrayType(ArrayType type, Void ignore) {
1309
printType("elemType", type.elemtype, Details.FULL);
1310
return visitType(type, null);
1313
public Void visitCapturedType(CapturedType type, Void ignore) {
1314
printType("wildcard", type.wildcard, Details.FULL);
1315
return visitTypeVar(type, null);
1318
public Void visitClassType(ClassType type, Void ignore) {
1319
printType("outer", type.getEnclosingType(), Details.SUMMARY);
1320
printList("typarams", type.typarams_field);
1321
printList("allparams", type.allparams_field);
1322
printType("supertype", type.supertype_field, Details.SUMMARY);
1323
printList("interfaces", type.interfaces_field);
1324
printList("allinterfaces", type.all_interfaces_field);
1325
return visitType(type, null);
1328
public Void visitErrorType(ErrorType type, Void ignore) {
1329
printType("originalType", type.getOriginalType(), Details.FULL);
1330
return visitClassType(type, null);
1333
public Void visitForAll(ForAll type, Void ignore) {
1334
printList("tvars", type.tvars);
1335
return visitDelegatedType(type);
1338
public Void visitMethodType(MethodType type, Void ignore) {
1339
printList("argtypes", type.argtypes);
1340
printType("restype", type.restype, Details.FULL);
1341
printList("thrown", type.thrown);
1342
printType("recvtype", type.recvtype, Details.FULL);
1343
return visitType(type, null);
1346
public Void visitModuleType(ModuleType type, Void ignore) {
1347
return visitType(type, null);
1350
public Void visitPackageType(PackageType type, Void ignore) {
1351
return visitType(type, null);
1354
public Void visitTypeVar(TypeVar type, Void ignore) {
1355
// For TypeVars (and not subtypes), the bound should always be
1356
// null or bot. So, only print the bound for subtypes of TypeVar,
1357
// or if the bound is (erroneously) not null or bot.
1358
if (!type.hasTag(TypeTag.TYPEVAR)
1359
|| !(type.getUpperBound() == null || type.getUpperBound().hasTag(TypeTag.BOT))) {
1360
printType("bound", type.getUpperBound(), Details.FULL);
1362
printType("lower", type.lower, Details.FULL);
1363
return visitType(type, null);
1366
public Void visitUndetVar(UndetVar type, Void ignore) {
1367
for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1368
printList("bounds." + ib, type.getBounds(ib));
1369
printInt("declaredCount", type.declaredCount);
1370
printType("inst", type.getInst(), Details.SUMMARY);
1371
return visitDelegatedType(type);
1374
public Void visitWildcardType(WildcardType type, Void ignore) {
1375
printType("type", type.type, Details.SUMMARY);
1376
printString("kind", type.kind.name());
1377
printType("bound", type.bound, Details.SUMMARY);
1378
return visitType(type, null);
1381
protected Void visitDelegatedType(DelegatedType type) {
1382
printType("qtype", type.qtype, Details.FULL);
1383
return visitType(type, null);
1386
public Void visitType(Type type, Void ignore) {
1393
// <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1395
protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1398
* Default visitor class for Attribute (annotation) objects.
1400
public class AttributeVisitor implements Attribute.Visitor {
1402
public void visitConstant(Attribute.Constant a) {
1403
printObject("value", a.value, Details.SUMMARY);
1407
public void visitClass(Attribute.Class a) {
1408
printObject("classType", a.classType, Details.SUMMARY);
1412
public void visitCompound(Attribute.Compound a) {
1413
if (a instanceof Attribute.TypeCompound) {
1414
Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1415
// consider a custom printer?
1416
printObject("position", ta.position, Details.SUMMARY);
1418
printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1419
printList("values", a.values);
1423
public void visitArray(Attribute.Array a) {
1424
printList("values", Arrays.asList(a.values));
1428
public void visitEnum(Attribute.Enum a) {
1429
printSymbol("value", a.value, Details.SUMMARY);
1433
public void visitError(Attribute.Error a) {
1437
public void visitAttribute(Attribute a) {
1438
printType("type", a.type, Details.SUMMARY);
1444
// <editor-fold defaultstate="collapsed" desc="Utility front end">
1447
* Utility class to invoke DPrinter from the command line.
1450
public static void main(String... args) throws IOException {
1451
Main m = new Main();
1452
PrintWriter out = new PrintWriter(System.out);
1454
if (args.length == 0)
1463
void usage(PrintWriter out) {
1464
out.println("Usage:");
1465
out.println(" java " + Main.class.getName() + " mode [options] [javac-options]");
1466
out.print("where mode is one of: ");
1468
for (Handler h: getHandlers().values()) {
1474
out.println("and where options include:");
1475
out.println(" -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1476
out.println(" -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1477
out.println(" -showPositions");
1478
out.println(" -showSource");
1479
out.println(" -showTreeSymbols");
1480
out.println(" -showTreeTypes");
1481
out.println(" -hideEmptyItems");
1482
out.println(" -hideNulls");
1485
void run(PrintWriter out, String... args) throws IOException {
1486
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1487
StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1490
final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1491
final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1492
boolean showPositions = false;
1493
boolean showSource = false;
1494
boolean showTreeSymbols = false;
1495
boolean showTreeTypes = false;
1496
boolean showEmptyItems = true;
1497
boolean showNulls = true;
1500
Collection<String> options = new ArrayList<String>();
1501
Collection<File> files = new ArrayList<File>();
1502
String classpath = null;
1503
String classoutdir = null;
1505
final Handler h = getHandlers().get(args[0]);
1507
throw new IllegalArgumentException(args[0]);
1509
for (int i = 1; i < args.length; i++) {
1510
String arg = args[i];
1511
if (arg.equals("-before") && i + 1 < args.length) {
1512
before.add(getKind(args[++i]));
1513
} else if (arg.equals("-after") && i + 1 < args.length) {
1514
after.add(getKind(args[++i]));
1515
} else if (arg.equals("-showPositions")) {
1516
showPositions = true;
1517
} else if (arg.equals("-showSource")) {
1519
} else if (arg.equals("-showTreeSymbols")) {
1520
showTreeSymbols = true;
1521
} else if (arg.equals("-showTreeTypes")) {
1522
showTreeTypes = true;
1523
} else if (arg.equals("-hideEmptyLists")) {
1524
showEmptyItems = false;
1525
} else if (arg.equals("-hideNulls")) {
1527
} else if (arg.equals("-classpath") && i + 1 < args.length) {
1528
classpath = args[++i];
1529
} else if (arg.equals("-d") && i + 1 < args.length) {
1530
classoutdir = args[++i];
1531
} else if (arg.startsWith("-")) {
1532
int n = c.isSupportedOption(arg);
1533
if (n < 0) throw new IllegalArgumentException(arg);
1535
while (n > 0) options.add(args[++i]);
1536
} else if (arg.endsWith(".java")) {
1537
files.add(new File(arg));
1541
if (classoutdir != null) {
1542
fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1545
if (classpath != null) {
1546
Collection<File> path = new ArrayList<File>();
1547
for (String p: classpath.split(File.pathSeparator)) {
1548
if (p.isEmpty()) continue;
1549
File f = new File(p);
1550
if (f.exists()) path.add(f);
1552
fm.setLocation(StandardLocation.CLASS_PATH, path);
1554
Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1556
JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1557
final Trees trees = Trees.instance(task);
1559
final DPrinter dprinter = new DPrinter(out, trees);
1560
dprinter.source(showSource)
1561
.emptyItems(showEmptyItems)
1563
.positions(showPositions)
1564
.treeSymbols(showTreeSymbols)
1565
.treeTypes(showTreeTypes);
1567
if (before.isEmpty() && after.isEmpty()) {
1568
if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1569
after.add(TaskEvent.Kind.PARSE);
1571
after.add(TaskEvent.Kind.ANALYZE);
1574
task.addTaskListener(new TaskListener() {
1575
public void started(TaskEvent e) {
1576
if (before.contains(e.getKind()))
1580
public void finished(TaskEvent e) {
1581
if (after.contains(e.getKind()))
1585
private void handle(TaskEvent e) {
1586
JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1587
switch (e.getKind()) {
1590
h.handle(e.getSourceFile().getName(),
1596
TypeElement elem = e.getTypeElement();
1597
h.handle(elem.toString(),
1598
unit, (JCTree) trees.getTree(elem),
1608
TaskEvent.Kind getKind(String s) {
1609
return TaskEvent.Kind.valueOf(s.toUpperCase());
1612
static protected abstract class Handler {
1614
Handler(String name) {
1617
abstract void handle(String label,
1618
JCCompilationUnit unit, JCTree tree,
1622
Map<String,Handler> getHandlers() {
1623
Map<String,Handler> map = new HashMap<String, Handler>();
1624
for (Handler h: defaultHandlers) {
1630
protected final Handler[] defaultHandlers = {
1631
new Handler("trees") {
1633
void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1634
dprinter.printTree(name, tree);
1635
dprinter.out.println();
1639
new Handler("doctrees") {
1641
void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1642
TreeScanner ds = new DeclScanner() {
1643
public void visitDecl(JCTree tree, Symbol sym) {
1644
DocTree dt = unit.docComments.getCommentTree(tree);
1646
String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1647
dprinter.printDocTree(label, dt);
1648
dprinter.out.println();
1656
new Handler("symbols") {
1658
void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1659
TreeScanner ds = new DeclScanner() {
1660
public void visitDecl(JCTree tree, Symbol sym) {
1661
String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1662
dprinter.printSymbol(label, sym);
1663
dprinter.out.println();
1670
new Handler("types") {
1672
void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1673
TreeScanner ts = new TreeScanner() {
1675
public void scan(JCTree tree) {
1679
if (tree.type != null) {
1680
String label = Pretty.toSimpleString(tree);
1681
dprinter.printType(label, tree.type);
1682
dprinter.out.println();
1693
protected static abstract class DeclScanner extends TreeScanner {
1695
public void visitClassDef(JCClassDecl tree) {
1696
visitDecl(tree, tree.sym);
1697
super.visitClassDef(tree);
1701
public void visitMethodDef(JCMethodDecl tree) {
1702
visitDecl(tree, tree.sym);
1703
super.visitMethodDef(tree);
1707
public void visitVarDef(JCVariableDecl tree) {
1708
visitDecl(tree, tree.sym);
1709
super.visitVarDef(tree);
1712
protected abstract void visitDecl(JCTree tree, Symbol sym);