5

我有代码

private static class MyVisitor extends VoidVisitorAdapter<Object> {
    @Override
    public void visit(MethodCallExpr exp, Object arg) {
        System.out.println("Scope: "  + exp.getScope());
        System.out.println("Method: " + exp.getName());
        if(exp.getArgs() != null)
            for(Expression e : exp.getArgs()) {
                System.out.println("\tArgument: " + e.toString());

            }
        System.out.println();
    }
}

CompilationUnit cu = JavaParser.parse(new File("Test.java"));

for(TypeDeclaration type : cu.getTypes()) {
    for(BodyDeclaration dec : type.getMembers()) {
        if(dec instanceof MethodDeclaration) {
            MethodDeclaration mdec = (MethodDeclaration) dec;
            BlockStmt block = mdec.getBody();
            for(Statement stmt : block.getStmts()) {
                MyVisitor visitor = new MyVisitor();
                s.accept(visitor, null);
            }
        }
    }
}

我有两个问题:

  1. 如何将语句转换为表达式?我要检查的是方法调用。我试图通过这种方式检查它们是否是不兼容的类型:if(stmt instanceof MethodCallExp)但出错了。我输入了我现在使用的代码。这是执行检查的一种方法吗?
  2. System.out.println("Scope: " + exp.getScope());将显示对象/包/包+类名。但是如何获得它的类型呢?例如对于代码System.out.println("Hello world"); 应该输出

类型:java.io.PrintStream

4

2 回答 2

0
  1. 语句和表达式之间没有 1:1 的关系。例如 ExpressionStmt 只包含一个 Expression,但 WhileStmt 包含一个条件 Expression 和一个包含进一步 Statement 的主体。
  2. getScope() 调用返回的 FieldAccessExpr 中不包含类型信息。JavaParser 似乎没有提供获取类型的简单方法。使用节点层次结构及其类型,您可以使用相应的反射类来实现您的目标。对于您的示例,这意味着找到最顶层的范围(类型为 NameExpr)并获取类对象(认识到 System 是 java.lang.System 的缩写),对于下一个节点(类型为 FieldAccessExpr),您将获得字段的类,然后可以得到类型:
    Class.forName("java.lang.System").getField("out").getType();
    在上面的代码示例中,您将访问者传递给方法主体中的每个语句。如果您在循环之外创建访问者,它将能够记住在之前的语句中看到的信息。这样,您可以向访问者添加一个字段来存储变量声明:
    final HashMap varNameToType = new HashMap();
    您可以存储变量声明,如下所示。当您进行方法调用时,您可以使用范围尝试通过映射获取类型。如果映射不包含类型,则可能需要使用反射,因为变量可能是 JDK 类的一部分。我并不是建议这涵盖所有情况。例如,当您访问父类的字段时,您将不会在代码中的位置获得有关该字段的任何信息——您可能需要为此查看不同的编译单元。
@Override
public void visit(
        final VariableDeclarationExpr n,
        final Object arg) {
    final Type varType = n.getType();
    n.getVars().forEach(vd ->
        varNameToType.put(vd.getId().getName(),varType)
    );
}
于 2015-04-20T12:19:45.967 回答
0

如果你不需要坚持,JavaParser也许你可以用 Android lint 工具的方式来解决它。EcjParserTest.java。它Lombok在引擎盖下使用。

在行380中,它在测试中比较与您想要的输出相似的输出[ExpressionStatement], type: void, resolved method: println java.io.PrintStream

我没有深入了解,但它看起来是一个有希望的起点

于 2015-04-21T08:52:07.493 回答