Java 使用EclipseJDT查找特定节点中可见的所有标识符

Java 使用EclipseJDT查找特定节点中可见的所有标识符,java,eclipse,eclipse-plugin,abstract-syntax-tree,Java,Eclipse,Eclipse Plugin,Abstract Syntax Tree,我正在开发EclipseJDT的一个插件,它解析Java文件并提供对它们的自动更正。我使用Eclipse的API来分析AST 我试图编写一个方法来计算一个方法的有效性-一个在该方法范围内可见的所有标识符的列表。另一种方式是可以从Eclipse中的特定点自动完成的标识符列表 例如: import ... public class MyClass { private static final int a = 3; private boolean b; float some

我正在开发EclipseJDT的一个插件,它解析Java文件并提供对它们的自动更正。我使用Eclipse的API来分析AST

我试图编写一个方法来计算一个方法的有效性-一个在该方法范围内可见的所有标识符的列表。另一种方式是可以从Eclipse中的特定点自动完成的标识符列表

例如:

import ...

public class MyClass {
    private static final int a = 3;
    private boolean b;

    float someMethod(String s) {
        int c = 3;
        (X);    
    }
}
(X)
中的环境由标识符
a
b
c
s
组成


如何在Eclipse中计算方法的环境?

必须从要解析的类中获取
ICompilationUnit
。 然后,您可以为所需的节点类型创建
访问者
,如
MethodDeclaration

public class MainMethodVisitor extends ASTVisitor {

    List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();

    @Override
    public boolean visit(MethodDeclaration node) {
     ... //do stuff with the node
有了方法节点,您可以使用
node.parameters()
访问其参数,以获得
s
。您必须找出类的成员变量是什么类型的节点(
a
b
)。 我认为,最后要做的事情是访问method节点内部的
VariableDeclaration
,以获得
c


这就是我要帮助你的全部。希望能有所帮助。

这里有一些工作代码解决了给定的简单示例,但需要扩展以获得更复杂的代码:

  • 范围,e。g<代码>整数a=1;{int b=2;}(X)(环境:
    a
  • 继承权
  • 带或不带通配符的静态导入,例如。g<代码>导入静态java.lang.Integer.MAX_值或
    导入静态java.lang.Integer.*
基本原则是通过
node.resolveBinding()
遍历AST并访问交叉连接

公共类环境{
公共静态void main(字符串[]args){
String code=“公共类MyClass{\n”+
“专用静态最终整数a=3;\n”+
“专用布尔b;\n”+
“\n”+
“float someMethod(字符串s){\n”+
“int c=3;\n”+
“/(X);\n”+
“}\n”+
"}";
for(IBinding binding:of(code,code.indexOf(“(X)”)){
System.out.println(binding.getName());
}
}
公共静态列表(字符串代码,整数偏移){
最终列表环境=新的ArrayList();
createAst(代码).accept(新ASTVisitor(真){
公共布尔访问(VariableDeclarationFragment节点){
if(offset
或者,字段(包括常量)可以通过
node.getFields()
visit(TypeDeclaration节点)
处收集,或者通过AST前面的
node.parameters()
visit(MethodDeclaration节点)
处收集方法的参数

ICompilationUnit unit;
//...
CompilationUnit parse = parse(unit);
MainMethodVisitor visitor = new MainMethodVisitor();
parse.accept(visitor);
public class Environment {

    public static void main(String[] args) {
        String code = "public class MyClass {\n" +
                "    private static final int a = 3;\n" +
                "    private boolean b;\n" +
                "\n" +
                "    float someMethod(String s) {\n" +
                "        int c = 3;\n" +
                "        // (X);\n" +
                "    }\n" +
                "}";
        for (IBinding binding : of(code, code.indexOf("(X)"))) {
            System.out.println(binding.getName());
        }
    }

    public static List<IBinding> of(String code, int offset) {
        final List<IBinding> environment = new ArrayList<>();
        createAst(code).accept(new ASTVisitor(true) {

            public boolean visit(VariableDeclarationFragment node) {
                if (offset < node.getStartPosition()) return false;
                environment.add(node.resolveBinding());
                return true;
            }

            public boolean visit(SingleVariableDeclaration node) {
                if (offset < node.getStartPosition()) return false;
                environment.add(node.resolveBinding());
                return true;
            }

        });
        return environment;
    }

    private static CompilationUnit createAst(String code) {

        // parser
        ASTParser parser = ASTParser.newParser(AST.JLS10);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setResolveBindings(true);
        parser.setBindingsRecovery(true);
        parser.setStatementsRecovery(true);

        // options
        final Hashtable<String, String> options = JavaCore.getOptions();
        options.put("org.eclipse.jdt.core.compiler.source", "1.8");
        parser.setCompilerOptions(options);

        // sources and classpath
        String[] sources   = new String[] { /* source folders */ };
        String[] classpath = new String[] { /* JARs */};
        String[] encodings = new String[sources.length];
        Arrays.fill(encodings, StandardCharsets.UTF_8.name());
        parser.setEnvironment(classpath, sources, encodings, true);
        parser.setUnitName("code");
        parser.setSource(code.toCharArray());

        // abstract syntax tree
        return (CompilationUnit) parser.createAST(null);
    }

}