diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt index e16419a7547..1b7c440b8d6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf class ExplicitThisInspection : AbstractKotlinInspection() { @@ -55,6 +56,7 @@ class ExplicitThisInspection : AbstractKotlinInspection() { val scope = expression.getResolutionScope(context) ?: return val referenceExpression = reference as? KtNameReferenceExpression ?: reference.getChildOfType() ?: return + val receiverType = context[BindingContext.EXPRESSION_TYPE_INFO, thisExpression]?.type ?: return //we avoid overload-related problems by enforcing that there is only one candidate val name = referenceExpression.getReferencedNameAsName() @@ -62,10 +64,11 @@ class ExplicitThisInspection : AbstractKotlinInspection() { if (referenceExpression.getCallableDescriptor() is SyntheticJavaPropertyDescriptor) { if (candidates.map { it.containingDeclaration }.distinct().size != 1) return } else { - if (candidates.size != 1) return + val candidate = candidates.singleOrNull() ?: return + val extensionType = candidate.extensionReceiverParameter?.type + if (extensionType != null && extensionType != receiverType && receiverType.isSubtypeOf(extensionType)) return } - val receiverType = context[BindingContext.EXPRESSION_TYPE_INFO, thisExpression]?.type ?: return val expressionFactory = scope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType) ?: return val label = thisExpression.getLabelName() ?: "" @@ -85,9 +88,7 @@ class ExplicitThisInspection : AbstractKotlinInspection() { override fun applyFix(project: Project, descriptor: ProblemDescriptor) { val thisExpression = descriptor.psiElement as? KtThisExpression ?: return - val parent = thisExpression.parent - - when (parent) { + when (val parent = thisExpression.parent) { is KtDotQualifiedExpression -> parent.replace(parent.selectorExpression ?: return) is KtCallableReferenceExpression -> thisExpression.delete() } diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension2.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension2.kt new file mode 100644 index 00000000000..f06087548ba --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension2.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// PROBLEM: none + +open class Foo + +class SubFoo : Foo() + +val Foo.bar: String get() = "" + +fun Foo.func() = Foo().apply { + this@func.bar +} diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension3.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension3.kt new file mode 100644 index 00000000000..b4f9d068ee3 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension3.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// PROBLEM: none + +open class Foo + +class SubFoo : Foo() + +val Foo.bar: String get() = "" + +fun SubFoo.func() = Foo().apply { + this@func.bar +} diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt new file mode 100644 index 00000000000..b3055caf7ef --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +open class Foo + +class SubFoo : Foo() + +val SubFoo.bar: String get() = "" + +fun SubFoo.func() = Foo().apply { + this@func.bar +} diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt.after b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt.after new file mode 100644 index 00000000000..0c980ff5c82 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +open class Foo + +class SubFoo : Foo() + +val SubFoo.bar: String get() = "" + +fun SubFoo.func() = Foo().apply { + bar +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 13b7964ae42..4b8b0da62a0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -3758,6 +3758,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt"); } + @TestMetadata("differentReceiverInstanceExtension2.kt") + public void testDifferentReceiverInstanceExtension2() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension2.kt"); + } + + @TestMetadata("differentReceiverInstanceExtension3.kt") + public void testDifferentReceiverInstanceExtension3() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension3.kt"); + } + + @TestMetadata("differentReceiverInstanceExtension4.kt") + public void testDifferentReceiverInstanceExtension4() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension4.kt"); + } + @TestMetadata("differentReceiverType.kt") public void testDifferentReceiverType() throws Exception { runTest("idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt");