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