Use one KtDestructuringDeclarationReference per each entry - better highlight usages and other actions
This commit is contained in:
@@ -34,13 +34,12 @@ object UsageTypeUtils {
|
||||
fun getUsageType(element: PsiElement?): UsageTypeEnum? {
|
||||
when (element) {
|
||||
is KtForExpression -> return IMPLICIT_ITERATION
|
||||
is KtDestructuringDeclaration -> return READ
|
||||
is KtDestructuringDeclarationEntry -> return READ
|
||||
is KtPropertyDelegate -> return PROPERTY_DELEGATION
|
||||
is KtStringTemplateExpression -> return USAGE_IN_STRING_LITERAL
|
||||
}
|
||||
|
||||
val refExpr = element?.getNonStrictParentOfType<KtReferenceExpression>()
|
||||
if (refExpr == null) return null
|
||||
val refExpr = element?.getNonStrictParentOfType<KtReferenceExpression>() ?: return null
|
||||
|
||||
val context = refExpr.analyze()
|
||||
|
||||
|
||||
+8
-24
@@ -26,9 +26,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
class KotlinReferenceContributor() : AbstractKotlinReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
with(registrar) {
|
||||
registerProvider<KtSimpleNameExpression> {
|
||||
KtSimpleNameReference(it)
|
||||
}
|
||||
registerProvider<KtSimpleNameExpression>(factory = ::KtSimpleNameReference)
|
||||
|
||||
registerMultiProvider<KtNameReferenceExpression> {
|
||||
if (it.getReferencedNameElementType() != KtTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
|
||||
@@ -43,33 +41,19 @@ class KotlinReferenceContributor() : AbstractKotlinReferenceContributor() {
|
||||
}
|
||||
}
|
||||
|
||||
registerProvider<KtConstructorDelegationReferenceExpression> {
|
||||
KtConstructorDelegationReference(it)
|
||||
}
|
||||
registerProvider<KtConstructorDelegationReferenceExpression>(factory = ::KtConstructorDelegationReference)
|
||||
|
||||
registerProvider<KtCallExpression> {
|
||||
KtInvokeFunctionReference(it)
|
||||
}
|
||||
registerProvider<KtCallExpression>(factory = ::KtInvokeFunctionReference)
|
||||
|
||||
registerProvider<KtArrayAccessExpression> {
|
||||
KtArrayAccessReference(it)
|
||||
}
|
||||
registerProvider<KtArrayAccessExpression>(factory = ::KtArrayAccessReference)
|
||||
|
||||
registerProvider<KtForExpression> {
|
||||
KtForLoopInReference(it)
|
||||
}
|
||||
registerProvider<KtForExpression>(factory = ::KtForLoopInReference)
|
||||
|
||||
registerProvider<KtPropertyDelegate> {
|
||||
KtPropertyDelegationMethodsReference(it)
|
||||
}
|
||||
registerProvider<KtPropertyDelegate>(factory = ::KtPropertyDelegationMethodsReference)
|
||||
|
||||
registerProvider<KtDestructuringDeclaration> {
|
||||
KtDestructuringDeclarationReference(it)
|
||||
}
|
||||
registerProvider<KtDestructuringDeclarationEntry>(factory = ::KtDestructuringDeclarationReference)
|
||||
|
||||
registerProvider<KDocName> {
|
||||
KDocReference(it)
|
||||
}
|
||||
registerProvider<KDocName>(factory = ::KDocReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-11
@@ -22,22 +22,16 @@ import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
|
||||
class KtDestructuringDeclarationReference(element: KtDestructuringDeclaration) : KtMultiReference<KtDestructuringDeclaration>(element) {
|
||||
class KtDestructuringDeclarationReference(element: KtDestructuringDeclarationEntry) : AbstractKtReference<KtDestructuringDeclarationEntry>(element) {
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
return expression.entries.mapNotNull { entry ->
|
||||
context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry)?.candidateDescriptor
|
||||
}
|
||||
return context[BindingContext.COMPONENT_RESOLVED_CALL, element]?.candidateDescriptor.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
override fun getRangeInElement(): TextRange? {
|
||||
val start = expression.lPar
|
||||
val end = expression.rPar
|
||||
if (start == null || end == null) return TextRange.EMPTY_RANGE
|
||||
return TextRange(start.startOffsetInParent, end.startOffsetInParent)
|
||||
}
|
||||
override fun getRangeInElement() = TextRange(0, element.textLength)
|
||||
|
||||
override fun canRename(): Boolean {
|
||||
val bindingContext = expression.analyze() //TODO: should it use full body resolve?
|
||||
|
||||
+17
-6
@@ -23,9 +23,11 @@ import com.intellij.psi.PsiReferenceService
|
||||
import com.intellij.psi.ReferenceRange
|
||||
import com.intellij.psi.search.RequestResultProcessor
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isCallableOverrideUsage
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isExtensionOfDeclarationClassUsage
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isUsageInContainingDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
class KotlinRequestResultProcessor(
|
||||
@@ -37,18 +39,27 @@ class KotlinRequestResultProcessor(
|
||||
private val referenceService = PsiReferenceService.getService()
|
||||
|
||||
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
|
||||
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
|
||||
val references = if (element is KtDestructuringDeclaration)
|
||||
element.entries.flatMap { referenceService.getReferences(it, PsiReferenceService.Hints.NO_HINTS) }
|
||||
else
|
||||
referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS)
|
||||
return references.all { ref ->
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
when {
|
||||
!filter(ref) -> true
|
||||
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
|
||||
!ref.isReferenceToTarget(unwrappedElement) -> true
|
||||
else -> consumer.process(ref)
|
||||
if (filter(ref) && ref.containsOffsetInElement(offsetInElement) && ref.isReferenceToTarget(unwrappedElement)) {
|
||||
consumer.process(ref)
|
||||
}
|
||||
else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiReference.containsOffsetInElement(offsetInElement: Int): Boolean {
|
||||
if (this is KtDestructuringDeclarationReference) return true
|
||||
return ReferenceRange.containsOffsetInElement(this, offsetInElement)
|
||||
}
|
||||
|
||||
private fun PsiReference.isReferenceToTarget(element: PsiElement): Boolean {
|
||||
if (isReferenceTo(element)) {
|
||||
return true
|
||||
|
||||
+13
-13
@@ -118,8 +118,16 @@ fun findDestructuringDeclarationUsages(
|
||||
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
|
||||
}
|
||||
|
||||
val componentIndex = when (ktDeclaration) {
|
||||
is KtParameter -> ktDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) }
|
||||
is KtFunction -> ktDeclaration.name?.let { getComponentIndex(it) }
|
||||
//TODO: java component functions (see KT-13605)
|
||||
else -> null
|
||||
} ?: return
|
||||
|
||||
Processor(dataType,
|
||||
ktDeclaration,
|
||||
componentIndex,
|
||||
scope,
|
||||
consumer,
|
||||
plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) },
|
||||
@@ -141,6 +149,7 @@ private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, opti
|
||||
private class Processor(
|
||||
private val dataType: FuzzyType,
|
||||
private val target: KtDeclaration,
|
||||
private val componentIndex: Int,
|
||||
private val searchScope: SearchScope,
|
||||
private val consumer: Processor<PsiReference>,
|
||||
plainSearchHandler: (SearchScope) -> Unit,
|
||||
@@ -248,17 +257,8 @@ private class Processor(
|
||||
when (kind) {
|
||||
CallableToProcessKind.HAS_DATA_CLASS_TYPE -> {
|
||||
if (reference is KtDestructuringDeclarationReference) {
|
||||
// declaration usage in form of destructuring declaration
|
||||
val entries = reference.element.entries
|
||||
val componentIndex = when (declaration) {
|
||||
is KtParameter -> declaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) }
|
||||
is KtFunction -> declaration.name?.let { getComponentIndex(it) }
|
||||
//TODO: java component functions (see KT-13605)
|
||||
else -> null
|
||||
}
|
||||
if (componentIndex != null && componentIndex <= entries.size) {
|
||||
addCallableDeclarationToProcess(entries[componentIndex - 1], CallableToProcessKind.HAS_DATA_CLASS_TYPE)
|
||||
}
|
||||
// declaration usage in form of destructuring declaration entry
|
||||
addCallableDeclarationToProcess(reference.element, CallableToProcessKind.HAS_DATA_CLASS_TYPE)
|
||||
}
|
||||
else {
|
||||
(reference.element as? KtReferenceExpression)?.let { processSuspiciousExpression(it) }
|
||||
@@ -552,10 +552,10 @@ private class Processor(
|
||||
*/
|
||||
private fun processSuspiciousDeclaration(declaration: KtDeclaration) {
|
||||
if (declaration is KtDestructuringDeclaration) {
|
||||
if (searchScope.contains(declaration)) {
|
||||
if (searchScope.contains(declaration) && componentIndex <= declaration.entries.size) {
|
||||
testLog?.add("Checked type of ${declaration.logPresentation()}")
|
||||
|
||||
val declarationReference = declaration.references.firstIsInstance<KtDestructuringDeclarationReference>()
|
||||
val declarationReference = declaration.entries[componentIndex - 1].references.firstIsInstance<KtDestructuringDeclarationReference>()
|
||||
if (declarationReference.isReferenceTo(target)) {
|
||||
consumer.process(declarationReference)
|
||||
}
|
||||
|
||||
+2
-2
@@ -293,8 +293,8 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
|
||||
if (isDataClass) {
|
||||
(functionPsi as KtPrimaryConstructor).valueParameters.firstOrNull()?.let {
|
||||
ReferencesSearch.search(it).mapNotNullTo(result) {
|
||||
val destructuringDeclaration = it.element as? KtDestructuringDeclaration ?: return@mapNotNullTo null
|
||||
KotlinComponentUsageInDestructuring(destructuringDeclaration)
|
||||
val destructuringEntry = it.element as? KtDestructuringDeclarationEntry ?: return@mapNotNullTo null
|
||||
KotlinComponentUsageInDestructuring(destructuringEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -24,21 +24,23 @@ import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator.Target
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.buildDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
|
||||
class KotlinComponentUsageInDestructuring(element: KtDestructuringDeclaration) : KotlinUsageInfo<KtDestructuringDeclaration>(element) {
|
||||
override fun processUsage(changeInfo: KotlinChangeInfo, element: KtDestructuringDeclaration, allUsages: Array<out UsageInfo>): Boolean {
|
||||
class KotlinComponentUsageInDestructuring(element: KtDestructuringDeclarationEntry) : KotlinUsageInfo<KtDestructuringDeclarationEntry>(element) {
|
||||
override fun processUsage(changeInfo: KotlinChangeInfo, element: KtDestructuringDeclarationEntry, allUsages: Array<out UsageInfo>): Boolean {
|
||||
if (!changeInfo.isParameterSetOrOrderChanged) return true
|
||||
|
||||
val currentEntries = element.entries
|
||||
val declaration = element.parent as KtDestructuringDeclaration
|
||||
val currentEntries = declaration.entries
|
||||
val newParameterInfos = changeInfo.getNonReceiverParameters()
|
||||
|
||||
val newDestructuring = KtPsiFactory(element).buildDestructuringDeclaration {
|
||||
val lastIndex = newParameterInfos.indexOfLast { it.oldIndex in currentEntries.indices }
|
||||
val nameValidator = CollectingNameValidator(filter = NewDeclarationNameValidator(element.parent, null, Target.VARIABLES))
|
||||
val nameValidator = CollectingNameValidator(filter = NewDeclarationNameValidator(declaration.parent, null, Target.VARIABLES))
|
||||
|
||||
appendFixedText("val (")
|
||||
for (i in 0..lastIndex) {
|
||||
@@ -58,7 +60,7 @@ class KotlinComponentUsageInDestructuring(element: KtDestructuringDeclaration) :
|
||||
appendFixedText(")")
|
||||
}
|
||||
replaceListPsiAndKeepDelimiters(
|
||||
element,
|
||||
declaration,
|
||||
newDestructuring,
|
||||
{
|
||||
apply {
|
||||
|
||||
+10
-1
@@ -17,9 +17,12 @@
|
||||
package org.jetbrains.kotlin.idea.search.ideaExtensions
|
||||
|
||||
import com.intellij.codeInsight.TargetElementEvaluatorEx
|
||||
import com.intellij.codeInsight.TargetElementUtil
|
||||
import com.intellij.codeInsight.TargetElementUtilExtender
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
@@ -28,7 +31,13 @@ import org.jetbrains.kotlin.psi.psiUtil.isAbstract
|
||||
class KotlinTargetElementEvaluator : TargetElementEvaluatorEx {
|
||||
override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is KtClass && element.isAbstract())
|
||||
|
||||
override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? = null
|
||||
override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? {
|
||||
// prefer destructing declaration entry to its target if element name is accepted
|
||||
if (ref is KtDestructuringDeclarationReference && flags.and(TargetElementUtil.ELEMENT_NAME_ACCEPTED) != 0) {
|
||||
return ref.element
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
|
||||
// '(' is considered identifier part if it belongs to primary constructor without 'constructor' keyword
|
||||
|
||||
@@ -6,8 +6,5 @@ fun <Int> f(l: List<Int>) {
|
||||
val (e<caret>l1, el2, el3) = l
|
||||
}
|
||||
|
||||
// MULTIRESOLVE
|
||||
// REF: (for kotlin.collections.List<T> in dependency).component1()
|
||||
// REF: (for kotlin.collections.List<T> in dependency).component2()
|
||||
// REF: (for kotlin.collections.List<T> in dependency).component3()
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ fun A.component1() = 1
|
||||
fun A.component2() = 1
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val (a,<caret> b) = A()
|
||||
val (a, <caret>b) = A()
|
||||
}
|
||||
|
||||
// MULTIRESOLVE
|
||||
// REF: (for A in a).component1()
|
||||
// REF: (for A in a).component2()
|
||||
|
||||
@@ -7,9 +7,7 @@ class MyPair {
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val p = MyPair()
|
||||
val (a, b<caret>) = p
|
||||
val (a, <caret>b) = p
|
||||
}
|
||||
|
||||
// MULTIRESOLVE
|
||||
// REF: (in a.MyPair).component1()
|
||||
// REF: (in a.MyPair).component2()
|
||||
Reference in New Issue
Block a user