INRIA / spoon

Spoon is a metaprogramming library to analyze and transform Java source code. :spoon: is made with :heart:, :beers: and :sparkles:. It parses source files to build a well-designed AST with powerful analysis and transformation API.
http://spoon.gforge.inria.fr/
Other
1.75k stars 351 forks source link

getExecutableDeclaration returning null on a known class #3245

Closed santos-samuel closed 4 years ago

santos-samuel commented 4 years ago

Hello, I have a doubt about Spoon.

I am using Spoon to construct a CallGraph of some classes belonging to a project folder. I am iterating over the classes/methods and following a DFS approach.

To start, I am giving a folder as input like shown:

Launcher launcher = new Launcher();
launcher.addInputResource(".../edition-ldod");

This folder has a lot of classes, which includes:

(...)/edition-ldod/src/main/java/pt/ist/socialsoftware/edition/ldod/controller/UserController.java
(...)/edition-ldod/src/main/java/pt/ist/socialsoftware/edition/ldod/validator/ChangePasswordValidator.java

By giving the whole folder as input to the launcher, I believe both of these classes will belong to the model (launcher.buildModel();).

So, I want to construct a callgraph of a method changePassword of the UserController class:

@RequestMapping(method = RequestMethod.POST, value = "/changePassword")
public String changePassword(@Valid ChangePasswordForm form, BindingResult formBinding) {
    (...)

    ChangePasswordValidator validator = new ChangePasswordValidator(this.passwordEncoder);
    validator.validate(form, formBinding);

    (...)
}

To do that, I retrieve all the CtAbstractInvocation Elements of this method. method.getElements(new TypeFilter<>(CtAbstractInvocation.class))

At some point I have a CtAbstractInvocation variable (calleeLocation) that represents the line validator.validate(form, formBinding); (which is in runtime a CtInvocationImpl).

Then, to add the method that is accessed in this line to a list I try to do: calleeLocation.getExecutable().getExecutableDeclaration() but this returns "null" and I can't understand why.

I believe the getExecutableDeclaration() should return the method that is being called and that is known because is present in the list of classes provided to the model. (For instance: launcher.getFactory().Class().getAll() shows the ChangePasswordValidator class.)

Method being called below:

package pt.ist.socialsoftware.edition.ldod.validator;

(...)

public class ChangePasswordValidator implements Validator {

    (...)

    @Override
    public void validate(Object target, Errors errors) {
        (...)
    }

    (...)
}

Can someone explain me why this is happening?

Thanks in advance!

monperrus commented 4 years ago

calleeLocation.getExecutable().getExecutableDeclaration() but this returns "null" and I can't understand why.

Seems like a bug. Would you make a PR with a failing test case? That would be super useful. Thanks!

santos-samuel commented 4 years ago

Should I make a guide on how to reproduce the error? I have my SpoonCallGraph.java class and I am analysing the code that belongs to another repository (https://github.com/socialsoftware/edition/tree/master/edition-ldod)

monperrus commented 4 years ago

A failing test case in a PR is much more productive than a guide.

santos-samuel commented 4 years ago

I already created a test case. I switched to a new branch but I believe I don't have permissions to commit and create a pull request...

monperrus commented 4 years ago

great. you have to first fork the repo, push the branch in your fork, and create the PR from there.