Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Eclipse JDT to find all identifiers visible within a specific node

I'm working on a plug-in to Eclipse JDT that parses Java files and offers automatic corrections to them. I'm doing so using Eclipse's API for analyzing the AST.

I'm trying to write a method that calculates the environment of a method - a list of all the identifiers that are visible within the scope of the method. Another way to look at this is the list of identifiers that can be auto-completed from a specific point in Eclipse.

For example:

import ...

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

    float someMethod(String s) {
        int c = 3;
        (X);    
    }
}

The environment in (X) is composed of the identifiers a, b, c and s.

How can I calculate the environment of a method in Eclipse?

like image 426
mittelmania Avatar asked Apr 20 '26 03:04

mittelmania


1 Answers

Here is some working code that solves the given simple example, but needs to be extended for more complex code:

  • Scopes, e. g. int a = 1; { int b = 2; } (X) (environment: a only)
  • Inheritance
  • Static imports with or without wildcards, e. g. import static java.lang.Integer.MAX_VALUE; or import static java.lang.Integer.*;
  • ...

The basic principle is to travel the AST and access cross connections via node.resolveBinding().

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

}

Alternatively, the fields (including constants) can be collected at visit(TypeDeclaration node) via node.getFields() or the parameters of a method at visit(MethodDeclaration node) via node.parameters() earlier in the AST.

like image 59
howlger Avatar answered Apr 22 '26 15:04

howlger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!