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             printName("label", tree.label);
 786         }
 787 
 788         @Override
 789         public void visitYield(JCYield tree) {
 790             printTree("value", tree.value);
 791         }
 792 
 793         @Override
 794         public void visitContinue(JCContinue tree) {
 795             printName("label", tree.label);
 796         }
 797 
 798         @Override
 799         public void visitReturn(JCReturn tree) {
 800             printTree("expr", tree.expr);
 801         }
 802 
 803         @Override
 804         public void visitThrow(JCThrow tree) {
 805             printTree("expr", tree.expr);
 806         }
 807 
 808         @Override
 809         public void visitAssert(JCAssert tree) {
 810             printTree("cond", tree.cond);
 811             printTree("detail", tree.detail);
 812         }
 813 
 814         @Override
 815         public void visitApply(JCMethodInvocation tree) {
 816             printList("typeargs", tree.typeargs);
 817             printTree("meth", tree.meth);
 818             printList("args", tree.args);
 819         }
 820 
 821         @Override
 822         public void visitNewClass(JCNewClass tree) {
 823             printTree("encl", tree.encl);
 824             printList("typeargs", tree.typeargs);
 825             printTree("clazz", tree.clazz);
 826             printList("args", tree.args);
 827             printTree("def", tree.def);
 828         }
 829 
 830         @Override
 831         public void visitNewArray(JCNewArray tree) {
 832             printList("annotations", tree.annotations);
 833             printTree("elemtype", tree.elemtype);
 834             printList("dims", tree.dims);
 835             printList("dimAnnotations", tree.dimAnnotations);
 836             printList("elems", tree.elems);
 837         }
 838 
 839         @Override
 840         public void visitLambda(JCLambda tree) {
 841             printTree("body", tree.body);
 842             printList("params", tree.params);
 843         }
 844 
 845         @Override
 846         public void visitParens(JCParens tree) {
 847             printTree("expr", tree.expr);
 848         }
 849 
 850         @Override
 851         public void visitAssign(JCAssign tree) {
 852             printTree("lhs", tree.lhs);
 853             printTree("rhs", tree.rhs);
 854         }
 855 
 856         @Override
 857         public void visitAssignop(JCAssignOp tree) {
 858             printTree("lhs", tree.lhs);
 859             printTree("rhs", tree.rhs);
 860         }
 861 
 862         @Override
 863         public void visitUnary(JCUnary tree) {
 864             printTree("arg", tree.arg);
 865         }
 866 
 867         @Override
 868         public void visitBinary(JCBinary tree) {
 869             printTree("lhs", tree.lhs);
 870             printTree("rhs", tree.rhs);
 871         }
 872 
 873         @Override
 874         public void visitTypeCast(JCTypeCast tree) {
 875             printTree("clazz", tree.clazz);
 876             printTree("expr", tree.expr);
 877         }
 878 
 879         @Override
 880         public void visitTypeTest(JCInstanceOf tree) {
 881             printTree("expr", tree.expr);
 882             printTree("pattern", tree.pattern);
 883         }
 884 
 885         @Override
 886         public void visitIndexed(JCArrayAccess tree) {
 887             printTree("indexed", tree.indexed);
 888             printTree("index", tree.index);
 889         }
 890 
 891         @Override
 892         public void visitSelect(JCFieldAccess tree) {
 893             printTree("selected", tree.selected);
 894         }
 895 
 896         @Override
 897         public void visitReference(JCMemberReference tree) {
 898             printTree("expr", tree.expr);
 899             printList("typeargs", tree.typeargs);
 900         }
 901 
 902         @Override
 903         public void visitIdent(JCIdent tree) {
 904             printName("name", tree.name);
 905         }
 906 
 907         @Override
 908         public void visitLiteral(JCLiteral tree) {
 909             printString("value", Pretty.toSimpleString(tree, 32));
 910         }
 911 
 912         @Override
 913         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
 914             printString("typetag", tree.typetag.name());
 915         }
 916 
 917         @Override
 918         public void visitTypeArray(JCArrayTypeTree tree) {
 919             printTree("elemtype", tree.elemtype);
 920         }
 921 
 922         @Override
 923         public void visitTypeApply(JCTypeApply tree) {
 924             printTree("clazz", tree.clazz);
 925             printList("arguments", tree.arguments);
 926         }
 927 
 928         @Override
 929         public void visitTypeUnion(JCTypeUnion tree) {
 930             printList("alternatives", tree.alternatives);
 931         }
 932 
 933         @Override
 934         public void visitTypeIntersection(JCTypeIntersection tree) {
 935             printList("bounds", tree.bounds);
 936         }
 937 
 938         @Override
 939         public void visitTypeParameter(JCTypeParameter tree) {
 940             printName("name", tree.name);
 941             printList("annotations", tree.annotations);
 942             printList("bounds", tree.bounds);
 943         }
 944 
 945         @Override
 946         public void visitWildcard(JCWildcard tree) {
 947             printTree("kind", tree.kind);
 948             printTree("inner", tree.inner);
 949         }
 950 
 951         @Override
 952         public void visitTypeBoundKind(TypeBoundKind tree) {
 953             printString("kind", tree.kind.name());
 954         }
 955 
 956         @Override
 957         public void visitModifiers(JCModifiers tree) {
 958             printList("annotations", tree.annotations);
 959             printString("flags", String.valueOf(Flags.asFlagSet(tree.flags)));
 960         }
 961 
 962         @Override
 963         public void visitAnnotation(JCAnnotation tree) {
 964             printTree("annotationType", tree.annotationType);
 965             printList("args", tree.args);
 966         }
 967 
 968         @Override
 969         public void visitAnnotatedType(JCAnnotatedType tree) {
 970             printList("annotations", tree.annotations);
 971             printTree("underlyingType", tree.underlyingType);
 972         }
 973 
 974         @Override
 975         public void visitErroneous(JCErroneous tree) {
 976             printList("errs", tree.errs);
 977         }
 978 
 979         @Override
 980         public void visitLetExpr(LetExpr tree) {
 981             printList("defs", tree.defs);
 982             printTree("expr", tree.expr);
 983         }
 984 
 985         @Override
 986         public void visitTree(JCTree tree) {
 987             Assert.error();
 988         }
 989     }
 990 
 991     // </editor-fold>
 992 
 993     // <editor-fold defaultstate="collapsed" desc="DocTree visitor">
 994 
 995     protected DocTreeVisitor<Void,Void> docTreeVisitor = new DefaultDocTreeVisitor();
 996 
 997     /**
 998      * Default visitor class for DocTree objects.
 999      * Note: each visitXYZ method ends by calling the corresponding
1000      * visit method for its superclass.
1001      */
1002     class DefaultDocTreeVisitor implements DocTreeVisitor<Void,Void> {
1003 
1004         public Void visitAttribute(AttributeTree node, Void p) {
1005             printName("name", node.getName());
1006             printString("vkind", node.getValueKind().name());
1007             printList("value", node.getValue());
1008             return visitTree(node, null);
1009         }
1010 
1011         public Void visitAuthor(AuthorTree node, Void p) {
1012             printList("name", node.getName());
1013             return visitBlockTag(node, null);
1014         }
1015 
1016         public Void visitComment(CommentTree node, Void p) {
1017             printLimitedEscapedString("body", node.getBody());
1018             return visitTree(node, null);
1019         }
1020 
1021         public Void visitDeprecated(DeprecatedTree node, Void p) {
1022             printList("body", node.getBody());
1023             return visitBlockTag(node, null);
1024         }
1025 
1026         public Void visitDocComment(DocCommentTree node, Void p) {
1027             printList("firstSentence", node.getFirstSentence());
1028             printList("body", node.getBody());
1029             printList("tags", node.getBlockTags());
1030             return visitTree(node, null);
1031         }
1032 
1033         public Void visitDocRoot(DocRootTree node, Void p) {
1034             return visitInlineTag(node, null);
1035         }
1036 
1037         @Override
1038         public Void visitDocType(DocTypeTree node, Void aVoid) {
1039             printLimitedEscapedString("body", node.getText());
1040             return visitTree(node, null);
1041         }
1042 
1043         public Void visitEndElement(EndElementTree node, Void p) {
1044             printName("name", node.getName());
1045             return visitTree(node, null);
1046         }
1047 
1048         public Void visitEntity(EntityTree node, Void p) {
1049             printName("name", node.getName());
1050             return visitTree(node, null);
1051         }
1052 
1053         public Void visitErroneous(ErroneousTree node, Void p) {
1054             printLimitedEscapedString("body", node.getBody());
1055             printString("diag", node.getDiagnostic().getMessage(Locale.getDefault()));
1056             return visitTree(node, null);
1057         }
1058 
1059         public Void visitHidden(HiddenTree node, Void p) {
1060             printList("body", node.getBody());
1061             return visitBlockTag(node, null);
1062         }
1063 
1064         public Void visitIdentifier(IdentifierTree node, Void p) {
1065             printName("name", node.getName());
1066             return visitTree(node, null);
1067         }
1068 
1069         public Void visitIndex(IndexTree node, Void p) {
1070             printString("kind", node.getKind().name());
1071             printDocTree("term", node.getSearchTerm());
1072             printList("desc", node.getDescription());
1073             return visitInlineTag(node, p);
1074         }
1075 
1076         public Void visitInheritDoc(InheritDocTree node, Void p) {
1077             return visitInlineTag(node, null);
1078         }
1079 
1080         public Void visitLink(LinkTree node, Void p) {
1081             printString("kind", node.getKind().name());
1082             printDocTree("ref", node.getReference());
1083             printList("list", node.getLabel());
1084             return visitInlineTag(node, null);
1085         }
1086 
1087         public Void visitLiteral(LiteralTree node, Void p) {
1088             printString("kind", node.getKind().name());
1089             printDocTree("body", node.getBody());
1090             return visitInlineTag(node, null);
1091         }
1092 
1093         public Void visitParam(ParamTree node, Void p) {
1094             printString("isTypeParameter", String.valueOf(node.isTypeParameter()));
1095             printString("kind", node.getKind().name());
1096             printList("desc", node.getDescription());
1097             return visitBlockTag(node, null);
1098         }
1099 
1100         public Void visitProvides(ProvidesTree node, Void p) {
1101             printString("kind", node.getKind().name());
1102             printDocTree("serviceType", node.getServiceType());
1103             printList("description", node.getDescription());
1104             return visitBlockTag(node, null);
1105         }
1106 
1107         public Void visitReference(ReferenceTree node, Void p) {
1108             printString("signature", node.getSignature());
1109             return visitTree(node, null);
1110         }
1111 
1112         public Void visitReturn(ReturnTree node, Void p) {
1113             printList("desc", node.getDescription());
1114             return visitBlockTag(node, null);
1115         }
1116 
1117         public Void visitSee(SeeTree node, Void p) {
1118             printList("ref", node.getReference());
1119             return visitBlockTag(node, null);
1120         }
1121 
1122         public Void visitSerial(SerialTree node, Void p) {
1123             printList("desc", node.getDescription());
1124             return visitBlockTag(node, null);
1125         }
1126 
1127         public Void visitSerialData(SerialDataTree node, Void p) {
1128             printList("desc", node.getDescription());
1129             return visitBlockTag(node, null);
1130         }
1131 
1132         public Void visitSerialField(SerialFieldTree node, Void p) {
1133             printDocTree("name", node.getName());
1134             printDocTree("type", node.getType());
1135             printList("desc", node.getDescription());
1136             return visitBlockTag(node, null);
1137         }
1138 
1139         public Void visitSince(SinceTree node, Void p) {
1140             printList("body", node.getBody());
1141             return visitBlockTag(node, null);
1142         }
1143 
1144         public Void visitStartElement(StartElementTree node, Void p) {
1145             printName("name", node.getName());
1146             printList("attrs", node.getAttributes());
1147             printString("selfClosing", String.valueOf(node.isSelfClosing()));
1148             return visitBlockTag(node, null);
1149         }
1150 
1151         public Void visitSummary(SummaryTree node, Void p) {
1152             printString("name", node.getTagName());
1153             printList("summary", node.getSummary());
1154             return visitInlineTag(node, null);
1155         }
1156 
1157         public Void visitText(TextTree node, Void p) {
1158             printLimitedEscapedString("body", node.getBody());
1159             return visitTree(node, null);
1160         }
1161 
1162         public Void visitThrows(ThrowsTree node, Void p) {
1163             printDocTree("name", node.getExceptionName());
1164             printList("desc", node.getDescription());
1165             return visitBlockTag(node, null);
1166         }
1167 
1168         public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
1169             printString("name", node.getTagName());
1170             printList("content", node.getContent());
1171             return visitBlockTag(node, null);
1172         }
1173 
1174         public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
1175             printString("name", node.getTagName());
1176             printList("content", node.getContent());
1177             return visitInlineTag(node, null);
1178         }
1179 
1180         public Void visitUses(UsesTree node, Void p) {
1181             printString("kind", node.getKind().name());
1182             printDocTree("serviceType", node.getServiceType());
1183             printList("description", node.getDescription());
1184             return visitBlockTag(node, null);
1185         }
1186 
1187         public Void visitValue(ValueTree node, Void p) {
1188             printDocTree("value", node.getReference());
1189             return visitInlineTag(node, null);
1190         }
1191 
1192         public Void visitVersion(VersionTree node, Void p) {
1193             printList("body", node.getBody());
1194             return visitBlockTag(node, null);
1195         }
1196 
1197         public Void visitOther(DocTree node, Void p) {
1198             return visitTree(node, null);
1199         }
1200 
1201         public Void visitBlockTag(DocTree node, Void p) {
1202             return visitTree(node, null);
1203         }
1204 
1205         public Void visitInlineTag(DocTree node, Void p) {
1206             return visitTree(node, null);
1207         }
1208 
1209         public Void visitTree(DocTree node, Void p) {
1210             return null;
1211         }
1212 
1213         @Override
1214         public Void visitAccessor(AccessorTree node, Void p) {
1215             printList("desc", node.getDescription());
1216             return visitTree(node, null);
1217         }
1218     }
1219 
1220     // </editor-fold>
1221 
1222     // <editor-fold defaultstate="collapsed" desc="Symbol visitor">
1223 
1224     protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
1225 
1226     /**
1227      * Default visitor class for Symbol objects.
1228      * Note: each visitXYZ method ends by calling the corresponding
1229      * visit method for its superclass.
1230      */
1231     class SymbolVisitor implements Symbol.Visitor<Void,Void> {
1232         @Override
1233         public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
1234             printName("fullname", sym.fullname);
1235             printName("flatname", sym.flatname);
1236             printScope("members", sym.members_field);
1237             printFileObject("sourcefile", sym.sourcefile);
1238             printFileObject("classfile", sym.classfile);
1239             // trans-local?
1240             // pool?
1241             return visitTypeSymbol(sym, null);
1242         }
1243 
1244         @Override
1245         public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
1246             // code
1247             printList("params", sym.params);
1248             return visitSymbol(sym, null);
1249         }
1250 
1251         @Override
1252         public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
1253             printName("fullname", sym.fullname);
1254             printScope("members", sym.members_field);
1255             printSymbol("package-info", sym.package_info, Details.SUMMARY);
1256             return visitTypeSymbol(sym, null);
1257         }
1258 
1259         @Override
1260         public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
1261             printInt("opcode", sym.opcode);
1262             return visitMethodSymbol(sym, null);
1263         }
1264 
1265         @Override
1266         public Void visitVarSymbol(VarSymbol sym, Void ignore) {
1267             printInt("pos", sym.pos);
1268             printInt("adm", sym.adr);
1269             // data is a private field, and the standard accessors may
1270             // mutate it as part of lazy evaluation. Therefore, use
1271             // reflection to get the raw data.
1272             printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
1273             return visitSymbol(sym, null);
1274         }
1275 
1276         @Override
1277         public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
1278             return visitSymbol(sym, null);
1279         }
1280 
1281         @Override
1282         public Void visitSymbol(Symbol sym, Void ignore) {
1283             return null;
1284         }
1285     }
1286 
1287     // </editor-fold>
1288 
1289     // <editor-fold defaultstate="collapsed" desc="Type visitor">
1290 
1291     protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
1292 
1293     /**
1294      * Default visitor class for Type objects.
1295      * Note: each visitXYZ method ends by calling the corresponding
1296      * visit method for its superclass.
1297      */
1298     public class TypeVisitor implements Type.Visitor<Void,Void> {
1299         public Void visitArrayType(ArrayType type, Void ignore) {
1300             printType("elemType", type.elemtype, Details.FULL);
1301             return visitType(type, null);
1302         }
1303 
1304         public Void visitCapturedType(CapturedType type, Void ignore) {
1305             printType("wildcard", type.wildcard, Details.FULL);
1306             return visitTypeVar(type, null);
1307         }
1308 
1309         public Void visitClassType(ClassType type, Void ignore) {
1310             printType("outer", type.getEnclosingType(), Details.SUMMARY);
1311             printList("typarams", type.typarams_field);
1312             printList("allparams", type.allparams_field);
1313             printType("supertype", type.supertype_field, Details.SUMMARY);
1314             printList("interfaces", type.interfaces_field);
1315             printList("allinterfaces", type.all_interfaces_field);
1316             return visitType(type, null);
1317         }
1318 
1319         public Void visitErrorType(ErrorType type, Void ignore) {
1320             printType("originalType", type.getOriginalType(), Details.FULL);
1321             return visitClassType(type, null);
1322         }
1323 
1324         public Void visitForAll(ForAll type, Void ignore) {
1325             printList("tvars", type.tvars);
1326             return visitDelegatedType(type);
1327         }
1328 
1329         public Void visitMethodType(MethodType type, Void ignore) {
1330             printList("argtypes", type.argtypes);
1331             printType("restype", type.restype, Details.FULL);
1332             printList("thrown", type.thrown);
1333             printType("recvtype", type.recvtype, Details.FULL);
1334             return visitType(type, null);
1335         }
1336 
1337         public Void visitModuleType(ModuleType type, Void ignore) {
1338             return visitType(type, null);
1339         }
1340 
1341         public Void visitPackageType(PackageType type, Void ignore) {
1342             return visitType(type, null);
1343         }
1344 
1345         public Void visitTypeVar(TypeVar type, Void ignore) {
1346             // For TypeVars (and not subtypes), the bound should always be
1347             // null or bot. So, only print the bound for subtypes of TypeVar,
1348             // or if the bound is (erroneously) not null or bot.
1349             if (!type.hasTag(TypeTag.TYPEVAR)
1350                     || !(type.getUpperBound() == null || type.getUpperBound().hasTag(TypeTag.BOT))) {
1351                 printType("bound", type.getUpperBound(), Details.FULL);
1352             }
1353             printType("lower", type.lower, Details.FULL);
1354             return visitType(type, null);
1355         }
1356 
1357         public Void visitUndetVar(UndetVar type, Void ignore) {
1358             for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1359                 printList("bounds." + ib, type.getBounds(ib));
1360             printInt("declaredCount", type.declaredCount);
1361             printType("inst", type.getInst(), Details.SUMMARY);
1362             return visitDelegatedType(type);
1363         }
1364 
1365         public Void visitWildcardType(WildcardType type, Void ignore) {
1366             printType("type", type.type, Details.SUMMARY);
1367             printString("kind", type.kind.name());
1368             printType("bound", type.bound, Details.SUMMARY);
1369             return visitType(type, null);
1370         }
1371 
1372         protected Void visitDelegatedType(DelegatedType type) {
1373             printType("qtype", type.qtype, Details.FULL);
1374             return visitType(type, null);
1375         }
1376 
1377         public Void visitType(Type type, Void ignore) {
1378             return null;
1379         }
1380     }
1381 
1382     // </editor-fold>
1383 
1384     // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1385 
1386     protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1387 
1388     /**
1389      * Default visitor class for Attribute (annotation) objects.
1390      */
1391     public class AttributeVisitor implements Attribute.Visitor {
1392 
1393         public void visitConstant(Attribute.Constant a) {
1394             printObject("value", a.value, Details.SUMMARY);
1395             visitAttribute(a);
1396         }
1397 
1398         public void visitClass(Attribute.Class a) {
1399             printObject("classType", a.classType, Details.SUMMARY);
1400             visitAttribute(a);
1401         }
1402 
1403         public void visitCompound(Attribute.Compound a) {
1404             if (a instanceof Attribute.TypeCompound) {
1405                 Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1406                 // consider a custom printer?
1407                 printObject("position", ta.position, Details.SUMMARY);
1408             }
1409             printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1410             printList("values", a.values);
1411             visitAttribute(a);
1412         }
1413 
1414         public void visitArray(Attribute.Array a) {
1415             printList("values", Arrays.asList(a.values));
1416             visitAttribute(a);
1417         }
1418 
1419         public void visitEnum(Attribute.Enum a) {
1420             printSymbol("value", a.value, Details.SUMMARY);
1421             visitAttribute(a);
1422         }
1423 
1424         public void visitError(Attribute.Error a) {
1425             visitAttribute(a);
1426         }
1427 
1428         public void visitAttribute(Attribute a) {
1429             printType("type", a.type, Details.SUMMARY);
1430         }
1431 
1432     }
1433     // </editor-fold>
1434 
1435     // <editor-fold defaultstate="collapsed" desc="Utility front end">
1436 
1437     /**
1438      * Utility class to invoke DPrinter from the command line.
1439      */
1440     static class Main {
1441         public static void main(String... args) throws IOException {
1442             Main m = new Main();
1443             PrintWriter out = new PrintWriter(System.out);
1444             try {
1445                 if (args.length == 0)
1446                     m.usage(out);
1447                 else
1448                     m.run(out, args);
1449             } finally {
1450                 out.flush();
1451             }
1452         }
1453 
1454         void usage(PrintWriter out) {
1455             out.println("Usage:");
1456             out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
1457             out.print("where mode is one of: ");
1458             String sep = "";
1459             for (Handler h: getHandlers().values()) {
1460                 out.print(sep);
1461                 out.print(h.name);
1462                 sep = ", ";
1463             }
1464             out.println();
1465             out.println("and where options include:");
1466             out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1467             out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1468             out.println("  -showPositions");
1469             out.println("  -showSource");
1470             out.println("  -showTreeSymbols");
1471             out.println("  -showTreeTypes");
1472             out.println("  -hideEmptyItems");
1473             out.println("  -hideNulls");
1474         }
1475 
1476         void run(PrintWriter out, String... args) throws IOException {
1477             JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1478             StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1479 
1480             // DPrinter options
1481             final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1482             final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1483             boolean showPositions = false;
1484             boolean showSource = false;
1485             boolean showTreeSymbols = false;
1486             boolean showTreeTypes = false;
1487             boolean showEmptyItems = true;
1488             boolean showNulls = true;
1489 
1490             // javac options
1491             Collection<String> options = new ArrayList<String>();
1492             Collection<File> files = new ArrayList<File>();
1493             String classpath = null;
1494             String classoutdir = null;
1495 
1496             final Handler h = getHandlers().get(args[0]);
1497             if (h == null)
1498                 throw new IllegalArgumentException(args[0]);
1499 
1500             for (int i = 1; i < args.length; i++) {
1501                 String arg = args[i];
1502                 if (arg.equals("-before") && i + 1 < args.length) {
1503                     before.add(getKind(args[++i]));
1504                 } else if (arg.equals("-after") && i + 1 < args.length) {
1505                     after.add(getKind(args[++i]));
1506                 } else if (arg.equals("-showPositions")) {
1507                     showPositions = true;
1508                 } else if (arg.equals("-showSource")) {
1509                     showSource = true;
1510                 } else if (arg.equals("-showTreeSymbols")) {
1511                     showTreeSymbols = true;
1512                 } else if (arg.equals("-showTreeTypes")) {
1513                     showTreeTypes = true;
1514                 } else if (arg.equals("-hideEmptyLists")) {
1515                     showEmptyItems = false;
1516                 } else if (arg.equals("-hideNulls")) {
1517                     showNulls = false;
1518                 } else if (arg.equals("-classpath") && i + 1 < args.length) {
1519                     classpath = args[++i];
1520                 } else if (arg.equals("-d") && i + 1 < args.length) {
1521                     classoutdir = args[++i];
1522                 } else if (arg.startsWith("-")) {
1523                     int n = c.isSupportedOption(arg);
1524                     if (n < 0) throw new IllegalArgumentException(arg);
1525                     options.add(arg);
1526                     while (n > 0) options.add(args[++i]);
1527                 } else if (arg.endsWith(".java")) {
1528                     files.add(new File(arg));
1529                 }
1530             }
1531 
1532             if (classoutdir != null) {
1533                 fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1534             }
1535 
1536             if (classpath != null) {
1537                 Collection<File> path = new ArrayList<File>();
1538                 for (String p: classpath.split(File.pathSeparator)) {
1539                     if (p.isEmpty()) continue;
1540                     File f = new File(p);
1541                     if (f.exists()) path.add(f);
1542                 }
1543                 fm.setLocation(StandardLocation.CLASS_PATH, path);
1544             }
1545             Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1546 
1547             JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1548             final Trees trees = Trees.instance(task);
1549 
1550             final DPrinter dprinter = new DPrinter(out, trees);
1551             dprinter.source(showSource)
1552                     .emptyItems(showEmptyItems)
1553                     .nulls(showNulls)
1554                     .positions(showPositions)
1555                     .treeSymbols(showTreeSymbols)
1556                     .treeTypes(showTreeTypes);
1557 
1558             if (before.isEmpty() && after.isEmpty()) {
1559                 if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1560                     after.add(TaskEvent.Kind.PARSE);
1561                 else
1562                     after.add(TaskEvent.Kind.ANALYZE);
1563             }
1564 
1565             task.addTaskListener(new TaskListener() {
1566                 public void started(TaskEvent e) {
1567                     if (before.contains(e.getKind()))
1568                         handle(e);
1569                 }
1570 
1571                 public void finished(TaskEvent e) {
1572                     if (after.contains(e.getKind()))
1573                         handle(e);
1574                 }
1575 
1576                 private void handle(TaskEvent e) {
1577                     JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1578                      switch (e.getKind()) {
1579                          case PARSE:
1580                          case ENTER:
1581                              h.handle(e.getSourceFile().getName(),
1582                                      unit, unit,
1583                                      dprinter);
1584                              break;
1585 
1586                          default:
1587                              TypeElement elem = e.getTypeElement();
1588                              h.handle(elem.toString(),
1589                                      unit, (JCTree) trees.getTree(elem),
1590                                      dprinter);
1591                              break;
1592                      }
1593                 }
1594             });
1595 
1596             task.call();
1597         }
1598 
1599         TaskEvent.Kind getKind(String s) {
1600             return TaskEvent.Kind.valueOf(s.toUpperCase());
1601         }
1602 
1603         static protected abstract class Handler {
1604             final String name;
1605             Handler(String name) {
1606                 this.name = name;
1607             }
1608             abstract void handle(String label,
1609                     JCCompilationUnit unit, JCTree tree,
1610                     DPrinter dprinter);
1611         }
1612 
1613         Map<String,Handler> getHandlers() {
1614             Map<String,Handler> map = new HashMap<String, Handler>();
1615             for (Handler h: defaultHandlers) {
1616                 map.put(h.name, h);
1617             }
1618             return map;
1619         }
1620 
1621         protected final Handler[] defaultHandlers = {
1622             new Handler("trees") {
1623                 @Override
1624                 void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1625                     dprinter.printTree(name, tree);
1626                     dprinter.out.println();
1627                 }
1628             },
1629 
1630             new Handler("doctrees") {
1631                 @Override
1632                 void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1633                     TreeScanner ds = new DeclScanner() {
1634                         public void visitDecl(JCTree tree, Symbol sym) {
1635                             DocTree dt = unit.docComments.getCommentTree(tree);
1636                             if (dt != null) {
1637                                 String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1638                                 dprinter.printDocTree(label, dt);
1639                                 dprinter.out.println();
1640                             }
1641                         }
1642                     };
1643                     ds.scan(tree);
1644                 }
1645             },
1646 
1647             new Handler("symbols") {
1648                 @Override
1649                 void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1650                     TreeScanner ds = new DeclScanner() {
1651                         public void visitDecl(JCTree tree, Symbol sym) {
1652                             String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1653                             dprinter.printSymbol(label, sym);
1654                             dprinter.out.println();
1655                         }
1656                     };
1657                     ds.scan(tree);
1658                 }
1659             },
1660 
1661             new Handler("types") {
1662                 @Override
1663                 void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1664                     TreeScanner ts = new TreeScanner() {
1665                         @Override
1666                         public void scan(JCTree tree) {
1667                             if (tree == null) {
1668                                 return;
1669                             }
1670                             if (tree.type != null) {
1671                                 String label = Pretty.toSimpleString(tree);
1672                                 dprinter.printType(label, tree.type);
1673                                 dprinter.out.println();
1674                             }
1675                             super.scan(tree);
1676                         }
1677                     };
1678                     ts.scan(tree);
1679                 }
1680             }
1681         };
1682     }
1683 
1684     protected static abstract class DeclScanner extends TreeScanner {
1685         @Override
1686         public void visitClassDef(JCClassDecl tree) {
1687             visitDecl(tree, tree.sym);
1688             super.visitClassDef(tree);
1689         }
1690 
1691         @Override
1692         public void visitMethodDef(JCMethodDecl tree) {
1693             visitDecl(tree, tree.sym);
1694             super.visitMethodDef(tree);
1695         }
1696 
1697         @Override
1698         public void visitVarDef(JCVariableDecl tree) {
1699             visitDecl(tree, tree.sym);
1700             super.visitVarDef(tree);
1701         }
1702 
1703         protected abstract void visitDecl(JCTree tree, Symbol sym);
1704     }
1705 
1706     // </editor-fold>
1707 
1708 }