PsiFileReference for custom java literal

Answered

I need to open custom file from specified folder after "go to declaration" on java String. I've created PsiReferenceContributor, which registers array of PsiReference (which return single PsiFile as getVariants(), resolve(), etc.), but I still get "cannot find declaration to go" message. There are no examples in documentation related with opening files from "go to".

16 comments
Comment actions Permalink

Please show your code

0
Comment actions Permalink
test code:

public class QueryReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {

registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralExpression.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext
context) {
PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
String value = literalExpression.getValue() instanceof String ?
(String) literalExpression.getValue() : null;
if (value != null) {
PsiReference[] references = Stream.of(FilenameIndex.getFilesByName(element.getProject(), value + ".query", GlobalSearchScope.allScope(element.getProject())))
.map(PsiElement::getReference).toArray(PsiReference[]::new);
return references;
}
return PsiReference.EMPTY_ARRAY;
}

@Override
public boolean acceptsTarget(@NotNull PsiElement target) {
return super.acceptsTarget(target);
}
});
}
}


and class that extends PsiFileImpl:

@Override
public PsiReference getReference() {
new FileReference(new FileReferenceSet("something", QueryFileElement.this, 0, null, true), TextRange.EMPTY_RANGE, 0, "azaz"){
@Override
public String getText() {
return super.getText() + ".query";
}
}
0
Comment actions Permalink

Why does your PsiFileImpl try to return references?

 

QueryReferenceContributor looks like good approach, but simply use FileReferenceSet there and return all references instead of "Stream.of..." expression

0
Comment actions Permalink

ok, I return single FileReference with FileReferenceSet, but still "cannot find declaration to go"

return Stream.of(FilenameIndex.getFilesByName(element.getProject(), value + ".query", GlobalSearchScope.allScope(element.getProject())))
.map(file -> new FileReference(new FileReferenceSet(value, file, 0, null, true), TextRange.EMPTY_RANGE, 0, value))
.toArray(PsiReference[]::new);

0
Comment actions Permalink

You must return com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet#getAllReferences, remove everything with Stream.... around it

0
Comment actions Permalink

Still isn't working

PsiElement[] files = FilenameIndex.getFilesByName(element.getProject(), value + ".query", GlobalSearchScope.allScope(element.getProject()));
return new FileReferenceSet(value, files[0], 0, null, true).getAllReferences();
0
Comment actions Permalink

2nd parameter in FileReferenceSet must be the PsiElement for which references are provided, not the files[0] . Please look at existing usages of FileReferenceSet in IntelliJ Community sources for further details on customizing

0
Comment actions Permalink

So how FileReferenceSet has to know what files to open? There are no constructor parameters for this. "String str"? No. "PsiReferenceProvider provider"? Well, you told me not to create FileReferences manually.

0
Comment actions Permalink

It will resolve to all files which match the limitations set in FileReferenceSet - it can be customized to some degree. if you want to hardcode resolve target to specific file, you can simply return com.intellij.psi.PsiReferenceBase.Immediate and pass file in "resolveTo" parameter

0
Comment actions Permalink

It returns one FileReference, but it just ignored somewhere else

0
Comment actions Permalink

And even when it finds file by name - same situation.

0
Comment actions Permalink

Sorry I don't understand what the exact problem is. Please post/link updated code of what you're trying now

0
Comment actions Permalink
public class QueryReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {

registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralExpression.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext
context) {
PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
String value = literalExpression.getValue() instanceof String ?
(String) literalExpression.getValue() : null;
if (value != null) {
return new FileReferenceSet(value, element, 0, this, false).getAllReferences();
}
return PsiReference.EMPTY_ARRAY;
}
});
}
}

FileReferenceSet returns single FileReference which provides to file with name from "value", but IDE still shows message "cannot find declaration to go". Why?

0
Comment actions Permalink

passing '0' as "startinElement" is most probably wrong (at least for Java String literal). Try passing in com.intellij.psi.ElementManipulators#getOffsetInElement for given literalExpression.

0
Comment actions Permalink
return new FileReferenceSet(value, element, ElementManipulators.getOffsetInElement(element), this, false).getAllReferences();

 

ElementManipulators.getOffsetInElement(element)

for my literal returns 1. Still not working

 

0
Comment actions Permalink

Please share your full plugin's sources and test project that doesn't work as expected

0

Please sign in to leave a comment.