简体   繁体   English

如何获得最终包名?

[英]How to get final package name?

I have the code 我有代码

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();
    }
}

And

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);
            }
        }
    }
}

I have two problems: 我有两个问题:

  1. How to convert Statement to Expression? 如何将Statement转换为Expression? I want to check is that Method Call. 我想查一下方法调用。 I tried to check that they are incompatible types by this way : if(stmt instanceof MethodCallExp) but got error. 我试图通过这种方式检查它们是不兼容的类型: if(stmt instanceof MethodCallExp)但是出错了。 I entered the code I use now. 我输入了我现在使用的代码。 Is that the one way to perform check? 这是执行检查的一种方法吗?
  2. System.out.println("Scope: " + exp.getScope()); will be displayed the object/package/package+class name. 将显示对象/包/包+类名。 But how to get its type? 但是如何获得它的类型? For example for the code System.out.println("Hello world"); 例如代码System.out.println("Hello world"); Should be outputted 应该输出

Type: java.io.PrintStream 键入:java.io.PrintStream

  1. There is no 1:1 relation between Statements and Expressions. 语句和表达式之间没有1:1的关系。 Eg ExpressionStmt contains just one Expression, but WhileStmt contains a condition Expression and a body comprising a further Statement. 例如,ExpressionStmt只包含一个Expression,但WhileStmt包含一个条件Expression和一个包含另一个Statement的主体。
  2. There is no type information contained in the FieldAccessExpr returned by the getScope() call. getScope()调用返回的FieldAccessExpr中没有包含类型信息。 JavaParser does not seem to provide an easy way of getting the type. JavaParser似乎没有提供获取类型的简单方法。 Using the Node hierarchy and their types you can use the corresponding Reflection classes to get to your goal. 使用Node层次结构及其类型,您可以使用相应的Reflection类来实现目标。 For your example that would mean finding the topmost scope (type would be NameExpr) and getting the Class Object (recognizing that System is short for java.lang.System), for the next node (type would be FieldAccessExpr) you would get the Field of the class and can then get the type: 对于你的例子,这意味着找到最顶层的范围(类型将是NameExpr)并获得类对象(认识到System是java.lang.System的简称),对于下一个节点(类型将是FieldAccessExpr),你将获得Field该类,然后可以得到类型:
     Class.forName("java.lang.System").getField("out").getType(); 
    In your code example above you pass your visitor to every statement within the method body. 在上面的代码示例中,您将访问者传递给方法体内的每个语句。 If you create the visitor outside of the loop, it will be able to remember information seen in previous statements. 如果您在循环之外创建访问者,它将能够记住在先前语句中看到的信息。 This way, you might add a field to your visitor to store the variable declarations: 这样,您可以向访问者添加一个字段来存储变量声明:
     final HashMap varNameToType = new HashMap(); 
    You can store the variable declarations like below. 您可以存储如下所示的变量声明。 When you get to a method call, you can use the scope to try and get the type via the map. 当您进行方法调用时,您可以使用范围尝试通过地图获取类型。 If the map doesn't contain the Type, you may need to use Reflection, since the variable may be part of the JDK classes. 如果映射不包含Type,则可能需要使用Reflection,因为该变量可能是JDK类的一部分。 I'm not suggesting that this covers all cases. 我并不是说这涵盖了所有情况。 Eg when you access a field of your parent class, you wouldn't have any information about that field at your position in the code - you may need to look at different compilation units for that. 例如,当您访问父类的字段时,您将无法在代码中的位置获得有关该字段的任何信息 - 您可能需要查看不同的编译单元。
@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)
    );
}

If you don't need to stick on JavaParser maybe you could solve it in the way the Android lint tools do it. 如果您不需要坚持JavaParser也许您可以通过Android lint工具的方式来解决它。 EcjParserTest.java . EcjParserTest.java It uses Lombok under the hood. 它使用Lombok引擎盖。

At line 380 it compares in the test an output similar to the one you want to have [ExpressionStatement], type: void, resolved method: println java.io.PrintStream . 在第380行,它在测试中比较了一个类似于你想要的输出[ExpressionStatement], type: void, resolved method: println java.io.PrintStream

I had no deeper look, but it looks as a promising starting point 我没有更深入的了解,但它看起来是一个很有希望的起点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM