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_CONSTANTThe 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
elementinstead of avalueto thePsiReferenceBaseconstructor.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:
valuebelongs toprop-args, andprop-argsbelong topositive-prop.My logic is this:
valueneeds to be resolved asDTOValueReference, andpositive-propalso 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 separateregisterReferenceProviderforvalueor include “prop or value” in the same pattern, the actual runtime behavior is that clicking onprop-nametriggers parsing forprop; clicking onvaluealso 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 forvaluespecially inPsiReferenceProvider.However, I have now thought of a potential solution, which is to stop creating reference parsing for
propand instead only do it forprop-name. This way,nameandvaluewould 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!