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