Search references on java class uses limited search scope

已回答

I just discovered that Android-Studio-Refactoring-Scope issue, has appeared in the latest SNAPSHOT build which ignores the selected refactoring and find usages scope and always use “Modules with dependents, scratches and consoles” even if “All Places” or “Project Files” is selected for java class files in the project view.

This causes a problem for Markdown Navigator refactoring because often the markdown files are in the project scope but not in any module. Resulting in links to Java and Kotlin files not being refactored or shown in find usages.

If the markdown file is placed under a module then everything works as expected.

Files such as version history or README are usually at the project root and not in any module and moving them to a module is not possible.

This used to work correctly in all JetBrains IDEs which I tested previously and today I noticed that it no longer works.

The optimization of using consoles & scratches, union module with dependents on class files only makes sense when searching for code references. Other types of references could be located in Project files which the passed scope ignores.

If I ignore the passed in scope and use project all scope then find references does return link references from Markdown. However, Go To Declaration or Usages ignores these references. The same for rename refactoring which leaves these links unchanged causing broken links.

0

Hi Vladimir,

I believe the optimisation is correct (though it's quite old, from April 2019, I think, it was introduced together with scopes in rename refactoring). If you need to find references outside of "normal" use scope, please provide scope enlarger (`com.intellij.psi.search.UseScopeEnlarger`) with included markdown files (e.g. based on file type).

 

Anna 

0

Thanks Anna.

I will implement a UseScopeEnlarger for markdown files. What I find strange is that until lately everything worked. First it failed in Android Studio release, then in snapshot build from intellij-community#master.

0

I see intersection with use scope added in 2019, probably there was another scope enlarger which doesn't work anymore or similar. If you know the version where it worked (IDEA version please, I am not sure I can reliably map AS sources to community sources), I can try to investigate.

But actually it's good that it doesn't work anymore as this means that IDEA becomes faster.

0

Thank you Anna.

I would say there is no need to spend your time on these curiosities. I am almost done implementing the scope enlarger which will fix the issue for all implementations. As long as the issue is solved, I am good.

I did not know about the scope enlarger. I was looking for something like that but missed it.

The JetBrains API is like the world of magic--as long as you know the true name of a thing you can accomplish almost anything. 

 

0

Debug could help, but that's true, we still have too many ways to achieve things and too little documentation. Sorry for that

0

Anna, the scope enlarger fixes Find Usages to show link usages. For that I had to enlarge scope to GlobalSearchScope.allScope(element.getProject()) for Psi class elements which match the containing file name since links always reference files not classes.

However, Go To Declaration or Usages on a link element does not navigate to the file like it used to before.

I stepped the code to https://upsource.jetbrains.com/idea-ce/file/idea-ce-b31e754fe26049a06bee450947daa78eb056aea4/platform/lang-impl/src/com/intellij/codeInsight/navigation/impl/gtdu.kt?nav=1147:1539:focused&line=50&preview=false where declaredData is the link reference location and referencedData is the PsiFile reference.

The action shows "No Usages Found in Project Files" is displayed because the code is trying to show usages of link address from the declaration, not references to PsiFile. BTW, Show Usages, popups up with the link and the file as choices for what usages to find. Selecting link element shows no usages as expected since a link is not a declaration but a reference.

This is a change in how this actions used to be handled.

What is the correct way to handle a reference to a file from another element?

Markdown links have references to files, ie. element.getReference().resolve() returns PsiFile element.

The link address element also implements PsiNameIdentifierOwner. Could this be causing a problem of the IDE treating the link address element as a declaration and not only as having references to file(s)? I do not remember why it implements PsiNameIdentifierOwner, could be for old historical reasons or my misunderstanding in the original implementation, which is an unnecessary hold-over to be removed.

I also saw in the code uses of GotoDeclarationHandler which I never implemented. Do I need to implement a handler for link elements and do I return an empty array or references to file(s) that this link targets?

 

0

Hi Anna,

I removed implementation of PsiNamedIdentifierOwner from all elements which refer to other PsiElement not actually defining a declaration element. 

This has not affected the IDE behaviour. It still treats link addresses as definitions.

How does IDE determine whether an element is a declaration element?

0

Hi Anna,

I figured it out. It is the implementation of PsiNamedIdentifierOwner which is causing the problems. I removed it from the interfaces in question but missed that some implementation classes had the interface implemented explicitly.

Once I removed PsiNamedIdentifierOwner from all link elements and other non-declaration elements, both navigation and find usages started working as before.

It seems that the IDE implementation was cleaned up and this caused the previously working (by accident) code to fail.

Thank you very much for your suggestions. It helped a lot to get me to re-think the old code.

0

Hi Anna,

Next issue is rename refactoring on a link reference to a Java file, which sound a short beep of not available. Link references to Markdown or other non Java work. Rename refactoring on a link reference to a Kotlin file also work. So this is only a link reference to a Java file which is not available.

Renaming the class/file node in the project view does update the links as expected. 

I suspect this is caused by link references returning a reference to a file instead of the Java Psi class which the file represents.

How can I handle rename refactoring which will allow renaming of link references to Java files?

0

Hi Vladimir,

sorry it was too late for me yesterday to answer.

So you have a reference to java file which works (navigate works, ref.resolve() goes to java file) but rename action is not available? Do you check master or 2020.1?

Anna

0

Anna, I am using master SNAPSHOT build, but the behaviour is the same in 2020.2, 2020.1, 2019.3, and 2019.2.

0

Please put a breakpoint to the `com.intellij.refactoring.actions.BaseRefactoringAction#findRefactoringTargetInEditor`, what element is calculated there?

0

Hi Anna,

The computed element is PsiJavaFile, which is expected since the link refers to a file.

I traced it to JavaVetoRenameCondition the last condition which returns true and disables the rename:

element instanceof PsiJavaFile &&
!FileTypeUtils.isInServerPageFile(element) &&
!JavaProjectRootsUtil.isOutsideJavaSourceRoot((PsiFile)element) &&
((PsiJavaFile) element).getClasses().length > 0

 

 

0

From what I understand in the code, renaming of a Java file which contains classes is not allowed from references.

0

that's true. IDEA isn't sure if you want to rename a same named class as well, probably the condition could be lessened though. WDYT?

0

If this condition is only used when renaming from code references then it can probably changed to allow renaming of a Java file and the contained class if the file contains a single class which would be easy to test.

How would the class be included when renaming the file or will the IDE prompt whether the class should also be renamed?

0

Is there a way for me to add this specific case as an extension point in my plugin? In other words, for rename refactoring, substitute a Java class for Java file reference?

0

I would say that it's easier to refer to java class instead of file, probably.

If I would ease the condition, then same named class would be renamed automatically or no class would be renamed

0

This is what I thought. Doing it on the IDE end, risks way too many unforeseen side effects.

I will have to create a utility function which will resolve a reference instead of using PsiReference#resolve(), which will return the PsiFile when the resolve method returns a Java class element. Then a reference to a Java class file will return a reference to the contained class instead.

The plugin code expects a PsiFile when a reference from link element is resolved. I will need to use the utility function everywhere a reference is resolved to make sure I don't introduce dozens of failures for links to Java files.

0

请先登录再写评论。