test/tools/javac/lib/DPrinter.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 2134
b0c086cd4520
parent 0
959103a6100f
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2013, 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  */
    24 import java.io.File;
    25 import java.io.IOException;
    26 import java.io.PrintWriter;
    27 import java.lang.reflect.Field;
    28 import java.util.ArrayList;
    29 import java.util.Arrays;
    30 import java.util.Collection;
    31 import java.util.EnumSet;
    32 import java.util.HashMap;
    33 import java.util.List;
    34 import java.util.Locale;
    35 import java.util.Map;
    36 import java.util.Set;
    38 import javax.lang.model.element.Name;
    39 import javax.lang.model.element.TypeElement;
    40 import javax.tools.FileObject;
    41 import javax.tools.JavaCompiler;
    42 import javax.tools.JavaFileObject;
    43 import javax.tools.StandardJavaFileManager;
    44 import javax.tools.StandardLocation;
    45 import javax.tools.ToolProvider;
    47 import com.sun.source.util.JavacTask;
    48 import com.sun.source.util.TaskEvent;
    49 import com.sun.source.util.TaskListener;
    50 import com.sun.source.util.Trees;
    51 import com.sun.tools.javac.api.JavacTrees;
    52 import com.sun.tools.javac.code.SymbolMetadata;
    53 import com.sun.tools.javac.code.Attribute;
    54 import com.sun.tools.javac.code.Flags;
    55 import com.sun.tools.javac.code.Kinds;
    56 import com.sun.tools.javac.code.Printer;
    57 import com.sun.tools.javac.code.Scope;
    58 import com.sun.tools.javac.code.Scope.CompoundScope;
    59 import com.sun.tools.javac.code.Symbol;
    60 import com.sun.tools.javac.code.Symbol.*;
    61 import com.sun.tools.javac.code.Type;
    62 import com.sun.tools.javac.code.Type.*;
    63 import com.sun.tools.javac.code.TypeTag;
    64 import com.sun.tools.javac.tree.JCTree;
    65 import com.sun.tools.javac.tree.JCTree.*;
    66 import com.sun.tools.javac.tree.Pretty;
    67 import com.sun.tools.javac.tree.TreeInfo;
    68 import com.sun.tools.javac.tree.TreeScanner;
    69 import com.sun.tools.javac.util.Assert;
    70 import com.sun.tools.javac.util.Context;
    71 import com.sun.tools.javac.util.Log;
    74 /**
    75  * Debug printer for javac internals, for when toString() just isn't enough.
    76  *
    77  * <p>
    78  * The printer provides an API to generate structured views of javac objects,
    79  * such as AST nodes, symbol, types and annotations. Various aspects of the
    80  * output can be configured, such as whether to show nulls, empty lists, or
    81  * a compressed representation of the source code. Visitors are used to walk
    82  * object hierarchies, and can be replaced with custom visitors if the default
    83  * visitors are not flexible enough.
    84  *
    85  * <p>
    86  * In general, nodes are printed with an initial line identifying the node
    87  * followed by indented lines for the child nodes. Currently, graphs are
    88  * represented by printing a spanning subtree.
    89  *
    90  * <p>
    91  * The printer can be accessed via a simple command-line utility,
    92  * which makes it easy to see the internal representation of source code,
    93  * such as simple test programs, during the compilation pipeline.
    94  *
    95  *  <p><b>This is NOT part of any supported API.
    96  *  If you write code that depends on this, you do so at your own risk.
    97  *  This code and its internal interfaces are subject to change or
    98  *  deletion without notice.</b>
    99  */
   101 public class DPrinter {
   102     protected final PrintWriter out;
   103     protected final Trees trees;
   104     protected Printer printer;
   105     protected boolean showEmptyItems = true;
   106     protected boolean showNulls = true;
   107     protected boolean showPositions = false;
   108     protected boolean showSrc;
   109     protected boolean showTreeSymbols;
   110     protected boolean showTreeTypes;
   111     protected int maxSrcLength = 32;
   112     protected Locale locale = Locale.getDefault();
   113     protected static final String NULL = "#null";
   115     // <editor-fold defaultstate="collapsed" desc="Configuration">
   117     public static DPrinter instance(Context context) {
   118         DPrinter dp = context.get(DPrinter.class);
   119         if (dp == null) {
   120             dp = new DPrinter(context);
   121         }
   122         return dp;
   124     }
   126     protected DPrinter(Context context) {
   127         context.put(DPrinter.class, this);
   128         out = context.get(Log.outKey);
   129         trees = JavacTrees.instance(context);
   130     }
   132     public DPrinter(PrintWriter out, Trees trees) {
   133         this.out = out;
   134         this.trees = trees;
   135     }
   137     public DPrinter emptyItems(boolean showEmptyItems) {
   138         this.showEmptyItems = showEmptyItems;
   139         return this;
   140     }
   142     public DPrinter nulls(boolean showNulls) {
   143         this.showNulls = showNulls;
   144         return this;
   145     }
   147     public DPrinter positions(boolean showPositions) {
   148         this.showPositions = showPositions;
   149         return this;
   150     }
   152     public DPrinter source(boolean showSrc) {
   153         this.showSrc = showSrc;
   154         return this;
   155     }
   157     public DPrinter source(int maxSrcLength) {
   158         this.showSrc = true;
   159         this.maxSrcLength = maxSrcLength;
   160         return this;
   161     }
   163     public DPrinter treeSymbols(boolean showTreeSymbols) {
   164         this.showTreeSymbols = showTreeSymbols;
   165         return this;
   166     }
   168     public DPrinter treeTypes(boolean showTreeTypes) {
   169         this.showTreeTypes = showTreeTypes;
   170         return this;
   171     }
   173     public DPrinter typeSymbolPrinter(Printer p) {
   174         printer = p;
   175         return this;
   176     }
   178     // </editor-fold>
   180     // <editor-fold defaultstate="collapsed" desc="Printing">
   182     protected enum Details {
   183         /** A one-line non-recursive summary */
   184         SUMMARY,
   185         /** Multi-line, possibly recursive. */
   186         FULL
   187     };
   189     public void printAnnotations(String label, SymbolMetadata annotations) {
   190         printAnnotations(label, annotations, Details.FULL);
   191     }
   193     protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
   194         if (annotations == null) {
   195             printNull(label);
   196         } else {
   197             // no SUMMARY format currently available to use
   199             // use reflection to get at private fields
   200             Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
   201             Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
   202             Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
   203             Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
   205             if (!showEmptyItems) {
   206                 if (attributes instanceof List && ((List) attributes).isEmpty()
   207                         && attributes != DECL_NOT_STARTED
   208                         && attributes != DECL_IN_PROGRESS
   209                         && type_attributes instanceof List && ((List) type_attributes).isEmpty())
   210                     return;
   211             }
   213             printString(label, hashString(annotations));
   215             indent(+1);
   216             if (attributes == DECL_NOT_STARTED)
   217                 printString("attributes", "DECL_NOT_STARTED");
   218             else if (attributes == DECL_IN_PROGRESS)
   219                 printString("attributes", "DECL_IN_PROGRESS");
   220             else if (attributes instanceof List)
   221                 printList("attributes", (List) attributes);
   222             else
   223                 printObject("attributes", attributes, Details.SUMMARY);
   225             if (attributes instanceof List)
   226                 printList("type_attributes", (List) type_attributes);
   227             else
   228                 printObject("type_attributes", type_attributes, Details.SUMMARY);
   229             indent(-1);
   230         }
   231     }
   233     public void printAttribute(String label, Attribute attr) {
   234         if (attr == null) {
   235             printNull(label);
   236         } else {
   237             printString(label, attr.getClass().getSimpleName());
   239             indent(+1);
   240             attr.accept(attrVisitor);
   241             indent(-1);
   242         }
   243     }
   245     public void printFileObject(String label, FileObject fo) {
   246         if (fo == null) {
   247             printNull(label);
   248         } else {
   249             printString(label, fo.getName());
   250         }
   251     }
   253     protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
   254         if (item.getClass() != stdImplClass)
   255             printString("impl", item.getClass().getName());
   256     }
   258     public void printInt(String label, int i) {
   259         printString(label, String.valueOf(i));
   260     }
   262     public void printList(String label, List<?> list) {
   263         if (list == null) {
   264              printNull(label);
   265         } else if (!list.isEmpty() || showEmptyItems) {
   266             printString(label, "[" + list.size() + "]");
   268             indent(+1);
   269             int i = 0;
   270             for (Object item: list) {
   271                 printObject(String.valueOf(i++), item, Details.FULL);
   272             }
   273             indent(-1);
   274         }
   275     }
   277     public void printName(String label, Name name) {
   278         if (name == null) {
   279             printNull(label);
   280         } else {
   281             printString(label, name.toString());
   282         }
   283     }
   285     public void printNull(String label) {
   286         if (showNulls)
   287             printString(label, NULL);
   288     }
   290     protected void printObject(String label, Object item, Details details) {
   291         if (item == null) {
   292             printNull(label);
   293         } else if (item instanceof Attribute) {
   294             printAttribute(label, (Attribute) item);
   295         } else if (item instanceof Symbol) {
   296             printSymbol(label, (Symbol) item, details);
   297         } else if (item instanceof Type) {
   298             printType(label, (Type) item, details);
   299         } else if (item instanceof JCTree) {
   300             printTree(label, (JCTree) item);
   301         } else if (item instanceof List) {
   302             printList(label, (List) item);
   303         } else if (item instanceof Name) {
   304             printName(label, (Name) item);
   305         } else {
   306             printString(label, String.valueOf(item));
   307         }
   308     }
   310     public void printScope(String label, Scope scope) {
   311         printScope(label, scope, Details.FULL);
   312     }
   314     public void printScope(String label, Scope scope, Details details) {
   315         if (scope == null) {
   316             printNull(label);
   317         } else {
   318             switch (details) {
   319                 case SUMMARY: {
   320                     indent();
   321                     out.print(label);
   322                     out.print(": [");
   323                     String sep = "";
   324                     for (Symbol sym: scope.getElements()) {
   325                         out.print(sep);
   326                         out.print(sym.name);
   327                         sep = ",";
   328                     }
   329                     out.println("]");
   330                     break;
   331                 }
   333                 case FULL: {
   334                     indent();
   335                     out.println(label);
   337                     indent(+1);
   338                     printImplClass(scope, Scope.class);
   339                     printSymbol("owner", scope.owner, Details.SUMMARY);
   340                     printScope("next", scope.next, Details.SUMMARY);
   341                     printObject("shared", getField(scope, Scope.class, "shared"), Details.SUMMARY);
   342                     if (scope instanceof CompoundScope) {
   343                         printObject("subScopes",
   344                                 getField(scope, CompoundScope.class, "subScopes"),
   345                                 Details.FULL);
   346                     } else {
   347                         for (Symbol sym : scope.getElements()) {
   348                             printSymbol(sym.name.toString(), sym, Details.SUMMARY);
   349                         }
   350                     }
   351                     indent(-1);
   352                     break;
   353                 }
   354             }
   355         }
   356     }
   358     public void printSource(String label, JCTree tree) {
   359         printString(label, Pretty.toSimpleString(tree, maxSrcLength));
   360     }
   362     public void printString(String label, String text) {
   363         indent();
   364         out.print(label);
   365         out.print(": ");
   366         out.print(text);
   367         out.println();
   368     }
   370     public void printSymbol(String label, Symbol symbol) {
   371         printSymbol(label, symbol, Details.FULL);
   372     }
   374     protected void printSymbol(String label, Symbol sym, Details details) {
   375         if (sym == null) {
   376             printNull(label);
   377         } else {
   378             switch (details) {
   379             case SUMMARY:
   380                 printString(label, toString(sym));
   381                 break;
   383             case FULL:
   384                 indent();
   385                 out.print(label);
   386                 out.println(": " +
   387                         info(sym.getClass(),
   388                             String.format("0x%x--%s", sym.kind, Kinds.kindName(sym)),
   389                             sym.getKind())
   390                         + " " + sym.name
   391                         + " " + hashString(sym));
   393                 indent(+1);
   394                 if (showSrc) {
   395                     JCTree tree = (JCTree) trees.getTree(sym);
   396                     if (tree != null)
   397                         printSource("src", tree);
   398                 }
   399                 printString("flags", String.format("0x%x--%s",
   400                         sym.flags_field, Flags.toString(sym.flags_field)));
   401                 printObject("completer", sym.completer, Details.SUMMARY); // what if too long?
   402                 printSymbol("owner", sym.owner, Details.SUMMARY);
   403                 printType("type", sym.type, Details.SUMMARY);
   404                 printType("erasure", sym.erasure_field, Details.SUMMARY);
   405                 sym.accept(symVisitor, null);
   406                 printAnnotations("annotations", sym.getAnnotations(), Details.SUMMARY);
   407                 indent(-1);
   408             }
   409         }
   410     }
   412     protected String toString(Symbol sym) {
   413         return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
   414     }
   416     protected void printTree(String label, JCTree tree) {
   417         if (tree == null) {
   418             printNull(label);
   419         } else {
   420             indent();
   421             String ext;
   422             try {
   423                 ext = tree.getKind().name();
   424             } catch (Throwable t) {
   425                 ext = "n/a";
   426             }
   427             out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
   428             if (showPositions) {
   429                 // We can always get start position, but to get end position
   430                 // and/or line+offset, we would need a JCCompilationUnit
   431                 out.print(" pos:" + tree.pos);
   432             }
   433             if (showTreeTypes && tree.type != null)
   434                 out.print(" type:" + toString(tree.type));
   435             Symbol sym;
   436             if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
   437                 out.print(" sym:" + toString(sym));
   438             out.println();
   440             indent(+1);
   441             if (showSrc) {
   442                 indent();
   443                 out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
   444             }
   445             tree.accept(treeVisitor);
   446             indent(-1);
   447         }
   448     }
   450     public void printType(String label, Type type) {
   451         printType(label, type, Details.FULL);
   452     }
   454     protected void printType(String label, Type type, Details details) {
   455         if (type == null)
   456             printNull(label);
   457         else {
   458             switch (details) {
   459                 case SUMMARY:
   460                     printString(label, toString(type));
   461                     break;
   463                 case FULL:
   464                     indent();
   465                     out.print(label);
   466                     out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
   467                             + " " + hashString(type));
   469                     indent(+1);
   470                     printSymbol("tsym", type.tsym, Details.SUMMARY);
   471                     printObject("constValue", type.constValue(), Details.SUMMARY);
   472                     printObject("annotations", type.getAnnotationMirrors(), Details.SUMMARY);
   473                     type.accept(typeVisitor, null);
   474                     indent(-1);
   475             }
   476         }
   477     }
   479     protected String toString(Type type) {
   480         return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
   481     }
   483     protected String hashString(Object obj) {
   484         return String.format("#%x", obj.hashCode());
   485     }
   487     protected String info(Class<?> clazz, Object internal, Object external) {
   488         return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
   489     }
   491     private int indent = 0;
   493     protected void indent() {
   494         for (int i = 0; i < indent; i++) {
   495             out.print("  ");
   496         }
   497     }
   499     protected void indent(int n) {
   500         indent += n;
   501     }
   503     protected Object getField(Object o, Class<?> clazz, String name) {
   504         try {
   505             Field f = clazz.getDeclaredField(name);
   506             boolean prev = f.isAccessible();
   507             f.setAccessible(true);
   508             try {
   509                 return f.get(o);
   510             } finally {
   511                 f.setAccessible(prev);
   512             }
   513         } catch (ReflectiveOperationException e) {
   514             return e;
   515         } catch (SecurityException e) {
   516             return e;
   517         }
   518     }
   520     // </editor-fold>
   522     // <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
   524     protected JCTree.Visitor treeVisitor = new TreeVisitor();
   526     /**
   527      * Default visitor class for JCTree (AST) objects.
   528      */
   529     public class TreeVisitor extends JCTree.Visitor {
   530         @Override
   531         public void visitTopLevel(JCCompilationUnit tree) {
   532             printList("packageAnnotations", tree.packageAnnotations);
   533             printTree("pid", tree.pid);
   534             printList("defs", tree.defs);
   535         }
   537         @Override
   538         public void visitImport(JCImport tree) {
   539             printTree("qualid", tree.qualid);
   540         }
   542         @Override
   543         public void visitClassDef(JCClassDecl tree) {
   544             printName("name", tree.name);
   545             printTree("mods", tree.mods);
   546             printList("typarams", tree.typarams);
   547             printTree("extending", tree.extending);
   548             printList("implementing", tree.implementing);
   549             printList("defs", tree.defs);
   550         }
   552         @Override
   553         public void visitMethodDef(JCMethodDecl tree) {
   554             printName("name", tree.name);
   555             printTree("mods", tree.mods);
   556             printTree("restype", tree.restype);
   557             printList("typarams", tree.typarams);
   558             printTree("recvparam", tree.recvparam);
   559             printList("params", tree.params);
   560             printList("thrown", tree.thrown);
   561             printTree("defaultValue", tree.defaultValue);
   562             printTree("body", tree.body);
   563         }
   565         @Override
   566         public void visitVarDef(JCVariableDecl tree) {
   567             printName("name", tree.name);
   568             printTree("mods", tree.mods);
   569             printTree("vartype", tree.vartype);
   570             printTree("init", tree.init);
   571         }
   573         @Override
   574         public void visitSkip(JCSkip tree) {
   575         }
   577         @Override
   578         public void visitBlock(JCBlock tree) {
   579             printList("stats", tree.stats);
   580         }
   582         @Override
   583         public void visitDoLoop(JCDoWhileLoop tree) {
   584             printTree("body", tree.body);
   585             printTree("cond", tree.cond);
   586         }
   588         @Override
   589         public void visitWhileLoop(JCWhileLoop tree) {
   590             printTree("cond", tree.cond);
   591             printTree("body", tree.body);
   592         }
   594         @Override
   595         public void visitForLoop(JCForLoop tree) {
   596             printList("init", tree.init);
   597             printTree("cond", tree.cond);
   598             printList("step", tree.step);
   599             printTree("body", tree.body);
   600         }
   602         @Override
   603         public void visitForeachLoop(JCEnhancedForLoop tree) {
   604             printTree("var", tree.var);
   605             printTree("expr", tree.expr);
   606             printTree("body", tree.body);
   607         }
   609         @Override
   610         public void visitLabelled(JCLabeledStatement tree) {
   611             printTree("body", tree.body);
   612         }
   614         @Override
   615         public void visitSwitch(JCSwitch tree) {
   616             printTree("selector", tree.selector);
   617             printList("cases", tree.cases);
   618         }
   620         @Override
   621         public void visitCase(JCCase tree) {
   622             printTree("pat", tree.pat);
   623             printList("stats", tree.stats);
   624         }
   626         @Override
   627         public void visitSynchronized(JCSynchronized tree) {
   628             printTree("lock", tree.lock);
   629             printTree("body", tree.body);
   630         }
   632         @Override
   633         public void visitTry(JCTry tree) {
   634             printList("resources", tree.resources);
   635             printTree("body", tree.body);
   636             printList("catchers", tree.catchers);
   637             printTree("finalizer", tree.finalizer);
   638         }
   640         @Override
   641         public void visitCatch(JCCatch tree) {
   642             printTree("param", tree.param);
   643             printTree("body", tree.body);
   644         }
   646         @Override
   647         public void visitConditional(JCConditional tree) {
   648             printTree("cond", tree.cond);
   649             printTree("truepart", tree.truepart);
   650             printTree("falsepart", tree.falsepart);
   651         }
   653         @Override
   654         public void visitIf(JCIf tree) {
   655             printTree("cond", tree.cond);
   656             printTree("thenpart", tree.thenpart);
   657             printTree("elsepart", tree.elsepart);
   658         }
   660         @Override
   661         public void visitExec(JCExpressionStatement tree) {
   662             printTree("expr", tree.expr);
   663         }
   665         @Override
   666         public void visitBreak(JCBreak tree) {
   667             printName("label", tree.label);
   668         }
   670         @Override
   671         public void visitContinue(JCContinue tree) {
   672             printName("label", tree.label);
   673         }
   675         @Override
   676         public void visitReturn(JCReturn tree) {
   677             printTree("expr", tree.expr);
   678         }
   680         @Override
   681         public void visitThrow(JCThrow tree) {
   682             printTree("expr", tree.expr);
   683         }
   685         @Override
   686         public void visitAssert(JCAssert tree) {
   687             printTree("cond", tree.cond);
   688             printTree("detail", tree.detail);
   689         }
   691         @Override
   692         public void visitApply(JCMethodInvocation tree) {
   693             printList("typeargs", tree.typeargs);
   694             printTree("meth", tree.meth);
   695             printList("args", tree.args);
   696         }
   698         @Override
   699         public void visitNewClass(JCNewClass tree) {
   700             printTree("encl", tree.encl);
   701             printList("typeargs", tree.typeargs);
   702             printTree("clazz", tree.clazz);
   703             printList("args", tree.args);
   704             printTree("def", tree.def);
   705         }
   707         @Override
   708         public void visitNewArray(JCNewArray tree) {
   709             printList("annotations", tree.annotations);
   710             printTree("elemtype", tree.elemtype);
   711             printList("dims", tree.dims);
   712             printList("dimAnnotations", tree.dimAnnotations);
   713             printList("elems", tree.elems);
   714         }
   716         @Override
   717         public void visitLambda(JCLambda tree) {
   718             printTree("body", tree.body);
   719             printList("params", tree.params);
   720         }
   722         @Override
   723         public void visitParens(JCParens tree) {
   724             printTree("expr", tree.expr);
   725         }
   727         @Override
   728         public void visitAssign(JCAssign tree) {
   729             printTree("lhs", tree.lhs);
   730             printTree("rhs", tree.rhs);
   731         }
   733         @Override
   734         public void visitAssignop(JCAssignOp tree) {
   735             printTree("lhs", tree.lhs);
   736             printTree("rhs", tree.rhs);
   737         }
   739         @Override
   740         public void visitUnary(JCUnary tree) {
   741             printTree("arg", tree.arg);
   742         }
   744         @Override
   745         public void visitBinary(JCBinary tree) {
   746             printTree("lhs", tree.lhs);
   747             printTree("rhs", tree.rhs);
   748         }
   750         @Override
   751         public void visitTypeCast(JCTypeCast tree) {
   752             printTree("clazz", tree.clazz);
   753             printTree("expr", tree.expr);
   754         }
   756         @Override
   757         public void visitTypeTest(JCInstanceOf tree) {
   758             printTree("expr", tree.expr);
   759             printTree("clazz", tree.clazz);
   760         }
   762         @Override
   763         public void visitIndexed(JCArrayAccess tree) {
   764             printTree("indexed", tree.indexed);
   765             printTree("index", tree.index);
   766         }
   768         @Override
   769         public void visitSelect(JCFieldAccess tree) {
   770             printTree("selected", tree.selected);
   771         }
   773         @Override
   774         public void visitReference(JCMemberReference tree) {
   775             printTree("expr", tree.expr);
   776             printList("typeargs", tree.typeargs);
   777         }
   779         @Override
   780         public void visitIdent(JCIdent tree) {
   781             printName("name", tree.name);
   782         }
   784         @Override
   785         public void visitLiteral(JCLiteral tree) {
   786             printString("value", Pretty.toSimpleString(tree, 32));
   787         }
   789         @Override
   790         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
   791             printString("typetag", tree.typetag.name());
   792         }
   794         @Override
   795         public void visitTypeArray(JCArrayTypeTree tree) {
   796             printTree("elemtype", tree.elemtype);
   797         }
   799         @Override
   800         public void visitTypeApply(JCTypeApply tree) {
   801             printTree("clazz", tree.clazz);
   802             printList("arguments", tree.arguments);
   803         }
   805         @Override
   806         public void visitTypeUnion(JCTypeUnion tree) {
   807             printList("alternatives", tree.alternatives);
   808         }
   810         @Override
   811         public void visitTypeIntersection(JCTypeIntersection tree) {
   812             printList("bounds", tree.bounds);
   813         }
   815         @Override
   816         public void visitTypeParameter(JCTypeParameter tree) {
   817             printName("name", tree.name);
   818             printList("annotations", tree.annotations);
   819             printList("bounds", tree.bounds);
   820         }
   822         @Override
   823         public void visitWildcard(JCWildcard tree) {
   824             printTree("kind", tree.kind);
   825             printTree("inner", tree.inner);
   826         }
   828         @Override
   829         public void visitTypeBoundKind(TypeBoundKind tree) {
   830             printString("kind", tree.kind.name());
   831         }
   833         @Override
   834         public void visitModifiers(JCModifiers tree) {
   835             printList("annotations", tree.annotations);
   836             printString("flags", String.valueOf(Flags.asFlagSet(tree.flags)));
   837         }
   839         @Override
   840         public void visitAnnotation(JCAnnotation tree) {
   841             printTree("annotationType", tree.annotationType);
   842             printList("args", tree.args);
   843         }
   845         @Override
   846         public void visitAnnotatedType(JCAnnotatedType tree) {
   847             printList("annotations", tree.annotations);
   848             printTree("underlyingType", tree.underlyingType);
   849         }
   851         @Override
   852         public void visitErroneous(JCErroneous tree) {
   853             printList("errs", tree.errs);
   854         }
   856         @Override
   857         public void visitLetExpr(LetExpr tree) {
   858             printList("defs", tree.defs);
   859             printTree("expr", tree.expr);
   860         }
   862         @Override
   863         public void visitTree(JCTree tree) {
   864             Assert.error();
   865         }
   866     }
   868     // </editor-fold>
   870     // <editor-fold defaultstate="collapsed" desc="Symbol visitor">
   872     protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
   874     /**
   875      * Default visitor class for Symbol objects.
   876      * Note: each visitXYZ method ends by calling the corresponding
   877      * visit method for its superclass.
   878      */
   879     class SymbolVisitor implements Symbol.Visitor<Void,Void> {
   880         @Override
   881         public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
   882             printName("fullname", sym.fullname);
   883             printName("flatname", sym.flatname);
   884             printScope("members", sym.members_field);
   885             printFileObject("sourcefile", sym.sourcefile);
   886             printFileObject("classfile", sym.classfile);
   887             // trans-local?
   888             // pool?
   889             return visitTypeSymbol(sym, null);
   890         }
   892         @Override
   893         public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
   894             // code
   895             printList("params", sym.params);
   896             printList("savedParameterNames", sym.savedParameterNames);
   897             return visitSymbol(sym, null);
   898         }
   900         @Override
   901         public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
   902             printName("fullname", sym.fullname);
   903             printScope("members", sym.members_field);
   904             printSymbol("package-info", sym.package_info, Details.SUMMARY);
   905             return visitTypeSymbol(sym, null);
   906         }
   908         @Override
   909         public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
   910             printInt("opcode", sym.opcode);
   911             return visitMethodSymbol(sym, null);
   912         }
   914         @Override
   915         public Void visitVarSymbol(VarSymbol sym, Void ignore) {
   916             printInt("pos", sym.pos);
   917             printInt("adm", sym.adr);
   918             // data is a private field, and the standard accessors may
   919             // mutate it as part of lazy evaluation. Therefore, use
   920             // reflection to get the raw data.
   921             printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
   922             return visitSymbol(sym, null);
   923         }
   925         @Override
   926         public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
   927             return visitSymbol(sym, null);
   928         }
   930         @Override
   931         public Void visitSymbol(Symbol sym, Void ignore) {
   932             return null;
   933         }
   934     }
   936     // </editor-fold>
   938     // <editor-fold defaultstate="collapsed" desc="Type visitor">
   940     protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
   942     /**
   943      * Default visitor class for Type objects.
   944      * Note: each visitXYZ method ends by calling the corresponding
   945      * visit method for its superclass.
   946      */
   947     public class TypeVisitor implements Type.Visitor<Void,Void> {
   948         public Void visitAnnotatedType(AnnotatedType type, Void ignore) {
   949             printList("typeAnnotations", type.getAnnotationMirrors());
   950             printType("underlyingType", type.unannotatedType(), Details.FULL);
   951             return visitType(type, null);
   952         }
   954         public Void visitArrayType(ArrayType type, Void ignore) {
   955             printType("elemType", type.elemtype, Details.FULL);
   956             return visitType(type, null);
   957         }
   959         public Void visitCapturedType(CapturedType type, Void ignore) {
   960             printType("wildcard", type.wildcard, Details.FULL);
   961             return visitTypeVar(type, null);
   962         }
   964         public Void visitClassType(ClassType type, Void ignore) {
   965             printType("outer", type.getEnclosingType(), Details.SUMMARY);
   966             printList("typarams", type.typarams_field);
   967             printList("allparams", type.allparams_field);
   968             printType("supertype", type.supertype_field, Details.SUMMARY);
   969             printList("interfaces", type.interfaces_field);
   970             printList("allinterfaces", type.all_interfaces_field);
   971             return visitType(type, null);
   972         }
   974         public Void visitErrorType(ErrorType type, Void ignore) {
   975             printType("originalType", type.getOriginalType(), Details.FULL);
   976             return visitClassType(type, null);
   977         }
   979         public Void visitForAll(ForAll type, Void ignore) {
   980             printList("tvars", type.tvars);
   981             return visitDelegatedType(type);
   982         }
   984         public Void visitMethodType(MethodType type, Void ignore) {
   985             printList("argtypes", type.argtypes);
   986             printType("restype", type.restype, Details.FULL);
   987             printList("thrown", type.thrown);
   988             return visitType(type, null);
   989         }
   991         public Void visitPackageType(PackageType type, Void ignore) {
   992             return visitType(type, null);
   993         }
   995         public Void visitTypeVar(TypeVar type, Void ignore) {
   996             // For TypeVars (and not subtypes), the bound should always be
   997             // null or bot. So, only print the bound for subtypes of TypeVar,
   998             // or if the bound is (erroneously) not null or bot.
   999             if (!type.hasTag(TypeTag.TYPEVAR)
  1000                     || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) {
  1001                 printType("bound", type.bound, Details.FULL);
  1003             printType("lower", type.lower, Details.FULL);
  1004             return visitType(type, null);
  1007         public Void visitUndetVar(UndetVar type, Void ignore) {
  1008             for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
  1009                 printList("bounds." + ib, type.getBounds(ib));
  1010             printInt("declaredCount", type.declaredCount);
  1011             printType("inst", type.inst, Details.SUMMARY);
  1012             return visitDelegatedType(type);
  1015         public Void visitWildcardType(WildcardType type, Void ignore) {
  1016             printType("type", type.type, Details.SUMMARY);
  1017             printString("kind", type.kind.name());
  1018             printType("bound", type.bound, Details.SUMMARY);
  1019             return visitType(type, null);
  1022         protected Void visitDelegatedType(DelegatedType type) {
  1023             printType("qtype", type.qtype, Details.FULL);
  1024             return visitType(type, null);
  1027         public Void visitType(Type type, Void ignore) {
  1028             return null;
  1032     // </editor-fold>
  1034     // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
  1036     protected Attribute.Visitor attrVisitor = new AttributeVisitor();
  1038     /**
  1039      * Default visitor class for Attribute (annotation) objects.
  1040      */
  1041     public class AttributeVisitor implements Attribute.Visitor {
  1043         public void visitConstant(Attribute.Constant a) {
  1044             printObject("value", a.value, Details.SUMMARY);
  1045             visitAttribute(a);
  1048         public void visitClass(Attribute.Class a) {
  1049             printObject("classType", a.classType, Details.SUMMARY);
  1050             visitAttribute(a);
  1053         public void visitCompound(Attribute.Compound a) {
  1054             if (a instanceof Attribute.TypeCompound) {
  1055                 Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
  1056                 // consider a custom printer?
  1057                 printObject("position", ta.position, Details.SUMMARY);
  1059             printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
  1060             printList("values", a.values);
  1061             visitAttribute(a);
  1064         public void visitArray(Attribute.Array a) {
  1065             printList("values", Arrays.asList(a.values));
  1066             visitAttribute(a);
  1069         public void visitEnum(Attribute.Enum a) {
  1070             printSymbol("value", a.value, Details.SUMMARY);
  1071             visitAttribute(a);
  1074         public void visitError(Attribute.Error a) {
  1075             visitAttribute(a);
  1078         public void visitAttribute(Attribute a) {
  1079             printType("type", a.type, Details.SUMMARY);
  1083     // </editor-fold>
  1085     // <editor-fold defaultstate="collapsed" desc="Utility front end">
  1087     /**
  1088      * Utility class to invoke DPrinter from the command line.
  1089      */
  1090     static class Main {
  1091         public static void main(String... args) throws IOException {
  1092             Main m = new Main();
  1093             PrintWriter out = new PrintWriter(System.out);
  1094             try {
  1095                 if (args.length == 0)
  1096                     m.usage(out);
  1097                 else
  1098                     m.run(out, args);
  1099             } finally {
  1100                 out.flush();
  1104         void usage(PrintWriter out) {
  1105             out.println("Usage:");
  1106             out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
  1107             out.print("where mode is one of: ");
  1108             String sep = "";
  1109             for (Handler h: getHandlers().values()) {
  1110                 out.print(sep);
  1111                 out.print(h.name);
  1112                 sep = ", ";
  1114             out.println();
  1115             out.println("and where options include:");
  1116             out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
  1117             out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
  1118             out.println("  -showPositions");
  1119             out.println("  -showSource");
  1120             out.println("  -showTreeSymbols");
  1121             out.println("  -showTreeTypes");
  1122             out.println("  -hideEmptyItems");
  1123             out.println("  -hideNulls");
  1126         void run(PrintWriter out, String... args) throws IOException {
  1127             JavaCompiler c = ToolProvider.getSystemJavaCompiler();
  1128             StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
  1130             // DPrinter options
  1131             final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
  1132             final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
  1133             boolean showPositions = false;
  1134             boolean showSource = false;
  1135             boolean showTreeSymbols = false;
  1136             boolean showTreeTypes = false;
  1137             boolean showEmptyItems = true;
  1138             boolean showNulls = true;
  1140             // javac options
  1141             Collection<String> options = new ArrayList<String>();
  1142             Collection<File> files = new ArrayList<File>();
  1143             String classpath = null;
  1144             String classoutdir = null;
  1146             final Handler h = getHandlers().get(args[0]);
  1147             if (h == null)
  1148                 throw new IllegalArgumentException(args[0]);
  1150             for (int i = 1; i < args.length; i++) {
  1151                 String arg = args[i];
  1152                 if (arg.equals("-before") && i + 1 < args.length) {
  1153                     before.add(getKind(args[++i]));
  1154                 } else if (arg.equals("-after") && i + 1 < args.length) {
  1155                     after.add(getKind(args[++i]));
  1156                 } else if (arg.equals("-showPositions")) {
  1157                     showPositions = true;
  1158                 } else if (arg.equals("-showSource")) {
  1159                     showSource = true;
  1160                 } else if (arg.equals("-showTreeSymbols")) {
  1161                     showTreeSymbols = true;
  1162                 } else if (arg.equals("-showTreeTypes")) {
  1163                     showTreeTypes = true;
  1164                 } else if (arg.equals("-hideEmptyLists")) {
  1165                     showEmptyItems = false;
  1166                 } else if (arg.equals("-hideNulls")) {
  1167                     showNulls = false;
  1168                 } else if (arg.equals("-classpath") && i + 1 < args.length) {
  1169                     classpath = args[++i];
  1170                 } else if (arg.equals("-d") && i + 1 < args.length) {
  1171                     classoutdir = args[++i];
  1172                 } else if (arg.startsWith("-")) {
  1173                     int n = c.isSupportedOption(arg);
  1174                     if (n < 0) throw new IllegalArgumentException(arg);
  1175                     options.add(arg);
  1176                     while (n > 0) options.add(args[++i]);
  1177                 } else if (arg.endsWith(".java")) {
  1178                     files.add(new File(arg));
  1182             if (classoutdir != null) {
  1183                 fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
  1186             if (classpath != null) {
  1187                 Collection<File> path = new ArrayList<File>();
  1188                 for (String p: classpath.split(File.pathSeparator)) {
  1189                     if (p.isEmpty()) continue;
  1190                     File f = new File(p);
  1191                     if (f.exists()) path.add(f);
  1193                 fm.setLocation(StandardLocation.CLASS_PATH, path);
  1195             Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
  1197             JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
  1198             final Trees trees = Trees.instance(task);
  1200             final DPrinter dprinter = new DPrinter(out, trees);
  1201             dprinter.source(showSource)
  1202                     .emptyItems(showEmptyItems)
  1203                     .nulls(showNulls)
  1204                     .positions(showPositions)
  1205                     .treeSymbols(showTreeSymbols)
  1206                     .treeTypes(showTreeTypes);
  1208             if (before.isEmpty() && after.isEmpty()) {
  1209                 if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
  1210                     after.add(TaskEvent.Kind.PARSE);
  1211                 else
  1212                     after.add(TaskEvent.Kind.ANALYZE);
  1215             task.addTaskListener(new TaskListener() {
  1216                 public void started(TaskEvent e) {
  1217                     if (before.contains(e.getKind()))
  1218                         handle(e);
  1221                 public void finished(TaskEvent e) {
  1222                     if (after.contains(e.getKind()))
  1223                         handle(e);
  1226                 private void handle(TaskEvent e) {
  1227                      switch (e.getKind()) {
  1228                          case PARSE:
  1229                          case ENTER:
  1230                              h.handle(e.getSourceFile().getName(),
  1231                                      (JCTree) e.getCompilationUnit(),
  1232                                      dprinter);
  1233                              break;
  1235                          default:
  1236                              TypeElement elem = e.getTypeElement();
  1237                              h.handle(elem.toString(),
  1238                                      (JCTree) trees.getTree(elem),
  1239                                      dprinter);
  1240                              break;
  1243             });
  1245             task.call();
  1248         TaskEvent.Kind getKind(String s) {
  1249             return TaskEvent.Kind.valueOf(s.toUpperCase());
  1252         static protected abstract class Handler {
  1253             final String name;
  1254             Handler(String name) {
  1255                 this.name = name;
  1257             abstract void handle(String label, JCTree tree, DPrinter dprinter);
  1260         Map<String,Handler> getHandlers() {
  1261             Map<String,Handler> map = new HashMap<String, Handler>();
  1262             for (Handler h: defaultHandlers) {
  1263                 map.put(h.name, h);
  1265             return map;
  1268         protected final Handler[] defaultHandlers = {
  1269             new Handler("trees") {
  1270                 @Override
  1271                 void handle(String name, JCTree tree, DPrinter dprinter) {
  1272                     dprinter.printTree(name, tree);
  1273                     dprinter.out.println();
  1275             },
  1277             new Handler("symbols") {
  1278                 @Override
  1279                 void handle(String name, JCTree tree, final DPrinter dprinter) {
  1280                     TreeScanner ds = new TreeScanner() {
  1281                         @Override
  1282                         public void visitClassDef(JCClassDecl tree) {
  1283                             visitDecl(tree, tree.sym);
  1284                             super.visitClassDef(tree);
  1287                         @Override
  1288                         public void visitMethodDef(JCMethodDecl tree) {
  1289                             visitDecl(tree, tree.sym);
  1290                             super.visitMethodDef(tree);
  1293                         @Override
  1294                         public void visitVarDef(JCVariableDecl tree) {
  1295                             visitDecl(tree, tree.sym);
  1296                             super.visitVarDef(tree);
  1299                         void visitDecl(JCTree tree, Symbol sym) {
  1300                             dprinter.printSymbol(sym.name.toString(), sym);
  1301                             dprinter.out.println();
  1303                     };
  1304                     ds.scan(tree);
  1306             },
  1308             new Handler("types") {
  1309                 @Override
  1310                 void handle(String name, JCTree tree, final DPrinter dprinter) {
  1311                     TreeScanner ts = new TreeScanner() {
  1312                         @Override
  1313                         public void scan(JCTree tree) {
  1314                             if (tree == null) {
  1315                                 return;
  1317                             if (tree.type != null) {
  1318                                 String label = Pretty.toSimpleString(tree);
  1319                                 dprinter.printType(label, tree.type);
  1320                                 dprinter.out.println();
  1322                             super.scan(tree);
  1324                     };
  1325                     ts.scan(tree);
  1328         };
  1331     // </editor-fold>

mercurial