Skip to content

About the Symbol Solver

Jamie Davis edited this page Jan 9, 2019 · 3 revisions

History

The symbol solver was born as a separate project, to be used with JavaParser without changing the JavaParser API. The main use case was considering specific expressions and method calls and "resolving" them. For example, given a reference understanding to what is what referring to and its type.

Resolution strategy

Because of this use case the symbol solver does not proceed from top to bottom as a compiler would do, instead it looks for the context around the reference we are trying to solve and if it cannot find an answer it moves up, to a broader scope. For example, given a reference to a name "foo" it will first look among the local variables, then among the parameters of the methods containing the reference, then among the fields of the class holding the method and so on.

Generics

Initially the symbol solver could only handle Java 5. A huge difference was made by the introduction of generics and later by the introduction of lambdas. These two features make the whole symbol resolution process much more complex. Initially a few mechanisms were added that worked in most of cases but the approach to handle them is not extremely robust and it does not work in 100% of cases.

Consider this case:

MyClass<A, B> foo = ...
foo.myMethodCall(a -> a.otherMethod());

Suppose we need to solve the call "myMethodCall". What if we have several methods named "myMethodCall" in class MyClass? We would need to consider the type of the parameter. What is the type of the lambda a -> a.otherMethod() ? It depends on:

  1. The type of a
  2. The return type of otherMethod
  3. The method being called (myMethodCall)

So there is this sort of circular dependency: in order to figure out which myMethodCall we are calling we need to figure out the type of the lambda but in order to figure out the lambda we need to know which method we are calling. So we use a two-step process that first find all candidate methods and then try to see if the lambda is compatible with those candidate methods.

The correct process

Our current implementation evolved over time to cover most cases but it is not been written following the JLS. However we have an in-progress implementation of the resolution of method calls involving generics as specified by the JLS.

package containing the implementation: com.github.javaparser.symbolsolver.resolution.typeinference relevant chapter of the JLS: JLS 18

Originally we followed the JLS for Java 8, but the process did not change much until now (we are considering Java 10 at this time).

Why are we not using it right now? Because the whole API try to first resolve the type of parameters and then try to find method declarations in a particular context that can be called with that particular list of parameter types. The new API instead would need the original method call, so there would be a significant refactoring to do in order to use it.

Clone this wiki locally