/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.j2objc.ast;
import com.google.devtools.j2objc.gen.SourceBuilder;
import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.ErrorUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeMirror;
/**
* Dumps a specified AST to show a specified tree's graph. Unlike
* {@link DebugASTPrinter}, the output does not look like the original
* Java source. It's instead intended to aid translator debugging and
* testing.
*
* @author Tom Ball
*/
public class DebugASTDump extends TreeVisitor {
private SourceBuilder sb = new SourceBuilder(false);
/**
* Dumps a compilation unit to a file. The output file's path is the
* same as where translated files get written, but with an "ast" suffix.
*/
public static void dumpUnit(CompilationUnit unit) {
String relativeOutputPath = unit.getMainTypeName().replace('.', '/') + ".ast";
File outputFile = new File(
unit.getEnv().options().fileUtil().getOutputDirectory(), relativeOutputPath);
outputFile.getParentFile().mkdirs();
try (FileOutputStream fout = new FileOutputStream(outputFile);
OutputStreamWriter out = new OutputStreamWriter(fout, "UTF-8")) {
out.write(dump(unit));
} catch (IOException e) {
ErrorUtil.fatalError(e, outputFile.getPath());
}
}
/**
* Dumps an AST node as a string.
*/
public static String dump(TreeNode node) {
DebugASTDump dumper = new DebugASTDump();
node.accept(dumper);
dumper.sb.newline();
return dumper.toString();
}
@Override
public boolean preVisit(TreeNode node) {
if (sb.length() > 0) {
sb.newline();
}
sb.printIndent();
sb.print(node.getClass().getSimpleName());
sb.print(" (line:" + node.getLineNumber() + " pos:" + node.getStartPosition()
+ " len:" + node.getLength() + ")");
sb.indent();
return true;
}
@Override
public void postVisit(TreeNode node) {
sb.unindent();
}
@Override
public boolean visit(AnnotationTypeDeclaration node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(AnnotationTypeMemberDeclaration node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(ArrayType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(EnumConstantDeclaration node) {
printName(node.getVariableElement());
return true;
}
@Override
public boolean visit(EnumDeclaration node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(ExpressionMethodReference node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(FieldAccess node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(IntersectionType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(Javadoc node) {
return true;
}
@Override
public boolean visit(MemberValuePair node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(MethodDeclaration node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(MethodInvocation node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(NameQualifiedType node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(PackageDeclaration node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(ParameterizedType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(PrimitiveType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(QualifiedName node) {
printName(node);
return true;
}
@Override
public boolean visit(QualifiedType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(SimpleName node) {
printName(node);
return true;
}
@Override
public boolean visit(SimpleType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(SingleVariableDeclaration node) {
printName(node.getVariableElement());
return true;
}
@Override
public boolean visit(SuperFieldAccess node) {
printName(node.getVariableElement());
return true;
}
@Override
public boolean visit(SuperMethodInvocation node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(SuperMethodReference node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(TagElement node) {
String tagName = node.getTagKind().toString();
sb.print(' ');
sb.print(tagName != null ? tagName : "null");
return true;
}
@Override
public boolean visit(TextElement node) {
sb.print(' ');
sb.print(node.getText());
return true;
}
@Override
public boolean visit(TypeDeclaration node) {
printName(node.getName());
return true;
}
@Override
public boolean visit(TypeMethodReference node) {
printName(node.getExecutableElement());
return true;
}
@Override
public boolean visit(UnionType node) {
printType(node.getTypeMirror());
return true;
}
@Override
public boolean visit(VariableDeclarationFragment node) {
printName(node.getVariableElement());
return true;
}
private void printName(Element element) {
sb.print(": ");
sb.print(ElementUtil.getName(element));
}
private void printName(Name name) {
if (name != null) {
sb.print(": ");
sb.print(name.toString());
}
}
private void printType(TypeMirror type) {
sb.print(": ");
sb.print(type.toString());
}
@Override
public String toString() {
return sb.toString();
}
}