Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
src.javacTransformer.lombok.ast.javac.JcTreePrinter Maven / Gradle / Ivy
Go to download
This is a very small fork of lombok.ast as some Android tools needed a few modifications. The normal repository for lombok.ast is here https://github.com/rzwitserloot/lombok.ast and our changes for 0.2.3 are in this pull request: https://github.com/rzwitserloot/lombok.ast/pull/8
/*
* Copyright (C) 2010 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.ast.javac;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import lombok.ast.StringLiteral;
import com.google.common.collect.MapMaker;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.main.OptionName;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCAssert;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCErroneous;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCSkip;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Options;
/**
* Diagnostic tool that turns a {@code JCTree} (javac) based tree into a hierarchical dump that should make
* it easy to analyse the exact structure of the AST.
*/
public class JcTreePrinter {
private final StringBuilder output = new StringBuilder();
private final boolean includePositions;
private final boolean includeObjectRefs;
private int indent;
private String rel;
private Map endPosTable;
private boolean modsOfEnum;
private final Map visited = new MapMaker().weakKeys().makeMap();
private int objectCounter = 0;
private static final Method GET_TAG_METHOD;
private static final Field TAG_FIELD;
//TODO Adopt the reflective printer principle used in the EcjTreePrinter. For example, we don't currently know if the type ref is shared or unique amongst
// JCVarDecls that all come from the same line: int[] x, y;
static {
Method m = null;
Field f = null;
try {
m = JCTree.class.getDeclaredMethod("getTag");
} catch (NoSuchMethodException e) {
try {
f = JCTree.class.getDeclaredField("tag");
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
}
}
GET_TAG_METHOD = m;
TAG_FIELD = f;
}
static int getTag(JCTree tree) {
if (GET_TAG_METHOD != null) {
try {
return (Integer) GET_TAG_METHOD.invoke(tree);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
}
try {
return TAG_FIELD.getInt(tree);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private JcTreePrinter(boolean includePositions) {
this.includePositions = includePositions;
this.includeObjectRefs = true;
}
public static JcTreePrinter printerWithPositions() {
return new JcTreePrinter(true);
}
public static JcTreePrinter printerWithoutPositions() {
return new JcTreePrinter(false);
}
@Override
public String toString() {
return output.toString();
}
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println("Usage: Supply a file name to print.");
return;
}
Context context = new Context();
Options.instance(context).put(OptionName.ENCODING, "UTF-8");
JavaCompiler compiler = new JavaCompiler(context);
compiler.genEndPos = true;
compiler.keepComments = true;
@SuppressWarnings("deprecation") JCCompilationUnit cu = compiler.parse(args[0]);
JcTreePrinter printer = new JcTreePrinter(true);
printer.visit(cu);
System.out.println(printer);
}
private void printNode(JCTree tree) {
if (tree == null) {
printNode("NULL");
} else {
String suffix = "";
int objId;
Integer backRef = visited.get(tree);
if (backRef == null) {
objId = ++objectCounter;
visited.put(tree, objId);
} else {
objId = backRef;
}
if (includePositions) {
Integer endPos_ = null;
if (endPosTable != null) endPos_ = endPosTable.get(tree);
int endPos = endPos_ == null ? tree.getEndPosition(endPosTable) : endPos_;
int startPos = tree.pos;
if (tree instanceof JCTypeApply || tree instanceof JCWildcard || tree instanceof JCTypeParameter) {
// Javac itself actually has bugs in generating the right endpos. To make sure our tests that compare end pos don't fail,
// as we do set the end pos at the right place, we overwrite it with magic value -2 which means: javac screws this up.
endPos = -2;
}
// When there are no modifiers but an internal flag is set, javac screws up,
// and sets start to the beginning of the node, and end to the last non-whitespace thing before it;
// yes - that would make for negatively sized modifier nodes.
if (tree instanceof JCModifiers && endPos-tree.pos <= 0) {
startPos = -1;
endPos = -1;
}
// The end value of an annotation is end-of-annotation-type in older javac, and end-of-parenslist in new javac.
if (tree instanceof JCAnnotation || tree instanceof JCModifiers) {
endPos = -2;
}
// Modifiers of enums never get their position set, but we do set the position.
if (modsOfEnum) {
startPos = -1;
endPos = -1;
modsOfEnum = false;
}
//In rare conditions, the end pos table is filled with a silly value, but start is -1.
if (startPos == -1 && endPos >= 0) endPos = -1;
/*Javac bug: sometimes the startpos of a binary expression is set to the wrong operator.*/ {
if (tree instanceof JCBinary && ((JCBinary)tree).rhs instanceof JCBinary) {
if (getTag(tree) != getTag(((JCBinary)tree).rhs)) {
startPos = -2;
}
}
if (tree instanceof JCBinary && ((JCBinary)tree).rhs instanceof JCInstanceOf) {
startPos = -2;
}
}
/* Javac bug: The end position of a "super.FOO" node which is itself the LHS of a select-like
concept (Select, Method Invocation, etcetera) are set to right after the dot following
it. This doesn't happen with 'this' or anything other than super. */ {
if (tree instanceof JCMethodInvocation) {
JCMethodInvocation invoke = (JCMethodInvocation) tree;
if (invoke.meth instanceof JCFieldAccess && ((JCFieldAccess) invoke.meth).selected instanceof JCIdent) {
JCIdent selected = (JCIdent) ((JCFieldAccess) invoke.meth).selected;
if (selected.name.toString().equals("super")) endPos = -2;
}
}
if (tree instanceof JCFieldAccess && ((JCFieldAccess) tree).selected instanceof JCIdent) {
JCIdent selected = (JCIdent) ((JCFieldAccess) tree).selected;
if (selected.name.toString().equals("super")) endPos = -2;
}
}
/* Javac bug: the 'JCAssign' starts at a dot (if present) in the expression instead of at the start of it, which is weird
and inconsistent. */ {
if (tree instanceof JCAssign && ((JCAssign) tree).rhs instanceof JCFieldAccess) {
startPos = -2;
}
}
suffix += String.format("(%d-%d)", startPos, endPos);
}
if (includeObjectRefs) {
suffix += String.format("(id: %d%s)", objId, backRef != null ? " BACKREF" : "");
}
printNode(String.format("%s%s", tree.getClass().getSimpleName(), suffix));
}
}
private void printNode(String nodeKind) {
printIndent();
if (rel != null)
output.append(rel).append(": ");
rel = null;
output.append("[").append(nodeKind).append("]\n");
indent++;
}
private void printIndent() {
for (int i = 0; i < indent; i++) {
output.append("\t");
}
}
private void property(String rel, Object val) {
printIndent();
if (rel != null)
output.append(rel).append(": ");
if (val instanceof JCTree)
output.append("!!JCTree-AS-PROP!!");
if (val == null) {
output.append("[NULL]\n");
} else {
String content;
if (val instanceof String) {
content = new StringLiteral().astValue(val.toString()).rawValue();
} else {
content = String.valueOf(val);
}
output.append("[").append(val.getClass().getSimpleName()).append(" ").append(content).append("]\n");
}
}
private void child(String rel, JCTree node) {
this.rel = rel;
if (node != null) {
node.accept(visitor);
} else {
printNode("NULL");
indent--;
}
}
private void children(String rel, List extends JCTree> nodes) {
this.rel = rel;
if (nodes == null) {
;
printNode("LISTNULL");
indent--;
} else if (nodes.isEmpty()) {
printNode("LISTEMPTY");
indent--;
} else {
int i = 0;
for (JCTree node : nodes) {
child(String.format("%s[%d]", rel, i++), node);
}
}
}
public void visit(JCTree tree) {
tree.accept(visitor);
}
private final JCTree.Visitor visitor = new JCTree.Visitor() {
@Override public void visitTopLevel(JCCompilationUnit tree) {
printNode(tree);
endPosTable = tree.endPositions;
child("pid", tree.pid);
children("defs", tree.defs);
indent--;
}
@Override public void visitImport(JCImport tree) {
printNode(tree);
property("staticImport", tree.staticImport);
child("qualid", tree.qualid);
indent--;
}
@Override public void visitClassDef(JCClassDecl tree) {
printNode(tree);
modsOfEnum = (tree.mods != null && (tree.mods.flags & Flags.ENUM) != 0);
child("mods", tree.mods);
property("name", tree.name);
children("typarams", tree.typarams);
child("extends", tree.extending);
children("implementing", tree.implementing);
children("defs", tree.defs);
indent--;
}
@Override public void visitMethodDef(JCMethodDecl tree) {
printNode(tree);
property("name", tree.name);
child("mods", tree.mods);
children("typarams", tree.typarams);
children("params", tree.params);
children("thrown", tree.thrown);
child("default", tree.defaultValue);
child("body", tree.body);
indent--;
}
@Override public void visitVarDef(JCVariableDecl tree) {
printNode(tree);
child("mods", tree.mods);
child("vartype", tree.vartype);
property("name", tree.name);
child("init", tree.init);
indent--;
}
@Override public void visitSkip(JCSkip tree) {
printNode(tree);
indent--;
}
@Override public void visitBlock(JCBlock tree) {
printNode(tree);
property("flags", "0x" + Long.toString(tree.flags, 0x10));
children("stats", tree.stats);
indent--;
}
@Override public void visitDoLoop(JCDoWhileLoop tree) {
printNode(tree);
child("body", tree.body);
child("cond", tree.cond);
indent--;
}
@Override public void visitWhileLoop(JCWhileLoop tree) {
printNode(tree);
child("cond", tree.cond);
child("body", tree.body);
indent--;
}
@Override public void visitForLoop(JCForLoop tree) {
printNode(tree);
children("init", tree.init);
child("cond", tree.cond);
children("step", tree.step);
child("body", tree.body);
indent--;
}
@Override public void visitForeachLoop(JCEnhancedForLoop tree) {
printNode(tree);
child("var", tree.var);
child("expr", tree.expr);
child("body", tree.body);
indent--;
}
@Override public void visitLabelled(JCLabeledStatement tree) {
printNode(tree);
property("label", tree.label);
child("body", tree.body);
indent--;
}
@Override public void visitSwitch(JCSwitch tree) {
printNode(tree);
child("selector", tree.selector);
children("cases", tree.cases);
indent--;
}
@Override public void visitCase(JCCase tree) {
printNode(tree);
child("pat", tree.pat);
children("stats", tree.stats);
indent--;
}
@Override public void visitSynchronized(JCSynchronized tree) {
printNode(tree);
child("lock", tree.lock);
child("body", tree.body);
indent--;
}
@Override public void visitTry(JCTry tree) {
printNode(tree);
child("body", tree.body);
children("catchers", tree.catchers);
child("finalizer", tree.finalizer);
indent--;
}
@Override public void visitCatch(JCCatch tree) {
printNode(tree);
child("param", tree.param);
child("body", tree.body);
indent--;
}
@Override public void visitConditional(JCConditional tree) {
printNode(tree);
child("cond", tree.cond);
child("truepart", tree.truepart);
child("falsepart", tree.falsepart);
indent--;
}
@Override public void visitIf(JCIf tree) {
printNode(tree);
child("cond", tree.cond);
child("thenpart", tree.thenpart);
child("elsepart", tree.elsepart);
indent--;
}
@Override public void visitExec(JCExpressionStatement tree) {
printNode(tree);
child("expr", tree.expr);
indent--;
}
@Override public void visitBreak(JCBreak tree) {
printNode(tree);
property("label", tree.label);
indent--;
}
@Override public void visitContinue(JCContinue tree) {
printNode(tree);
property("label", tree.label);
indent--;
}
@Override public void visitReturn(JCReturn tree) {
printNode(tree);
child("expr", tree.expr);
indent--;
}
@Override public void visitThrow(JCThrow tree) {
printNode(tree);
child("expr", tree.expr);
indent--;
}
@Override public void visitAssert(JCAssert tree) {
printNode(tree);
child("cond", tree.cond);
child("detail", tree.detail);
indent--;
}
@Override public void visitApply(JCMethodInvocation tree) {
printNode(tree);
children("typeargs", tree.typeargs);
child("meth", tree.meth);
children("args", tree.args);
indent--;
}
@Override public void visitNewClass(JCNewClass tree) {
printNode(tree);
child("encl", tree.encl);
children("typeargs", tree.typeargs);
child("clazz", tree.clazz);
children("args", tree.args);
child("def", tree.def);
indent--;
}
@Override public void visitNewArray(JCNewArray tree) {
printNode(tree);
child("elemtype", tree.elemtype);
children("dims", tree.dims);
children("elems", tree.elems);
indent--;
}
@Override public void visitParens(JCParens tree) {
printNode(tree);
child("expr", tree.expr);
indent--;
}
@Override public void visitAssign(JCAssign tree) {
printNode(tree);
child("lhs", tree.lhs);
child("rhs", tree.rhs);
indent--;
}
public String operatorName(int tag) {
switch (tag) {
case JCTree.POS:
return "+";
case JCTree.NEG:
return "-";
case JCTree.NOT:
return "!";
case JCTree.COMPL:
return "~";
case JCTree.PREINC:
return "++X";
case JCTree.PREDEC:
return "--X";
case JCTree.POSTINC:
return "X++";
case JCTree.POSTDEC:
return "X--";
case JCTree.NULLCHK:
return "<*nullchk*>";
case JCTree.OR:
return "||";
case JCTree.AND:
return "&&";
case JCTree.EQ:
return "==";
case JCTree.NE:
return "!=";
case JCTree.LT:
return "<";
case JCTree.GT:
return ">";
case JCTree.LE:
return "<=";
case JCTree.GE:
return ">=";
case JCTree.BITOR:
return "|";
case JCTree.BITXOR:
return "^";
case JCTree.BITAND:
return "&";
case JCTree.SL:
return "<<";
case JCTree.SR:
return ">>";
case JCTree.USR:
return ">>>";
case JCTree.PLUS:
return "+";
case JCTree.MINUS:
return "-";
case JCTree.MUL:
return "*";
case JCTree.DIV:
return "/";
case JCTree.MOD:
return "%";
case JCTree.PLUS_ASG:
return "+=";
case JCTree.MINUS_ASG:
return "-=";
case JCTree.MUL_ASG:
return "*=";
case JCTree.DIV_ASG:
return "/=";
case JCTree.MOD_ASG:
return "%=";
case JCTree.BITAND_ASG:
return "&=";
case JCTree.BITXOR_ASG:
return "^=";
case JCTree.BITOR_ASG:
return "|=";
case JCTree.SL_ASG:
return "<<=";
case JCTree.SR_ASG:
return ">>=";
case JCTree.USR_ASG:
return ">>>=";
case JCTree.TYPETEST:
return "instanceof";
default:
throw new Error("Unexpected operator: " + tag);
}
}
@Override public void visitAssignop(JCAssignOp tree) {
printNode(tree);
child("lhs", tree.lhs);
property("(operator)", operatorName(getTag(tree) - JCTree.ASGOffset) + "=");
child("rhs", tree.rhs);
indent--;
}
@Override public void visitUnary(JCUnary tree) {
printNode(tree);
child("arg", tree.arg);
property("(operator)", operatorName(getTag(tree)));
indent--;
}
@Override public void visitBinary(JCBinary tree) {
printNode(tree);
child("lhs", tree.lhs);
property("(operator)", operatorName(getTag(tree)));
child("rhs", tree.rhs);
indent--;
}
@Override public void visitTypeCast(JCTypeCast tree) {
printNode(tree);
child("clazz", tree.clazz);
child("expr", tree.expr);
indent--;
}
@Override public void visitTypeTest(JCInstanceOf tree) {
printNode(tree);
child("expr", tree.expr);
child("clazz", tree.clazz);
indent--;
}
@Override public void visitIndexed(JCArrayAccess tree) {
printNode(tree);
child("indexed", tree.indexed);
child("index", tree.index);
indent--;
}
@Override public void visitSelect(JCFieldAccess tree) {
printNode(tree);
child("selected", tree.selected);
property("name", tree.name);
indent--;
}
@Override public void visitIdent(JCIdent tree) {
printNode(tree);
property("name", tree.name);
indent--;
}
public String literalName(int typeTag) {
switch (typeTag) {
case TypeTags.BYTE:
return "BYTE";
case TypeTags.SHORT:
return "SHORT";
case TypeTags.INT:
return "INT";
case TypeTags.LONG:
return "LONG";
case TypeTags.FLOAT:
return "FLOAT";
case TypeTags.DOUBLE:
return "DOUBLE";
case TypeTags.CHAR:
return "CHAR";
case TypeTags.BOOLEAN:
return "BOOLEAN";
case TypeTags.VOID:
return "VOID";
case TypeTags.CLASS:
return "CLASS/STRING";
case TypeTags.BOT:
return "BOT";
default:
return "ERROR(" + typeTag + ")";
}
}
@Override public void visitLiteral(JCLiteral tree) {
printNode(tree);
property("typetag", literalName(tree.typetag));
property("value", tree.value);
indent--;
}
@Override public void visitTypeIdent(JCPrimitiveTypeTree tree) {
printNode(tree);
property("typetag", literalName(tree.typetag));
indent--;
}
@Override public void visitTypeArray(JCArrayTypeTree tree) {
printNode(tree);
child("elemtype", tree.elemtype);
indent--;
}
@Override public void visitTypeApply(JCTypeApply tree) {
printNode(tree);
child("clazz", tree.clazz);
children("arguments", tree.arguments);
indent--;
}
@Override public void visitTypeParameter(JCTypeParameter tree) {
printNode(tree);
property("name", tree.name);
children("bounds", tree.bounds);
indent--;
}
@Override public void visitWildcard(JCWildcard tree) {
printNode(tree);
Object o;
// In some javacs (older ones), JCWildcard.kind is a BoundKind, which is an enum. In newer ones its a TypeBoundKind which is a JCTree, i.e. has positions.
try {
o = tree.getClass().getField("kind").get(tree);
} catch (Exception e) {
throw new RuntimeException("There's no field at all named 'kind' in JCWildcard? This is not a javac I understand.", e);
}
if (o instanceof JCTree) {
child("kind", (JCTree)o);
} else if (o instanceof BoundKind) {
property("kind", String.valueOf(o));
}
child("inner", tree.inner);
indent--;
}
// In older javacs this method does not exist, so no @Override here
public void visitTypeBoundKind(TypeBoundKind tree) {
printNode(tree);
property("kind", String.valueOf(tree.kind));
indent--;
}
@Override public void visitErroneous(JCErroneous tree) {
printNode(tree);
children("errs", tree.errs);
indent--;
}
@Override public void visitLetExpr(LetExpr tree) {
printNode(tree);
children("defs", tree.defs);
child("expr", tree.expr);
indent--;
}
@Override public void visitModifiers(JCModifiers tree) {
printNode(tree);
children("annotations", tree.annotations);
property("flags", "0x" + Long.toString(tree.flags, 0x10));
indent--;
}
@Override public void visitAnnotation(JCAnnotation tree) {
printNode(tree);
child("annotationType", tree.annotationType);
children("args", tree.args);
indent--;
}
@Override public void visitTree(JCTree tree) {
String typeName = tree == null ? "NULL" : tree.getClass().getSimpleName();
printNode("UNKNOWN(" + typeName + ")");
indent--;
}
};
}