diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt index b988153114e..509b1696754 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt @@ -30,24 +30,37 @@ import org.jetbrains.kotlin.resolve.BindingContext class ImplicitThisInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : KtVisitorVoid() { + + override fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression) { + if (expression.receiverExpression != null) return + + handle(expression, expression.callableReference, ::CallableReferenceFix) + } + override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { if (expression !is KtNameReferenceExpression) return if (expression.parent is KtThisExpression) return + if (expression.parent is KtCallableReferenceExpression) return if (expression.isSelectorOfDotQualifiedExpression()) return val parent = expression.parent if (parent is KtCallExpression && parent.isSelectorOfDotQualifiedExpression()) return - val context = expression.analyze() - val scope = expression.getResolutionScope(context) ?: return + handle(expression, expression, ::CallFix) + } - val descriptor = context[BindingContext.REFERENCE_TARGET, expression] as? CallableDescriptor ?: return + private fun handle(expression: KtExpression, reference: KtReferenceExpression, fixFactory: (String) -> LocalQuickFix) { + val context = reference.analyze() + val scope = reference.getResolutionScope(context) ?: return + + val descriptor = context[BindingContext.REFERENCE_TARGET, reference] as? CallableDescriptor ?: return val receiverDescriptor = descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter ?: return val receiverType = receiverDescriptor.type val expressionFactory = scope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType) ?: return val receiverText = if (expressionFactory.isImmediate) "this" else expressionFactory.expressionText - holder.registerProblem(expression, "Add explicit '$receiverText'", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, Fix(receiverText)) + val fix = fixFactory(receiverText) + holder.registerProblem(expression, "Add explicit '$receiverText'", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix) } private fun KtExpression.isSelectorOfDotQualifiedExpression(): Boolean { @@ -56,7 +69,7 @@ class ImplicitThisInspection : AbstractKotlinInspection() { } } - private class Fix(private val receiverText: String) : LocalQuickFix { + private class CallFix(private val receiverText: String) : LocalQuickFix { override fun getFamilyName() = "Add explicit '$receiverText'" override fun applyFix(project: Project, descriptor: ProblemDescriptor) { @@ -67,4 +80,16 @@ class ImplicitThisInspection : AbstractKotlinInspection() { call.replace(factory.createExpressionByPattern("$0.$1", receiverText, call)) } } + + private class CallableReferenceFix(private val receiverText: String) : LocalQuickFix { + override fun getFamilyName() = "Add explicit '$receiverText'" + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val expression = descriptor.psiElement as? KtCallableReferenceExpression ?: return + val factory = KtPsiFactory(project) + val reference = expression.callableReference + + expression.replace(factory.createExpressionByPattern("$0::$1", receiverText, reference)) + } + } } \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/functionReference.kt b/idea/testData/inspectionsLocal/implicitThis/functionReference.kt new file mode 100644 index 00000000000..f80cf407505 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/functionReference.kt @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + ::s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/functionReference.kt.after b/idea/testData/inspectionsLocal/implicitThis/functionReference.kt.after new file mode 100644 index 00000000000..d5e5199f4fb --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/functionReference.kt.after @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + this::s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt b/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt new file mode 100644 index 00000000000..b287819c655 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + ::s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt.after b/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt.after new file mode 100644 index 00000000000..ff1a6acaf71 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/propertyReference.kt.after @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + this::s + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index ee5e66cc76b..1f3d6f61137 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -767,6 +767,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { doTest(fileName); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/functionReference.kt"); + doTest(fileName); + } + @TestMetadata("multipleReceivers.kt") public void testMultipleReceivers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt"); @@ -797,6 +803,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { doTest(fileName); } + @TestMetadata("propertyReference.kt") + public void testPropertyReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/propertyReference.kt"); + doTest(fileName); + } + @TestMetadata("topLevel.kt") public void testTopLevel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/topLevel.kt");