如何获得最终的包名?

How to get final package name?

我有密码

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()); 将显示 object/package/package+class 名称。但是如何得到它的类型呢? 例如代码 System.out.println("Hello world"); 应该输出

Type: java.io.PrintStream

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

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

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

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