Is it possible to use getNavigationElement on a PsiFile ? (stack trace in UsageInfo)
In my language, when a file has a function ‘make()’ I want to navigate to this function.
For that, I have implemented the getNavigationElement method in my FileBase.java class (that inherits from PsiFileBase). If there is a make I return that PsiElement instead, something like this:
class FileBase inherits PsiFileBase {
public PsiElement getNavigationElement() {
if (isComponent()) {
for (RPsiLet let : PsiTreeUtil.getStubChildrenOfTypeAsList(this, RPsiLet.class)) {
if ("make".equals(let.getName())) {
return let;
}
}
}
return super.getNavigationElement();
}
The problem is when a user is doing a ‘find in files’, the search is correct but the preview doesn’t show anything, and I got a stack trace like this one:
java.lang.IllegalArgumentException: element RPsiLet:make; startOffset 3341; endOffset=3351; effectiveStart=-490; effectiveEnd=-480; elementRange=(3831,8268); element.getTextOffset()=3835
at com.intellij.usageView.UsageInfo.<init>(UsageInfo.java:71)
at com.intellij.usageView.UsageInfo.<init>(UsageInfo.java:122)
at com.intellij.find.impl.FindResultUsageInfo.<init>(FindResultUsageInfo.java:48)
at com.intellij.find.impl.FindInProjectUtil.processSomeOccurrencesInFile(FindInProjectUtil.java:303)
at com.intellij.find.impl.FindInProjectUtil.lambda$processUsagesInFile$4(FindInProjectUtil.java:265)
at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:941)
at com.intellij.openapi.application.ReadAction.compute(ReadAction.java:68)
at com.intellij.find.impl.FindInProjectUtil.processUsagesInFile(FindInProjectUtil.java:264)
at com.intellij.find.impl.FindInProjectTask.processFindInFilesUsagesInFile(FindInProjectTask.java:251)
at com.intellij.find.impl.FindInProjectTask.lambda$wrapUsageProcessor$6(FindInProjectTask.java:205)
at com.intellij.find.impl.FindInProjectTask.lambda$findUsages$4(FindInProjectTask.java:154)
at com.intellij.openapi.roots.impl.FilesScanExecutor.lambda$doProcessOnAllThreadsInReadAction$1(FilesScanExecutor.java:99)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1154)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.lambda$runInReadActionWithWriteActionPriority$0(ProgressIndicatorUtils.java:75)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.runActionAndCancelBeforeWrite(ProgressIndicatorUtils.java:158)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.lambda$runWithWriteActionPriority$1(ProgressIndicatorUtils.java:115)
at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:66)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:188)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:608)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:683)
at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:639)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:607)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:60)
at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:175)
at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:66)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.runWithWriteActionPriority(ProgressIndicatorUtils.java:112)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(ProgressIndicatorUtils.java:75)
at com.intellij.openapi.roots.impl.FilesScanExecutor.lambda$doProcessOnAllThreadsInReadAction$2(FilesScanExecutor.java:98)
at com.intellij.openapi.roots.impl.FilesScanExecutor.lambda$processOnAllThreads$3(FilesScanExecutor.java:141)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:188)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:608)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:683)
at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:639)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:607)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:60)
at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:175)
at com.intellij.openapi.roots.impl.FilesScanExecutor.lambda$runOnAllThreads$0(FilesScanExecutor.java:65)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at com.intellij.util.concurrency.BoundedTaskExecutor.doRun(BoundedTaskExecutor.java:241)
at com.intellij.util.concurrency.BoundedTaskExecutor.access$200(BoundedTaskExecutor.java:31)
at com.intellij.util.concurrency.BoundedTaskExecutor$1.execute(BoundedTaskExecutor.java:214)
at com.intellij.util.ConcurrencyUtil.runUnderThreadName(ConcurrencyUtil.java:212)
at com.intellij.util.concurrency.BoundedTaskExecutor$1.run(BoundedTaskExecutor.java:203)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:702)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:699)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:699)
at java.base/java.lang.Thread.run(Thread.java:833)
The problem is that originalElement is the file and element is the navigationElement. Because element is different from originalElement a delta is computed and is negative (fileStartOffset - elementStartOffset)
Is it possible to have a navigationElement for a PsiFile, and if yes, what method should I implement to not get the exception ?
Please sign in to leave a comment.
Hi Giraud,
I understand that you want to navigate to the make function when you navigate to a file from usages in the editor with the “Go to declaration” action.
If it is the case, please try implementing com.intellij.codeInsight.TargetElementEvaluatorEx2.getGotoDeclarationTarget() (and register it in com.intellij.targetElementEvaluator extension point) to return the make() function if it exists.
I’ll try and let you know, thank you
It works for this use case, thanks.
I still have few more questions if you don’t mind:
- I have other PsiElements (not files) that implement this getNavigationElement() method. should I remove it and always use the TargetElementEvaluatorEx2 instead ? when getNavigationElement should be used ?
- How to test navigation with fixtures ? before I would just do myFixture.getElementAtCaret() and get the PsiElement of the function, now I get the file.
Sure.
1. According to method's Javadoc:
It seems that the purpose of this method is to override it in cases when the element doesn't have a physical PSI representation ("does not have a file and offset"). In your case, elements do have files and offsets (even if it is 0), so it doesn't apply. I suggest using TargetElementEvaluator for other elements too.
2. You can try the following approach (Kotlin code):
woah, very helpful !