framework.src.org.checkerframework.common.util.debug.TreeDebug Maven / Gradle / Ivy
Show all versions of checker Show documentation
package org.checkerframework.common.util.debug;
import com.sun.source.tree.*;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
/**
* A utility class for displaying the structure of the AST of a program.
*
*
*
* The class is actually an annotation processor; in order to use it, invoke the
* compiler on the source file(s) for which you wish to view the structure of
* the program. You may also wish to use the {@code -proc:only} javac option to
* stop compilation after annotation processing. (But, in general
* {@code -proc:only} causes type annotation processors not to be run.)
*
*
*
* The utility will display the {@link Kind} of each
* node it encounters while scanning the AST, indented according to its depth in
* the tree. Additionally, the names of identifiers and member selection trees
* are displayed (since these names are not tree nodes and therefore not
* directly visited during AST traversal).
*
* @see org.checkerframework.common.util.debug.TreePrinter
*/
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TreeDebug extends AbstractProcessor {
protected Visitor createSourceVisitor(CompilationUnitTree root) {
return new Visitor();
}
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static class Visitor extends TreePathScanner {
private final StringBuffer buf;
public Visitor() {
buf = new StringBuffer();
}
@Override
public Void scan(Tree node, Void p) {
// Indent according to subtrees.
if (getCurrentPath() != null) {
for (TreePath tp = getCurrentPath(); tp != null; tp = tp.getParentPath()) {
buf.append(" ");
}
}
// Add node kind to the buffer.
if (node == null) {
buf.append("null");
} else {
buf.append(node.getKind());
}
buf.append(LINE_SEPARATOR);
// Visit subtrees.
super.scan(node, p);
// Display and clear the buffer.
System.out.print(buf.toString());
buf.setLength(0);
return null;
}
/**
* Splices additional information for a node into the buffer.
*
* @param text additional information for the node
*/
private final void insert(Object text) {
buf.insert(buf.length() - 1, " ");
buf.insert(buf.length() - 1, text);
}
@Override
public Void visitIdentifier(IdentifierTree node, Void p) {
insert(node);
return super.visitIdentifier(node, p);
}
@Override
public Void visitMemberSelect(MemberSelectTree node, Void p) {
insert(node.getExpression() + "." + node.getIdentifier());
return super.visitMemberSelect(node, p);
}
@Override
public Void visitNewArray(NewArrayTree node, Void p) {
insert(((JCNewArray)node).annotations);
insert("|");
insert(((JCNewArray)node).dimAnnotations);
return super.visitNewArray(node, p);
}
@Override
public Void visitLiteral(LiteralTree node, Void p) {
insert(node.getValue());
return super.visitLiteral(node, p);
}
}
@Override
public boolean process(Set annotations,
RoundEnvironment roundEnv) {
for (TypeElement element : ElementFilter.typesIn(roundEnv.getRootElements())) {
TreePath path = Trees.instance(processingEnv).getPath(element);
new Visitor().scan(path, null);
}
return false;
}
}