diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt index df2235c208c7..2ce7fdee4424 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt @@ -10,12 +10,15 @@ import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor import org.jetbrains.kotlin.idea.util.getFactoryForImplicitReceiverWithSubtypeOf import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall class ImplicitThisInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : KtVisitorVoid() { @@ -41,10 +44,10 @@ class ImplicitThisInspection : AbstractKotlinInspection() { val context = reference.analyze() val scope = reference.getResolutionScope(context) ?: return - val descriptor = reference.getCallableDescriptor() ?: return - val receiverDescriptor = descriptor.extensionReceiverParameter - ?: descriptor.dispatchReceiverParameter - ?: return + val resolvedCall = reference.getResolvedCall(context) ?: return + val variableDescriptor = (resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor + val callableDescriptor = resolvedCall.resultingDescriptor + val receiverDescriptor = variableDescriptor?.receiverDescriptor() ?: callableDescriptor.receiverDescriptor() ?: return val receiverType = receiverDescriptor.type val expressionFactory = scope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType) ?: return @@ -59,6 +62,10 @@ class ImplicitThisInspection : AbstractKotlinInspection() { ) } + private fun CallableDescriptor.receiverDescriptor(): ReceiverParameterDescriptor? { + return extensionReceiverParameter ?: dispatchReceiverParameter + } + private fun KtExpression.isSelectorOfDotQualifiedExpression(): Boolean { val parent = parent return parent is KtDotQualifiedExpression && parent.selectorExpression == this diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 47da352cf96c..0dc7ea3e3a16 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -4885,6 +4885,16 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti runTest("testData/inspectionsLocal/implicitThis/already.kt"); } + @TestMetadata("callVariableAsFunction.kt") + public void testCallVariableAsFunction() throws Exception { + runTest("testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt"); + } + + @TestMetadata("callVariableAsFunction2.kt") + public void testCallVariableAsFunction2() throws Exception { + runTest("testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt"); + } + @TestMetadata("function.kt") public void testFunction() throws Exception { runTest("testData/inspectionsLocal/implicitThis/function.kt"); diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt new file mode 100644 index 000000000000..4d7a41b102af --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt @@ -0,0 +1,11 @@ +class Foo { + operator fun invoke() {} +} + +class Bar { + val foo = Foo() +} + +fun Bar.test() { + foo() +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt.after new file mode 100644 index 000000000000..e47a9b0f4b6d --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction.kt.after @@ -0,0 +1,11 @@ +class Foo { + operator fun invoke() {} +} + +class Bar { + val foo = Foo() +} + +fun Bar.test() { + this.foo() +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt new file mode 100644 index 000000000000..5981d67682ff --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt @@ -0,0 +1,7 @@ +class Bar { + val bar: () -> Unit = {} +} + +fun Bar.test() { + bar() +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt.after new file mode 100644 index 000000000000..45a5bfe2c069 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/implicitThis/callVariableAsFunction2.kt.after @@ -0,0 +1,7 @@ +class Bar { + val bar: () -> Unit = {} +} + +fun Bar.test() { + this.bar() +}