diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt index 9d0b1cb17ef..4bc6f40fad3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt @@ -19,9 +19,7 @@ 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.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor @@ -32,21 +30,19 @@ 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.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver -import kotlin.properties.Delegates public class UnusedReceiverParameterInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { return object : KtVisitorVoid() { private fun check(callableDeclaration: KtCallableDeclaration) { - val receiverTypeReference = callableDeclaration.getReceiverTypeReference() + val receiverTypeReference = callableDeclaration.receiverTypeReference if (receiverTypeReference == null || receiverTypeReference.textRange.isEmpty) return if (callableDeclaration.isOverridable() || callableDeclaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return - if (callableDeclaration is KtProperty && callableDeclaration.getAccessors().isEmpty()) return + if (callableDeclaration is KtProperty && callableDeclaration.accessors.isEmpty()) return if (callableDeclaration is KtNamedFunction && !callableDeclaration.hasBody()) return val callable = callableDeclaration.descriptor @@ -60,13 +56,25 @@ public class UnusedReceiverParameterInspection : AbstractKotlinInspection() { val bindingContext = element.analyze() val resolvedCall = element.getResolvedCall(bindingContext) ?: return - if (resolvedCall.getDispatchReceiver().getThisReceiverOwner(bindingContext) == callable || + if (isUsageOfReceiver(resolvedCall, bindingContext)) { + used = true + } else if (resolvedCall is VariableAsFunctionResolvedCall + && isUsageOfReceiver(resolvedCall.variableCall, bindingContext)) { + used = true + } + } + + private fun isUsageOfReceiver(resolvedCall: ResolvedCall<*>, bindingContext: BindingContext): Boolean { + // As receiver of call + if (resolvedCall.dispatchReceiver.getThisReceiverOwner(bindingContext) == callable || (resolvedCall.extensionReceiver as ReceiverValue?).getThisReceiverOwner(bindingContext) == callable) { - used = true + return true } - else if ((resolvedCall.getCandidateDescriptor() as? ReceiverParameterDescriptor)?.getContainingDeclaration() == callable) { - used = true + // As explicit "this" + if ((resolvedCall.candidateDescriptor as? ReceiverParameterDescriptor)?.containingDeclaration == callable) { + return true } + return false } }) @@ -99,6 +107,6 @@ public class UnusedReceiverParameterInspection : AbstractKotlinInspection() { declaration.setReceiverTypeReference(null) } - override fun getFamilyName(): String = getName() + override fun getFamilyName(): String = name } } diff --git a/idea/testData/inspections/unusedReceiverParameter/implicitReceiverOfInvokeConvention.kt b/idea/testData/inspections/unusedReceiverParameter/implicitReceiverOfInvokeConvention.kt new file mode 100644 index 00000000000..e796ee2b3bb --- /dev/null +++ b/idea/testData/inspections/unusedReceiverParameter/implicitReceiverOfInvokeConvention.kt @@ -0,0 +1,29 @@ +// KT-8365 Bogus "Receiver never used" warning +class FunctionLike { + fun invoke() {} +} + +class OwnerClass { + val functionLike = FunctionLike() + val function = { } +} + +val OwnerClass.extFunctionLike = FunctionLike() +val OwnerClass.extFunction = { } + + +fun OwnerClass.f1() { + functionLike() +} + +fun OwnerClass.f2() { + function() +} + +fun OwnerClass.f3() { + extFunctionLike() +} + +fun OwnerClass.f4() { + extFunction() +} \ No newline at end of file