在解析树中查找特定节点,具体取决于具有

时间:2018-01-02 15:12:27

标签: java antlr antlr4

要自动执行C#代码的安全性审核,我想从具有[HttpPost]属性但没有[ValidateAntiForgeryToken]属性的控制器中检索所有方法。我正在使用ANTLR来获取C#代码的ParseTree。当我有这个时,获得具有HttpPost子节点而不是ValidateAntiForgeryToken子节点的节点的最佳方法是什么?

我尝试过XPath,但似乎ANTLR只支持XPath的一个子集。我正在考虑将解析树转换为XML并在其上使用真正的XPath。有更简单的方法吗?

我使用以下代码来解析C#文件:

import java.io.*;
import java.util.*;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.tree.xpath.*;

public class MyParser {
    public static void main(String[] args) throws IOException {
        CharStream input = CharStreams.fromFileName(args[0]);
        Lexer lexer = new CSharpLexer(input);
        TokenStream stream = new CommonTokenStream(lexer);
        CSharpParser parser = new CSharpParser(stream);
        ParseTree tree = parser.compilation_unit();

        String xpath = "//class_member_declaration";
        Collection<ParseTree> matches = XPath.findAll(tree, xpath, parser);
        System.out.println(matches);
    }
}

树看起来像这样:

ANTLR parse tree

2 个答案:

答案 0 :(得分:1)

除了XPath的一个子集外,Antlr4不支持ParseTree上的花式匹配。但是,这也可能是解决这个问题的错误方法。

对于大多数用例,您应该遍历解析树并收集所需的信息。这可以使用听众或访客来完成。例如,以下代码收集方法和属性,并打印具有某些属性的方法:

import java.util.*;

public class MyListener extends CSharpParserBaseListener {
    String currentClass = null;
    String currentMethod = null;
    List<String> attributes;
    boolean inClassMember = false;

    @Override public void enterClass_definition(CSharpParser.Class_definitionContext ctx) { 
        this.currentClass = ctx.identifier().getText();
    }

    // Class member declaration. This thing holds both the attributes and the method declaration.
    @Override public void enterClass_member_declaration(CSharpParser.Class_member_declarationContext ctx) { 
        this.attributes = new ArrayList<String>();
        this.inClassMember = true;
    }

    @Override public void enterAttribute(CSharpParser.AttributeContext ctx) { 
        if (this.inClassMember) {
            String attrName = ctx.namespace_or_type_name().identifier().get(0).getText();
            this.attributes.add(attrName);
        }
    }

    @Override public void enterMethod_declaration(CSharpParser.Method_declarationContext ctx) { 
        this.currentMethod = ctx.method_member_name().identifier().get(0).getText();
    }

    // In the exit we have collected our method name and attributes.
    @Override public void exitClass_member_declaration(CSharpParser.Class_member_declarationContext ctx) {
        if (this.attributes.contains("HttpPost") && !this.attributes.contains("ValidateAntiForgeryToken")) {
            System.out.println(this.currentClass + "." + this.currentMethod);
        }

        this.attributes = null;
        this.currentMethod = null;
        this.inClassMember = false;
    }   
}

为了使这种功能更加通用,更好的方法是将解析树转换为另一棵树(即抽象语法树),并在树中搜索您想要的信息。

答案 1 :(得分:0)

  

我正在考虑将解析树转换为XML并在其上使用真正的XPath。有更简单的方法吗?

无需将树转换为实际的XML即可使用XPath查询。 Apache Commons libary JXPath支持Java对象的内存树中的XPath查询。