From 59414f9e5b41ab1efa763335c0f2d53f088f1e0a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 20 Mar 2016 12:22:33 +0100 Subject: [PATCH] Add a dump facade to print out the AST tree --- .../pmd/lang/apex/ApexHandler.java | 15 ++++ .../pmd/lang/apex/ast/DumpFacade.java | 83 +++++++++++++++++++ .../pmd/lang/apex/ast/ApexParserTest.java | 18 ++-- 3 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/DumpFacade.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java index 021cd5ccf9..7afbd7c936 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java @@ -3,12 +3,18 @@ */ package net.sourceforge.pmd.lang.apex; +import java.io.Writer; + import net.sf.saxon.sxpath.IndependentContext; import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.VisitorStarter; import net.sourceforge.pmd.lang.XPathHandler; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.ast.DumpFacade; import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory; +import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; @@ -40,4 +46,13 @@ public class ApexHandler extends AbstractLanguageVersionHandler { public Parser getParser(ParserOptions parserOptions) { return new ApexParser(parserOptions); } + + @Override + public VisitorStarter getDumpFacade(Writer writer, String prefix, boolean recurse) { + return new VisitorStarter() { + public void start(Node rootNode) { + new DumpFacade().initializeWith(writer, prefix, recurse, (ApexNode) rootNode); + } + }; + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/DumpFacade.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/DumpFacade.java new file mode 100644 index 0000000000..a4a486027c --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/DumpFacade.java @@ -0,0 +1,83 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd.lang.apex.ast; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.util.StringUtil; + +public class DumpFacade { + private PrintWriter writer; + private boolean recurse; + + public void initializeWith(Writer writer, String prefix, boolean recurse, ApexNode node) { + this.writer = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer); + this.recurse = recurse; + this.dump(node, prefix); + try { + writer.flush(); + } catch (IOException e) { + throw new RuntimeException("Problem flushing PrintWriter.", e); + } + } + + public Object visit(ApexNode node, Object data) { + dump(node, (String) data); + if (recurse) { + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + visit((ApexNode) node.jjtGetChild(i), data + " "); + } + return data; + } else { + return data; + } + } + + private void dump(ApexNode node, String prefix) { + // + // Dump format is generally composed of the following items... + // + + // 1) Dump prefix + writer.print(prefix); + + // 2) JJT Name of the Node + writer.print(node.toString()); + + // + // If there are any additional details, then: + // 1) A colon + // 2) The Node.getImage() if it is non-empty + // 3) Extras in parentheses + // + + // Standard image handling + String image = node.getImage(); + + // Special image handling (e.g. Nodes with normally null images) + image = StringUtil.escapeWhitespace(image); + + // Extras + List extras = new ArrayList<>(); + + // Output image and extras + if (image != null || !extras.isEmpty()) { + writer.print(':'); + if (image != null) { + writer.print(image); + } + for (String extra : extras) { + writer.print('('); + writer.print(extra); + writer.print(')'); + } + } + + writer.println(); + } +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java index e5893c6150..5bfd5697bc 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java @@ -9,15 +9,14 @@ import static org.junit.Assert.assertEquals; import java.io.Reader; import java.io.StringReader; +import java.io.StringWriter; import java.util.List; -import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ApexParser; - import org.junit.Test; +import net.sourceforge.pmd.lang.apex.ApexParserOptions; +import net.sourceforge.pmd.lang.ast.Node; + public class ApexParserTest { private String code1 = "public class HelloWorld { public void foo() {} private static int bar() { return 1; } }"; @@ -30,6 +29,7 @@ public class ApexParserTest { @Test public void testParse() { ASTUserClass rootNode = parse(code1); + dumpNode(rootNode); List methods = rootNode.findDescendantsOfType(ASTMethod.class); assertEquals(2, methods.size()); @@ -40,4 +40,12 @@ public class ApexParserTest { Reader reader = new StringReader(code); return (ASTUserClass) parser.parse(reader); } + + private void dumpNode(Node node) { + DumpFacade facade = new DumpFacade(); + StringWriter writer = new StringWriter(); + facade.initializeWith(writer, "", true, (ApexNode)node); + facade.visit((ApexNode)node, ""); + System.out.println(writer.toString()); + } }