-
Notifications
You must be signed in to change notification settings - Fork 260
Fix broken call graph for nested lambdas #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix broken call graph for nested lambdas #22
Conversation
cc2933c to
951db05
Compare
951db05 to
3249600
Compare
Generalize from ConstantMethodref to ConstantCP to cover also ConstantInterfaceMethodref and possibly others.
|
I just added 2 new commits:
|
|
Again, fantastic work! |
|
I did not have the time to test it thoroughly, but your test code gives me lots of confidence. |
|
I was perhaps too quick to merge this. It looks like it cannot run on Java's |
|
This is the problem when there is no automated tests. These issues will need to be considered one after the other. Try to add tests to reproduce them if you happen to work on them, so there is no future regression on them. I can reproduce it with my own rt.jar (OpenJDK 8 on Ubuntu 16.04). I already had this error when it was trying to play with an interface (there is no code there, so the Since a native method should be related to no Java code (source) it makes sense to ignore it too. Just by replacing: if (method.isAbstract()) {by this it works for me: if (method.isAbstract() || method.isNative()) {Can I let you make the test which can reproduce it? |
|
Did not take me long to do, so here is the test you need: #Author: matthieu.vergne@gmail.com
Feature: Native
I want to identify all native methods within the analyzed code.
Scenario: Retrieve native method call
Given I have the class "NativeTest" with code:
"""
public class NativeTest {
public void methodA() {
methodB();
}
public native void methodB();
}
"""
When I run the analyze
Then the result should contain:
"""
M:NativeTest:methodA() (M)NativeTest:methodB()
"""Just add it, run it to check it fails with the same exception, do the change I suggest above, and check it works. |
|
You might as well add a test for abstract method & another for interface method. It would test the |
|
Thanks, works! |
This pull request builds on #21.
Context
When we create a lambda in a method
myMethodof a classMyClass, it is identified like this:When this lambda calls another method
anotherMethodof a classAnotherClass, the static analysis retrieves the call relationship:This way, we can see that the method
MyClass:myMethod()callsAnotherClass:anotherMethod()through its lambda.Problem
When having nested lambdas, the parent method is lost. For instance, if in the lambda above we don't call directly
AnotherClass:anotherMethod(), but we create another lambda which calls it, then the deepest call is represented as:Thus, we cannot know anymore that
MyClass:myMethod()callsAnotherClass:anotherMethod().Solution
This pull request provides a Cucumber test which reproduces this behaviour (one commit) and a fix to make it pass (another commit).
Basically, this information is lost because the compiler, for each lambda, introduces an intermediary method (bootstrap) which is resolved at runtime through dynamic linking. Consequently, I have added in the code an analysis of the bootstrap methods to retrieve statically the lambdas they represent. Then, I use this information to complete the method names by replacing their
nullpart with the parent caller. Taking the example above, it replaces this:by this:
It works recursively (tested until 3 levels of nesting).