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