"Find Usages" doesn't work despite "Go to Declaration" works

Hi, everyone!
I am working on plugin for custom language working in pair with *.lua files from EmmyLua.
It went pretty good until I faced a challenge where “Find Usages” from my custom language file *.simple unable to find reference in the *.lua file despite “Go to Declaration” can lead me from *.lua file to *.simple.

For sake of testing I figured out that something wrong with ReferenceContributor because I had to re-write it to support psiElements from EmmyLua. The only one change from simple_language_plugin you can find here - contributor · SaloEater/simple_language_plugin@ab9d7b9 · GitHub

To reproduce issue, just clone the repo, run runIde gradle, open test_folder and try to find usages for s.simple:prop (it doesn’t work). And try to get reference from file.lua:simple:prop (it works)

I am so desperate and lost that I am willing to do anything to get this weird issue solved.

Have you implemented com.intellij.psi.PsiElement#getUseScope and com.intellij.psi.PsiElement#getResolveScope for your PsiElements in your *.ltx files, which are the target of references?

Are these implementing PsiNameIdentifierOwner or PsiNamedElement?

Have you properly implemented com.intellij.psi.PsiReference#isReferenceTo for your references?

Just a few thoughts without checking your sources, but these are common problems with “Find Usages”.

Thanks for the answer!
Gonna research about PsiElement#getUseScope and PsiElement#getResolveScope.
Unfortunately, isReferenceTo set just to return true and even with that it’s not called when i am Find Usages for elements from *.ltx files

“Find usages” on a reference first locates the definition of the reference and then collects usages for this definition. The scopes mentioned above are used for these lookups. Without proper scopes, “Find Usages” won’t work as expected. So hopefully this should fix it.
Also experiment with the named elements, there were a few assumptions in the platform code about definition elements, as far as I remember.

Will try to dig in this direction, appreciate it!

It’s just very weird that while demo plugin simple_language_plugin works fine with Java, “Find Usages” no longer works when I switch to Lua language and there is no point where we can debug the difference due to huge amount of hidden frames T_T

The sources you linked seem incomplete, there isn‘t a plugin.xml file for example.

I can only guess why there‘s a difference. There‘s a find usage handler in your repo, perhaps that‘s inactive?
Is the resolve of your references returning PsiNamedElement?

My bad for doing poor with the repository.
Here is fixed link and it was updated in the first message - GitHub - SaloEater/simple_language_plugin at cumulative

Yes, resolve results in picking corrent elements from *.simple file

Hi, I tried my best with copilot to apply your previous answers but still unable to make it work.
Is there anything else I can research or maybe there are dedicated marketplace where I can hire/talk to actual plugins developers?
Or maybe I can ask you to clone and debug that plugin?

Thank you in advance

P.S. I figured out PsySearchHelperImpl: this.processVirtualFile(vfile, stopped, localProcessor); doesn’t even work with .lua file, looking deeper

Although I’m offering consulting for plugin development, this wouldn’t be a fit for a single problem.

Your repository is not buildable (not build file) and is apparently not the original repository, because it doesn’t have any file type associations for *.ltx file you mentioned.

Thank you very much for returning to this thread again!
Just pushed files required to build the project, please, take another look.

Please, forget about *.ltx file format, it’s only *.simple. Repository is literally official custom language support tutorial but instead of *.java just trying to use *.lua.

Please, use test-folder directory to test plugin functionality.

This was a bit tricky.

Find usages first resolves to the definition of the current element.
Then the definition is the start to find references in the project.
Because parsing every file is too slow, find usages relies on a word index. Any file with a word matching the name of the definition is searched.
The words are provided by com.intellij.lang.findUsages.FindUsagesProvider#getWordsScanner.

Because the word scanner used by Lua doesn’t provide "simple:my_key" as multiple, separate words the word index does not contain my_key and find usages has no result.

A possible workaround (not safe for production) is this:

  • Register this instead for Lua. You registered SimpleFindUsagesProvider for Lua, which is incorrect. SimpleFindUsagesProvider is only working for the Simple language.

    <lang.findUsagesProvider language="Lua" order="first"
        implementationClass="org.intellij.sdk.language.LuaFindUsagesProvider"/>
    
  • Implementation using a very basic scanner. For production, a better word scanner is needed, e.g. similar to DefaultWordScanner, but splitting literal content at :. There may be alternative solutions by providing more low-level find usages extensions, but I wouldn’t do that.

final class LuaFindUsagesProvider implements FindUsagesProvider {
  private final FindUsagesProvider delegate = new com.tang.intellij.lua.usages.LuaFindUsagesProvider();

  @Override
  public WordsScanner getWordsScanner() {
    return new SimpleWordsScanner();
  }

  @Override
  public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
    return delegate.canFindUsagesFor(psiElement);
  }

  @Nullable
  @Override
  public String getHelpId(@NotNull PsiElement psiElement) {
    return delegate.getHelpId(psiElement);
  }

  @NotNull
  @Override
  public String getType(@NotNull PsiElement element) {
    return delegate.getType(element);
  }

  @NotNull
  @Override
  public String getDescriptiveName(@NotNull PsiElement element) {
    return delegate.getDescriptiveName(element);
  }

  @NotNull
  @Override
  public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
    return delegate.getNodeText(element, useFullName);
  }
}

The java language’s find usage implementation is more complex, that’s why it probably worked but Lua did not.

1 Like

That’s straightforward cool!
Appreciate your patience and working example very much!

Will definitely spend development time on making a dedicated DefaultWordScanner when other parts are done.

Thanks again!