Get usages in return from referenced element
PsiReferenceContributor implementation:
public class ImplementationStepReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(literalExpression(), new ImplementationStepReferenceProvider());
}
}
PsiReferenceProvider:
public class ImplementationStepReferenceProvider extends PsiReferenceProvider {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext context) {
if (isStepCallLiteral(psiElement)) {
return new PsiReference[] { new ImplementationStepReference((PsiLiteralExpression) psiElement) };
}
return PsiReference.EMPTY_ARRAY;
}
}
PsiReferenceBase<PsiLiteralExpression>:
public class ImplementationStepReference extends PsiReferenceBase<PsiLiteralExpression> {
public ImplementationStepReference(@NotNull PsiLiteralExpression element) {
super(element);
}
@Override
public @Nullable PsiElement resolve() {
return SearchUtil.findSingleStepImplementation(myElement).orElse(null);
}
}
This code gives me a single reference to a method from a specific PsiLiteralExpression.
Example:
From some where I call translate method of class Specification:
public void steps() {
new Specification().translate("this is my step name example");
new Specification().translate("this is my step name example");
new Specification().translate("this is my step name example");
}
And my method that I bind must be annotated like this:
@Step("this is my step name example")
public void someMethod() {}
My implementation supports CTRL+ click onto literal on method call -> new Specification().translate("this is my step name example"); and it navigates me to a method successfully.
But how do I implement usages in return?
If I have a reference to a method at least in one place it shouldn't be popping a warning that it is not used anywhere but to provide 3 usages as in the example above in return.
Thanks,
Serhii
Please sign in to leave a comment.
Hi Serhii,
You can try implementing QueryExecutorBase, which will search for method references with custom names (value of @Step in your case). It can look like this (in Kotlin):
and register it as:
Of course, your reference's isReferenceTo() should return true if asked for the searched method.
Karol Lewandowski It worked instantly, cool!
However search by word has limitations because it is compared by equals I suppose. What if I need to search by regexp instead?
I looked at method:
But it seems to be super difficult to compose and I am not sure this is the right way.
Hi Serhii,
This case is harder to handle. The Find Usages mechanism is based on word index, so occurrences of words will be processed. See:
https://plugins.jetbrains.com/docs/intellij/find-usages.html
If your regular expressions contain any words, then you can split them and invoke searchParams.optimizer.searchWord() for each word, and of course, in isReferenceTo() return true if the found element text matches the regexp.
Hi Karol Lewandowski
I've tried to implement FindUsagesProvider but looks like it requires Custom Language Lexer to be implemented and corresponding dependencies, isn't it?
Can't I do this without such chellenges?
This is what I've started with, just to understand if my FindUsagesProvider ever called:
But when I trigger an action CTRL + click on method name only constructor is called and no other overriden methods.
What can be wrong here?
Hi Serhii,
I don't think this is a way to go, or I don't get your idea.
FindUsagesProvider is intended to be implemented for custom languages. Java Find Usages Provider is implemented in the Java plugin: com.intellij.lang.java.JavaFindUsagesProvider.
Your provider is not called because JavaFindUsagesProvider is found before your provider as a one that supports finding methods, see:
https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/lang/java/JavaFindUsagesProvider.java#L37
Karol Lewandowski
Sorry for misleading, let me make my goal clear.
So having method call:
And resolving method:
I have a single reference on a literal myObject.translate("this is my step 'text' example"); which navigates me to a method (method name if you wish) ...public void someMethod() {...}
It is implemented through regex match of method annotation literal @Step("this is my step $name example"). In other words:
So my $name in annotation literal is a parameter that matches anything in single quotes.
This works perfectly.
Then, I want to make this vise-versa:
Clicking on a method name with CTRL:
Show me usages that match the same pattern:
Hope this is clear now. Looking forward for your reply!
Thank you,
Serhii
Thanks for the explanation.
I think that you can implement something very similar to my previous proposal, so extending the method reference search with additional words to search, with the difference that you can slightly modify the word to search by avoiding the dynamic part, e.g.:
Karol Lewandowski
It worked like a charm, thank you so much for help provided. Topic can be closed ;)