-
Notifications
You must be signed in to change notification settings - Fork 401
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
search for references from IClassFile without source #1632
Conversation
319a904
to
90650bb
Compare
@snjeza Would you mind sharing the specific root cause to help us understand this fix? |
There are several issues:
The PR improves both JDTUtils.findElementAtSelection() and ReferencesHandler.findReferences |
Not the first time we've had issues with finding references (eg. https://github.com/eclipse/eclipse.jdt.ls/pull/1561/files#r501326693) |
Some initial thoughts. The code in ReferencesHandler seems to resolve the issue with finding references, so I'll take a closer look there. Calling AST parsing on the classfile contents of every match could be intensive but I don't see a way around it. Would this still work with setResolveBindings/setBindingsRecovery set to false ? The additions to JDTUtils#findElementsAtSelection(..) seem to produce better resolutions (eg. hovers) for various tokens, which aren't that informative (in the example i'm using), but better than nothing. Instead of the search engine just looking for type declarations in classfiles, it can now find other types of elements as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looks good to me. Just a small refactoring of the visit(..) boolean check, and maybe avoiding binding resolution if possible.
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ReferencesHandler.java
Outdated
Show resolved
Hide resolved
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ReferencesHandler.java
Outdated
Show resolved
Hide resolved
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java
Outdated
Show resolved
Hide resolved
3558bc6
to
9ce4d13
Compare
test this please |
@rgrunber I have updated the PR. |
Great! @testforstephen , let me know if there's anything else you'd like to address here. I'll likely be merging this before the week is up. |
Performance is my concern. Based on the results of profiling the code action handler I did before, Let me take a look at the performance side. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code in ReferencesHandler seems to resolve the issue with finding references, so I'll take a closer look there. Calling AST parsing on the classfile contents of every match could be intensive but I don't see a way around it. Would this still work with setResolveBindings/setBindingsRecovery set to false ?
Yes, AST parser is expensive. An idea is to add a preference to control whether to include the decompiled sources when finding references.
The additions to JDTUtils#findElementsAtSelection(..) seem to produce better resolutions (eg. hovers) for various tokens, which aren't that informative (in the example i'm using), but better than nothing. Instead of the search engine just looking for type declarations in classfiles, it can now find other types of elements as well.
The search engine will look up for more pattern, it will take more time to return. But i don't see it will affect the code action performance yet. Because SourceAssistProcessor.java will preferentially use the unit.codeSelect branch of findElementsAtSelection method to find the currently selected element.
However, this pull request didn't fix the issue you mentioned at Issue with 'Go To Definition' #1634. 'Go to definition' still stops at 0,0 of the disassembled source contents of the classfile. We need use the same logic to convert position to the location of it's disassembled source. I'm ok to fix go to definition by using a new PR.
go-to-definition.mov
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ReferencesHandler.java
Outdated
Show resolved
Hide resolved
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java
Outdated
Show resolved
Hide resolved
org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ReferencesHandler.java
Outdated
Show resolved
Hide resolved
@testforstephen @rgrunber I have updated the PR. |
return location; | ||
} | ||
|
||
public static ICompilationUnit getWorkingCopy(IClassFile classFile, String contents, IProgressMonitor monitor) throws JavaModelException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not to use ITypeRoot.getWorkingCopy() method directly? What's the difference between this one and ITypeRoot.getWorkingCopy()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We associate a decompiled source with a class file and configure a ICompilationUnit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But in your new findElementAtSelection() method, you're using ClassFile.getWorkingCopy() to attach a decompile source, it looks more concise to me.
ICompilationUnit workingCopy = classFile.getWorkingCopy(new WorkingCopyOwner() { }, monitor);
workingCopy.getBuffer().setContents(contents);
workingCopy.becomeWorkingCopy(monitor);
workingCopy.makeConsistent(monitor);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
try { | ||
if (monitor.isCanceled()) { | ||
return cancelled(res); | ||
} | ||
IJavaElement[] elements = JDTUtils.findElementsAtSelection(unit, line, column, this.preferenceManager, monitor); | ||
ITypeRoot typeRoot = unit; | ||
if (unit instanceof IClassFile && preferenceManager.getPreferences().isIncludeDecompiledSources()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would add check to bypass those class file with source jar attached to avoid creating workingCopy for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
String name = contents.substring(region.getOffset(), region.getOffset() + region.getLength()); | ||
List<IJavaElement> elements = search(unit, name, element, preferenceManager, monitor); | ||
if (monitor != null && monitor.isCanceled()) { | ||
return null; | ||
} | ||
if (elements.isEmpty()) { | ||
elements = search(unit.getJavaProject(), name, element, preferenceManager, monitor); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The codeSelect above already returns a JavaElement, it it possible to make other places to use this result directly? I didn't get the point to use search engine to search the element again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The codeselect finds a java element in a ICompilationUnit we have created using JDTUtils.getWorkingCopy(). We can't return a java element from ICompilationUnit which is created temporarily and destroyed. We have to search a class file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't return a java element from ICompilationUnit which is created temporarily and destroyed.
If this is the only concern, then you can have the outermost caller to create the workingcopy, and destroy the workingcopy until the LSP response returns.
We need to search three times to find the currently selected element, which seems a bit too complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the PR. Could, you, please, review it.
34aa411
to
a7ba70d
Compare
@rgrunber @testforstephen I have updated the PR. It also fixes #1634. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried the latest commit, it works better than before. But i find it's not pretty stable with go-to-definition. For example, in the decompiled StringUtils library, sometimes go to definition can jump to the right position of the decompiled source, sometimes not.
gtd.mov
BTW, i will be off for two weeks. @rgrunber, you can merge it if you test it to be OK.
* | ||
* @param uri | ||
* @param returnCompilationUnit | ||
* @param monitor2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
monitor2 -> monitor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
return resolveCompilationUnit(uri); | ||
} | ||
|
||
public static void discardWorkingCopy(ITypeRoot unit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about naming it as discardClassFileWorkingCopy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@@ -937,6 +1100,20 @@ public static IJavaSearchScope createSearchScope(IJavaProject project, Preferenc | |||
return SearchEngine.createJavaSearchScope(elements, scope); | |||
} | |||
|
|||
public static IJavaSearchScope createSearchScope(IJavaElement element, PreferenceManager preferenceManager) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just searched the code and this new helper method is unused. You can remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed it.
ICompilationUnit workingCopy = null; | ||
workingCopy = getWorkingCopy(classFile, contents, monitor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge them to one line.
ICompilationUnit workingCopy = getWorkingCopy(classFile, contents, monitor);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
I have updated the PR.
Could you try again? |
I think this is working pretty well. The case I've been testing from before seem to be working. Occasionally I got the following stacktrace when selecting the StringWriter type, from line 291 in Gson.class, from the eclipse-sample project :
It seemed to only happen the first few attempts. Otherwise, I'll probably have a look at the new additions, but I think this is in better shape. |
@rgrunber It is an issue related to the fernflower decompiler. Could you, please, test the latest PR? - aec27b7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this change works. I think it's in better shape than before. I still had some cases where go-to-definition would fail the first or 2nd time (eg. From within Gson.class on StringWriter with the java sources installed, "No definition found") but maybe we can address these issues separately as this patch is getting large.
} | ||
return resolveCompilationUnit(uri); | ||
} | ||
|
||
public static void discardClassFileWorkingCopy(ITypeRoot unit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think unit is ever a ClassFileWorkingCopy for me. Is there a specific case where this should happen ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should prepare to merge this after the 0.75.0 release just so that we at least have weeks leading up to 0.76.0 to fix up any regressions that may come up.
I'll still try a few of the use-cases and maybe look at the code more thoroughly, and make suggestions. However, to me the functionality seems pretty solid now, and I think merging + fixing any subsequent issues is the best option.
Signed-off-by: Snjezana Peco <[email protected]>
@rgrunber The issue you have faced is an upstream fernflower issue. |
If that's the case, then let's merge this along with its dependent change and we can address any additional issues that might arise in separate changes. |
@snjeza since you have figured out the cause of this failure, how about sending a PR to Java Decompiler extension?https://github.com/dgileadi/dg.jdt.ls.decompiler/tree/master/dg.jdt.ls.decompiler.fernflower/lib |
I will try. |
Fixes redhat-developer/vscode-java#1665
Fixes #1634
Requires redhat-developer/vscode-java#1773
Signed-off-by: Snjezana Peco [email protected]