From 646f325f5780de790dbd47645f90e2dca6778fd7 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Tue, 9 Apr 2019 20:12:36 +0700 Subject: [PATCH] Fix false positive "Redundant qualifier name" for functions with a receiver #KT-30879 Fixed --- .../RemoveRedundantQualifierNameInspection.kt | 15 ++++++++++----- .../removeRedundantQualifierName/asReceiver.kt | 15 +++++++++++++++ .../asReceiver.kt.after | 15 +++++++++++++++ .../notApplicableAsReceiver.kt | 16 ++++++++++++++++ .../LocalInspectionTestGenerated.java | 10 ++++++++++ 5 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt create mode 100644 idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt.after create mode 100644 idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableAsReceiver.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt index cd13d9b372c..931fe885310 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt @@ -30,14 +30,15 @@ class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), Clean object : KtVisitorVoid() { override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) { if (expression.parent is KtDotQualifiedExpression? || expression.isInImportDirective()) return + val expressionForAnalyze = expression.firstExpressionWithoutReceiver() ?: return - val context = expression.analyze() - val importableFqName = expression.getQualifiedElementSelector() - ?.getResolvedCall(context)?.resultingDescriptor + val context = expressionForAnalyze.analyze() + val importableFqName = expressionForAnalyze.getQualifiedElementSelector() + ?.mainReference?.resolveToDescriptors(context)?.firstOrNull() ?.importableFqName ?: return - val applicableExpression = expression.firstApplicableExpression(validator = { - applicableExpression(expression, context, importableFqName) + val applicableExpression = expressionForAnalyze.firstApplicableExpression(validator = { + applicableExpression(expressionForAnalyze, context, importableFqName) }) { firstChild as? KtDotQualifiedExpression } ?: return @@ -57,6 +58,10 @@ class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), Clean } } +private tailrec fun KtDotQualifiedExpression.firstExpressionWithoutReceiver(): KtDotQualifiedExpression? = + if ((getQualifiedElementSelector()?.mainReference?.resolve() as? KtFunction)?.receiverTypeReference == null) this + else (receiverExpression as? KtDotQualifiedExpression)?.firstExpressionWithoutReceiver() + private tailrec fun T.firstApplicableExpression(validator: T.() -> T?, generator: T.() -> T?): T? = validator() ?: generator()?.firstApplicableExpression(validator, generator) diff --git a/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt b/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt new file mode 100644 index 00000000000..bedf0e5dbf2 --- /dev/null +++ b/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt @@ -0,0 +1,15 @@ +// WITH_RUNTIME + +import B.G + +fun test() { + B.G.let { it } +} + +class B { + object G +} + +class C { + object G +} diff --git a/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt.after b/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt.after new file mode 100644 index 00000000000..b2c2388963f --- /dev/null +++ b/idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt.after @@ -0,0 +1,15 @@ +// WITH_RUNTIME + +import B.G + +fun test() { + G.let { it } +} + +class B { + object G +} + +class C { + object G +} diff --git a/idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableAsReceiver.kt b/idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableAsReceiver.kt new file mode 100644 index 00000000000..a196c943480 --- /dev/null +++ b/idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableAsReceiver.kt @@ -0,0 +1,16 @@ +// PROBLEM: none +// WITH_RUNTIME + +import C.G + +fun test() { + B.G.let { it } +} + +class B { + object G +} + +class C { + object G +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 1be95b90d3e..baa55dfd5e4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -6230,6 +6230,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/removeRedundantQualifierName"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } + @TestMetadata("asReceiver.kt") + public void testAsReceiver() throws Exception { + runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiver.kt"); + } + @TestMetadata("companionCollision.kt") public void testCompanionCollision() throws Exception { runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/companionCollision.kt"); @@ -6350,6 +6355,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/localFun2.kt"); } + @TestMetadata("notApplicableAsReceiver.kt") + public void testNotApplicableAsReceiver() throws Exception { + runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableAsReceiver.kt"); + } + @TestMetadata("notApplicableCollisionTopLevelClass.kt") public void testNotApplicableCollisionTopLevelClass() throws Exception { runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableCollisionTopLevelClass.kt");