From cc70ea2586ef81cfc562d4bbb5530255f3da6483 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 15 Jun 2015 20:25:35 +0300 Subject: [PATCH] KT-7883 Receiver parameter falsely marked as unused #KT-7883 fixed --- .../kotlin/idea/util/extensionsUtils.kt | 24 +++++++++++++++---- .../KotlinRecursiveCallLineMarkerProvider.kt | 13 +++------- .../UnusedReceiverParameterInspection.kt | 14 +++++++---- .../invokeConvention.kt | 5 ++++ 4 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 idea/testData/inspections/unusedReceiverParameter/invokeConvention.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt index ab57b8fb442..cbf06d82779 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt @@ -17,13 +17,17 @@ package org.jetbrains.kotlin.idea.util import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.psi.JetPsiUtil +import org.jetbrains.kotlin.psi.JetThisExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.resolve.scopes.JetScope -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver public enum class CallType { NORMAL, @@ -102,3 +106,15 @@ public fun CallableDescriptor.substituteExtensionIfCallable( } } +public fun ReceiverValue.getThisReceiverOwner(bindingContext: BindingContext): DeclarationDescriptor? { + return when (this) { + is ExpressionReceiver -> { + val thisRef = (JetPsiUtil.deparenthesize(this.getExpression()) as? JetThisExpression)?.getInstanceReference() ?: return null + bindingContext[BindingContext.REFERENCE_TARGET, thisRef] + } + + is ThisReceiver -> this.getDeclarationDescriptor() + + else -> null + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt index bdbd0010fd1..983ff0e76ef 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt @@ -27,6 +27,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.util.getThisReceiverOwner import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.resolve.BindingContext @@ -77,17 +78,9 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider { if (resolvedCall.getCandidateDescriptor().getOriginal() != enclosingFunctionDescriptor) return false fun isDifferentReceiver(receiver: ReceiverValue): Boolean { - val receiverOwner = - when (receiver) { - is ExpressionReceiver -> { - val thisRef = (JetPsiUtil.deparenthesize(receiver.getExpression()) as? - JetThisExpression)?.getInstanceReference() ?: return true - bindingContext[BindingContext.REFERENCE_TARGET, thisRef] ?: return true - } + if (receiver == ReceiverValue.NO_RECEIVER) return false - is ThisReceiver -> receiver.getDeclarationDescriptor() - else -> return false - } + val receiverOwner = receiver.getThisReceiverOwner(bindingContext) ?: return true return when (receiverOwner) { is SimpleFunctionDescriptor -> receiverOwner != enclosingFunctionDescriptor diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt index 1e126960518..3d2231f09a6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt @@ -19,16 +19,23 @@ package org.jetbrains.kotlin.idea.inspections import com.intellij.codeInspection.* import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.idea.JetBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor +import org.jetbrains.kotlin.idea.util.getThisReceiverOwner import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.isOverridable import org.jetbrains.kotlin.psi.typeRefHelpers.setReceiverTypeReference +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver import kotlin.properties.Delegates public class UnusedReceiverParameterInspection : AbstractKotlinInspection() { @@ -52,10 +59,9 @@ public class UnusedReceiverParameterInspection : AbstractKotlinInspection() { val bindingContext = element.analyze() val resolvedCall = element.getResolvedCall(bindingContext) ?: return - if ((resolvedCall.getDispatchReceiver() as? ExtensionReceiver)?.getDeclarationDescriptor() == callable) { - used = true - } - else if (((resolvedCall.getExtensionReceiver() as? ExtensionReceiver)?.getDeclarationDescriptor() == callable)) { + + if (resolvedCall.getDispatchReceiver().getThisReceiverOwner(bindingContext) == callable || + resolvedCall.getExtensionReceiver().getThisReceiverOwner(bindingContext) == callable) { used = true } else if ((resolvedCall.getCandidateDescriptor() as? ReceiverParameterDescriptor)?.getContainingDeclaration() == callable) { diff --git a/idea/testData/inspections/unusedReceiverParameter/invokeConvention.kt b/idea/testData/inspections/unusedReceiverParameter/invokeConvention.kt new file mode 100644 index 00000000000..55b34f996ab --- /dev/null +++ b/idea/testData/inspections/unusedReceiverParameter/invokeConvention.kt @@ -0,0 +1,5 @@ +// KT-7883 Receiver parameter falsely marked as unused + +fun (() -> Any).foo() { + this() +} \ No newline at end of file