Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bindings not resolving with AST processing in eclipse

I'm using the eclipse JDT AST parser to process some Java code and am trying to extract the type bindings for fields and method declarations. The logic for doing that is inside my Visitor class (see below). Unfortunately, I'm not having any luck and none of the bindings are resolving (they are consistently null). The interesting thing is that the bindings do work on the same code with the eclipse ASTView plugin. What am I doing wrong?

Here are some relevant code snippets which will hopefully help someone figure out what is going on!

ASTParser parser = ASTParser.newParser(AST.JLS3); 
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(source);
parser.setResolveBindings(true);
CompilationUnit unit = (CompilationUnit) parser.createAST(null);

GenericVisitor visitor = new GenericVisitor(outDir + "//" + file.getName() + ".xml");
visitor.process(unit);


public class GenericVisitor extends ASTVisitor 
{
    public void endVisit(FieldDeclaration node) 
    {
        String bindingInfo = "";    
        ITypeBinding binding = node.getType().resolveBinding();

        if(binding == null)
        {                    
         System.out.println("field declaration binding = null");
        }
        else
        {
         bindingInfo = binding.getQualifiedName();
        }

        endVisitNode(node, bindingInfo); 
    }

    public void endVisit(MethodInvocation node) 
    {
         String bindingInfo = "";   
         IMethodBinding binding = node.resolveMethodBinding();

     if(binding == null)
     {                    
        System.out.println("method binding = null");
     }
     else
     {
         bindingInfo = binding.toString();
     }

    endVisitNode(node, bindingInfo); 
    }
} 
like image 680
Shirley Cohen Avatar asked Jan 07 '10 03:01

Shirley Cohen


People also ask

What is the purpose of an AST instance?

An AST instance serves as the common owner of any number of AST nodes, and as the factory for creating new AST nodes owned by that instance. Abstract syntax trees may be hand constructed by clients, using the newTYPE factory methods to create new nodes, and the various setCHILD methods (see ASTNode and its subclasses) to connect them together.

What is the difference between parent and child AST nodes?

The children of an AST node always have the same owner as their parent node. If a node from one AST is to be added to a different AST, the subtree must be cloned first to ensures that the added nodes have the correct owning AST. There can be any number of AST nodes owned by a single AST instance that are unparented.

What is the ownership of an AST node?

Each AST node belongs to a unique AST instance, called the owning AST. The children of an AST node always have the same owner as their parent node. If a node from one AST is to be added to a different AST, the subtree must be cloned first to ensures that the added nodes have the correct owning AST.


6 Answers

When you use: parser.setSource(source); What is the type of param "source"?

Binding information is obtained from the Java model. This means that the compilation unit must be located relative to the Java model. This happens automatically when the source code comes from either setSource(ICompilationUnit) or setSource(IClassFile). When source is supplied by setSource(char[]), the location must be extablished explicitly by calling setProject(IJavaProject) and setUnitName(String).

This is from http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/dom/ASTParser.html I think maybe you just use setSource(char[]) without calling setProject(IJavaProject) and setUnitName(String)

like image 51
Ida Avatar answered Sep 28 '22 04:09

Ida


The problem is that your parser has not been provided with the necessary information to construct its Java Model which is required for resolving bindings.

If the parser's source is attained from setSource(ICompilationUnit) or setSource(IClassFile) this information is provided to the parser automatically.

However, if you use setSource(char[]) instead, you must provide this context for the parser. This can be done by either calling parser.setProject(IJavaProject) or setEnvironment(String[], String[], String[], boolean) and setUnitName(String)

Source: http://help.eclipse.org/kepler/topic/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setResolveBindings(boolean)

like image 31
Rung Ip Avatar answered Sep 28 '22 03:09

Rung Ip


The probable reason is that you should not be calling the method in Visitor instance directly. You should do something like:

unit.accept(visitor);

The parent class of CompilationUnit, ASTNode, has an accept method which takes a visitor that is of type ASTVisitor.

The Visitor you have written, GenericVisitor, does subclasses the abstarct class ASTVisitor and overrides implementation for the node types you are intersted in. So I think changing your code to do the invocation in above form would fix your problem.

like image 39
sateesh Avatar answered Sep 28 '22 05:09

sateesh


ASTParser is just the parser: It builds an AST which is the first step in compilation. The actual compiler is doing more than that: it runs various visitor which enhance the tree with additional information. One of them is the binding resolution visitor.

In particular, take a look at the body of the public void process(CompilationUnitDeclaration unit, int i) method in the org.eclipse.jdt.internal.compiler.Compiler class.

like image 22
Itay Maman Avatar answered Sep 28 '22 03:09

Itay Maman


Sometimes, if you got errors in the referenced source files, then the bindings to these types are not resolved. For instance, make sure that you use the correct encoding and Java version of the source.

    ASTParser parser = ASTParser.newParser(AST.JLS3);
    parser.setKind(ASTParser.K_COMPILATION_UNIT);
    parser.setResolveBindings(true);
    parser.setBindingsRecovery(true);
    Hashtable<String, String> options = JavaCore.getDefaultOptions();
    options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
    parser.setCompilerOptions(options);
    parser.setEnvironment(classpath, sources, new String[] { "UTF-8", "UTF-8" }, true);
    parser.setSource(fileContents.toCharArray());
    CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
    IProblem[] problems = compilationUnit.getProblems();
    if (problems != null && problems.length > 0) {
        logger.warn("Got {} problems compiling the source file: ", problems.length);
        for (IProblem problem : problems) {
            logger.warn("{}", problem);
        }
    }
    return compilationUnit;
like image 26
roesslerj Avatar answered Sep 28 '22 03:09

roesslerj


Okay, this is my first answer on Stack Overflow. Nervous...

I got the same problem with you, and since you have done this:

parser.setResolveBindings(true);

Let's see whether it worked by checking this:

if (unit.getAST().hasResolvedBindings()) {
    System.out.println("Binding activated.");
}
else {
    Ststem.out.println("Binding is not activated.");
}

And I think the result is "Binding is not activated.". And that's why you got the null pointer all the time.

Then, I add this statement to my code:

parser.setEnvironment(null, null, null, true);

Magically, the problem is fixed!!! And I suppose you can try this too.

like image 44
Cicero Avatar answered Sep 28 '22 04:09

Cicero