Resolve method calls in Java code using the JavaSymbolSolver


Resolve method calls in Java Code using JavaSymbolSolver

Why I created the java-symbol-solver?

A few years ago I started using JavaParser and then I started contributing. After a while I realized that many operations we want to do on Java code cannot be done just by using the Abstract Syntax Tree produced by a parser, we need also to resolve types, symbols and method calls. For this reason I have created the JavaSymbolSolver. It is now been used to produce static analysis tools by Coati.

One thing that is missing is documentation: people open issues on JavaParser asking how to answer a certain question and the answer is often “for this you need to use JavaSymbolSolver”. Starting from these issues I will show a few examples.

Inspired by this issue I will show how to produce a list of all calls to a specific method.

How can we resolve method calls in Java using the java-symbol-solver?

It can be done in two steps:

  1. You use JavaParser on the source code to build your ASTs
  2. You call JavaSymbolSolver on the nodes of the ASTs representing method calls and get the answer

We are going to write a short example. At the end we will get an application that given a source file will produce this:

We are going to use Kotlin and Gradle. Our build file looks like this:

Building an AST is quite easy, you simply call this method:

What the hell is a Type Solver? It is the object which knows where to look for classes. When processing source code you will typically have references to code that is not yet compiled, but it is just present in other source files. You could also use classes contained in JARs or classes from the Java standard libraries. You have just to tell to your TypeSolver where to look for classes and it will figure it out.

In our example we will parse the source code from the JavaParser project (how meta?!). This project has source code in two different directories, for proper source code and code generated by JavaCC (you can ignore what JavaCC is, it is not relevant to you). We of course use also classes from the java standard libraries. This is how our TypeSolver looks like:

This is where we invoke JavaParserFacade, one of the classes provided by JavaSymbolSolver. We just take a method call at the time and we pass it to the method solve of the JavaParserFacade. We get a MethodUsage (which is basically a method declaration + the value of the parameter types for that specific invocation). From it we get the MethodDeclaration and we print the qualified signature, i.e., the qualified name of the class followed by the signature of the method. This is how we get the final output:

There is so plumbing to do but basically JavaSymbolSolver does all the heavy work behind the scene. Once you have a node of the AST you can throw it at the class JavaParserFacade and it will give you back all the information you may need: it will find corresponding types, fields, methods, etc.

The problem is… we need more documentation and feedback from users. I hope some of you will start using JavaSymbolSolver and tell us how we can improve it.

Also, last week the JavaSymbolSolver was moved under the JavaParser organization. This means that in the future we will work more closely with the JavaParser project.

The code is available on GitHub: java-symbol-solver-examples