When returning multiple references from PsiReferenceProvider#getReferencesByElement, the highlighting effect is gone
Answered
The BNF structure looks like this:
positive-prop ::= prop-name prop-args? {
pin = 1
implements="net.fallingangel.jimmerdto.psi.mixin.DTONamedElement"
mixin="net.fallingangel.jimmerdto.psi.mixin.impl.DTONamedElementImpl"
methods=[getPsi getName setName]
}
prop-name ::= IDENTIFIER | "null"
prop-args ::= "(" value ("," value)* ")"
value ::= CHAR_CONSTANT | STRING_CONSTANT
The implementation of PsiReferenceProvider#getReferencesByElement is as follows:
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerReferenceProvider(
psiElement(DTONamedElement::class.java),
object : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
element as DTOPositiveProp
val propArgs = element.propArgs
@Suppress("IfThenToElvis")
return if (propArgs == null) {
arrayOf(DTOReference(element, element.propName.textRangeInParent))
} else {
propArgs.valueList
.map {
val valueStart = it.textRangeInParent.startOffset
val argStart = it.parent.textRangeInParent.startOffset
val valueInArgStart = argStart + valueStart
DTOValueReference(it, element, TextRange(valueInArgStart, valueInArgStart + it.textLength))
}
.toTypedArray()
}
}
},
)
}
The DTOValueReference is implemented as follows:
class DTOValueReference(private val value: DTOValue, element: PsiElement, textRange: TextRange) : PsiReferenceBase<PsiElement>(element, textRange) {
override fun resolve(): PsiElement? {
val project = value.project
val entityFile = value.virtualFile.entityFile(project) ?: throw IllegalStateException()
val propName = value.text
val prop = value.parent.parent as DTOPositiveProp
return when (entityFile.language) {
Language.Java -> {
val clazz = prop.psiClass()
clazz.methods().find { it.name == propName }
}
Language.Kotlin -> {
val clazz = prop.ktClass()
clazz.properties().find { it.name == propName }
}
}
}
}
The actual runtime case where one DTOValueReference
is returned:

The actual runtime case where more than one DTOValueReference
is returned:


As you can see, when one DTOValueReference
is returned, it's exactly as expected; when more than one DTOValueReference
is returned, the highlighting of each DTOValue
is lost, but other things such as documentation and reference parsing are as expected.
Please sign in to leave a comment.
Hi,
This looks suspicious to me:
This is a reference for a value, but you pass an
element
instead of avalue
to thePsiReferenceBase
constructor.Yes... it's quite possible that my parsing element is "value," while the "element" is a parent of "value". I'll give it a try!
Here's the situation:
My BNF structure is as follows:
value
belongs toprop-args
, andprop-args
belong topositive-prop
.My logic is this:
value
needs to be resolved asDTOValueReference
, andpositive-prop
also needs to be resolved asDTOReference
. Herein lies a problem:When registering structures in
registerReferenceProvider
, if the pattern is set forpositive-prop
, whether I write a separateregisterReferenceProvider
forvalue
or include “prop or value” in the same pattern, the actual runtime behavior is that clicking onprop-name
triggers parsing forprop
; clicking onvalue
also triggers parsing forprop
, causing confusion in logic. This is why I created a base class for elements (DTONamedElement
) and two reference classes (DTOReference
,DTOValueReference
), and why I handled the reference forvalue
specially inPsiReferenceProvider
.However, I have now thought of a potential solution, which is to stop creating reference parsing for
prop
and instead only do it forprop-name
. This way,name
andvalue
would not have a parent-child relationship, which should prevent the confusion in reference parsing when clicking on elements.I am going to try this new approach.
Exactly, that's how it is! The issue has been resolved, thank you, Karol Lewandowski!