如何获得最终包名?

iva*_*van 5 java parsing javaparser

我有代码

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

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

键入:java.io.PrintStream

muu*_*ued 0

  1. 语句和表达式之间不存在 1:1 的关系。例如,ExpressionStmt 仅包含一个表达式,而WhileStmt 包含一个条件表达式和一个包含进一步语句的主体。
  2. getScope() 调用返回的 FieldAccessExpr 中不包含类型信息。JavaParser 似乎没有提供获取类型的简单方法。使用节点层次结构及其类型,您可以使用相应的反射类来实现您的目标。对于您的示例,这意味着找到最顶层的范围(类型为 NameExpr)并获取类对象(认识到 System 是 java.lang.System 的缩写),对于下一个节点(类型为 FieldAccessExpr),您将获得 Field类,然后可以获得类型:
    Class.forName("java.lang.System").getField("out").getType();
    Run Code Online (Sandbox Code Playgroud) 在上面的代码示例中,您将访问者传递给方法主体中的每个语句。如果您在循环之外创建访问者,它将能够记住先前语句中看到的信息。这样,您可以向访问者添加一个字段来存储变量声明:
    final HashMap varNameToType = new HashMap();
    Run Code Online (Sandbox Code Playgroud) 您可以像下面这样存储变量声明。当您进行方法调用时,您可以使用范围来尝试通过映射获取类型。如果映射不包含类型,则可能需要使用反射,因为变量可能是 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)
    );
}
Run Code Online (Sandbox Code Playgroud)