How to check whether element ever referenced by custom reference

Answered

I have implemented a PsiReferenceContributor for specific PsiExpressionLiteral elements. They refer to methods.
But method is highlighted as "never used".
How can I suppress this warning?

I've started with HighlightInfoFilter:

@Override
public boolean accept(@NotNull HighlightInfo highlighted, @Nullable PsiFile psiFile) {
if (psiFile == null | !highlighted.getSeverity().equals(HighlightSeverity.WARNING)) {
return true;
}
PsiElement element = psiFile.findElementAt(highlighted.getStartOffset());
if (element == null | highlighted.getDescription() == null) {
return true;
}
if (!(element instanceof PsiIdentifier)) {
return true;
}
PsiMethod method = getParentOfType(element, PsiMethod.class);
if (method == null) {
return true;
}
...other method specific filtering...
// Now here how can I make sure this method is really referenced at least once?
}

method.getReference()
method.getReferences()
method.getOwnReferences()

all of these return null of empty array.

9 comments
Comment actions Permalink

Hi Serhii,

Please take a look at com.intellij.codeInsight.daemon.ImplicitUsageProvider.

0
Comment actions Permalink

Karol Lewandowski
Tried to implement this, but I don't get how to complete my validation...

In my case it should return true if any reference leads to my element (please see comment in the code):

public class MyUsageProvider implements ImplicitUsageProvider {

@Override
public boolean isImplicitUsage(@NotNull PsiElement psiElement) {
if (psiElement instanceof PsiMethod && ((PsiMethod) psiElement).hasAnnotation("some.annotation.of.mine.Example")) {
// should only return true if any reference leads to this method
return true;
}
return false;
}

@Override
public boolean isImplicitRead(@NotNull PsiElement psiElement) {
return false;
}

@Override
public boolean isImplicitWrite(@NotNull PsiElement psiElement) {
return false;
}
}

So basically I am looking for a solution of problem:

How to find elements that references to current element
0
Comment actions Permalink

You should check if element is references and it can be done by searching for references:

ReferencesSearch.search(element, scope).findFirst() != null

Additionally, it can be cached:

CachedValuesManager.getManager(project).getCachedValue(element) {
CachedValueProvider.Result.create(
ReferencesSearch.search(element, scope).findFirst() != null,
PsiModificationTracker.SERVICE.getInstance(project).forLanguage(JavaLanguage.INSTANCE) // if references are only in Java
)
}
0
Comment actions Permalink

Yes, I tried that as well, however with .findAll();
But it always returns me empty collection

0
Comment actions Permalink

Is the isReferenceTo() in your references called? What is the scope you pass to the references search?

0
Comment actions Permalink

Just to skip all misunderstandings here is the example:

I have a literal in code (lets imagine it works only for literals with value "I am literal"):


When I Hold CTRL it resolves as it has a reference:


After CTRL + click idea navigates me to class:


But as you can see class indicates that it is not used anywhere.

Now, my code looks like this:

public class MyReference extends PsiReferenceBase<PsiLiteralExpression> {

private final JavaPsiFacade psiFacade = new JavaPsiFacadeImpl(myElement.getProject());

public MyReference(@NotNull PsiLiteralExpression element) {
super(element);
}

@Nullable
@Override
public PsiElement resolve() {
return psiFacade.findClass(
"my.example.reference.MyClass",
myElement.getResolveScope()
);
}

@Override
public boolean isReferenceTo(@NotNull PsiElement element) {
if (element instanceof PsiClass) {
PsiClass myPsiClass = psiFacade.findClass(
"my.example.reference.MyClass",
myElement.getResolveScope()
);
return element.isEquivalentTo(myPsiClass);
}
return false;
}
}
public class MyReferenceContributor extends PsiReferenceContributor {

@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(
literalExpression(),
new PsiReferenceProvider() {

@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {
if (!(psiElement instanceof PsiLiteralExpression)) {
return PsiReference.EMPTY_ARRAY;
}
PsiLiteralExpression literal = (PsiLiteralExpression) psiElement;
String literalValue = PsiLiteralUtil.getStringLiteralContent(literal);
if (!literalValue.equals("I am literal")) {
return PsiReference.EMPTY_ARRAY;
}
PsiReference[] references = PsiReference.ARRAY_FACTORY.create(1);
references[0] = new MyReference(literal);
return references;
}
});
}
}

How can I suppress "class never used" warning if in the project I have ANYWHERE at least one literal used with value - "I am literal" ?

0
Comment actions Permalink

Thanks for sharing, but the previous question remains: is the isReferenceTo() called when usages are searched?

If the class doesn't see the usages in your custom references, then I suspect that they are in different scopes. If the scope is the case, then in implicit usage provider you will probably have to use a wide scope that includes your references (I mean scope in ReferencesSearch.search(aClass, scope).

0
Comment actions Permalink

Yes, it is called when usages are searched.
Should I use this - is this the widest scope available?

GlobalSearchScope.allScope(element.getProject())


EDIT:

Also tried with this - neither worked for me ;(

0
Comment actions Permalink

Got this working for methods, exactly what I was looking for:

MethodReferencesSearch.search(method, method.getResolveScope(), true).iterator().hasNext()

Thank you Karol Lewandowski

0

Please sign in to leave a comment.