I have an IntelliJ plugin that is walking PsiReference resolutions to a "distant" class, and having trouble because the resolve()
method is returning null if and only if i have not navigated to the distant file in the editor during the current IntelliJ session. I suspect that IntelliJ needs to be prodded to parse the file in some sense (when you navigate to the file, you can see that IntelliJ kicks off some sort of parsing run as a lot of the code goes from being minimally highlighted to fully highlighted) but I don't know how to do that. I looked in PsiManager
and PsiFile
, where I found some refresh()
and reloadFromDisk()
methods, but I'm guessing these have a lot of side-effects I don't want and probably won't kick off the parsing run anyways. Details/clarification below.
The code looks something like this:
File 1, in which I invoke a plugin action on foo
:
@AnnotationReferringToAnotherType(File2.class)
class File1 {
String foo;
}
File 2, which the plugin must lookup in order to perform the action on foo
:
class File2 {
@File3
void mustBeLookedUpToHandleAction() {}
}
File 3 must also be looked up:
@interface File3 {
public enum SomeEnum {
DEFAULT,
SOMETHING_ELSE
}
SomeEnum value() default SomeEnum.DEFAULT;
}
I perform the action on foo
, and then the logic finds the @AnnotationReferringToAnotherType
at the top of the containing file (File 1) and resolve()
s to the definition of File2
. Then it looks for a method in File2
that is annotated with @File3
. Since the @File3
annotation on mustBeLookedUpToHandleAction
does not specify its value, the plugin must now look up the definition of @File3
in order to determine what the default value is. All of this works completely smoothly after freshly loading IntelliJ. The part that fails is the resolve()
from the PsiReferenceExpression
SomeEnum.DEFAULT
to the actual definition of DEFAULT
in SomeEnum
. It consistently returns null
, until i navigate, in the editor, to File 3, and after that it works every time for the remainder of the session. It seems clear that the references' resolutions are being parsed lazily, and if i can just find some way to kick off that parsing everything should be OK?
You may be thinking "why the hell is this logic so complicated?". Most of the logic is actually in a library i'm using - it's internal, so i may be able to get some changes made but I doubt i'll be able to make fundamental changes on account of this issue unless this issue turns out to be completely unmanageable.
Turns out this is a bug in IntelliJ: https://youtrack.jetbrains.com/issue/IDEA-133994
the workaround is to call
getText()
on one of the annotation definition'sPsiElement
s before callingresolve()
- e.g. once you have thePsiAnnotationMethod
forFile3.value
callgetText()
on it before callinggetDefaultValue().resolve()
deets:
The definition for
File3
is "stubbed", so only the core components of its psi tree are actually available. Whenever information is requested from the stub that the stub doesn't have (e.g. by callinggetText
), the file containing the stubbed psi tree will be fully parsed and the stub replaced with a complete psi tree (see https://confluence.jetbrains.com/display/IDEADEV/Indexing+and+PSI+Stubs+in+IntelliJ+IDEA). The particular implementation ofPsiAnnotationMethod.getDefaultValue
will return a dummyPsiAnnotationMemberValue
if the annotation is stubbed, and that dummy element is apparently not knowledgeable to honor theresolve()
.