From bbb571260b2b3d991528f36de6f3fb87091346fa Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Mon, 2 Oct 2017 10:32:07 +0300 Subject: [PATCH] Fix 'Redundant override' when delegated member hides super type override So #KT-20231 Fixed --- .../KotlinRedundantOverrideInspection.kt | 30 ++++++++++++++++++- .../delegatedMemberHidesSuperTypeOverride.kt | 14 +++++++++ .../delegatedMemberHidesSuperTypeOverride2.kt | 18 +++++++++++ .../delegatedMemberHidesSuperTypeOverride3.kt | 13 ++++++++ ...atedMemberHidesSuperTypeOverride3.kt.after | 12 ++++++++ .../delegatedMemberHidesSuperTypeOverride4.kt | 13 ++++++++ ...atedMemberHidesSuperTypeOverride4.kt.after | 12 ++++++++ .../LocalInspectionTestGenerated.java | 24 +++++++++++++++ 8 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt create mode 100644 idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinRedundantOverrideInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinRedundantOverrideInspection.kt index 6594dc206f8..a339d3a41ae 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinRedundantOverrideInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinRedundantOverrideInspection.kt @@ -19,11 +19,17 @@ package org.jetbrains.kotlin.idea.inspections import com.intellij.codeInspection.* import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange +import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = @@ -59,6 +65,7 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc val superCallElement = qualifiedExpression.selectorExpression as? KtCallElement ?: return if (!isSameFunctionName(superCallElement, function)) return if (!isSameArguments(superCallElement, function)) return + if (function.isDefinedInDelegatedSuperType(qualifiedExpression)) return val descriptor = holder.manager.createProblemDescriptor( function, @@ -98,4 +105,25 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc companion object { private val MODIFIER_EXCLUDE_OVERRIDE = KtTokens.MODIFIER_KEYWORDS_ARRAY.asList() - KtTokens.OVERRIDE_KEYWORD } -} \ No newline at end of file +} + +private fun KtNamedFunction.isDefinedInDelegatedSuperType(superQualifiedExpression: KtDotQualifiedExpression): Boolean { + val delegatedSuperTypeEntries = + containingClassOrObject?.superTypeListEntries?.filterIsInstance() ?: return false + if (delegatedSuperTypeEntries.isEmpty()) return false + + val context = superQualifiedExpression.analyze() + val delegatedSuperTypes = delegatedSuperTypeEntries.mapNotNull { entry -> + context[BindingContext.TYPE, entry.typeReference] + } + + val superResolvedCall = superQualifiedExpression.getResolvedCall(context) ?: return false + val superCallResolvedDescriptor = superResolvedCall.resultingDescriptor + val superCallResolvedReceiverTypes = superCallResolvedDescriptor.overriddenDescriptors.mapNotNull { it.dispatchReceiverParameter?.type } + + return delegatedSuperTypes.any { delegatedSuperType -> + superCallResolvedReceiverTypes.any { superCallReceiverType -> + delegatedSuperType.isSubtypeOf(superCallReceiverType) + } + } +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt new file mode 100644 index 00000000000..effb4c25663 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt @@ -0,0 +1,14 @@ +// PROBLEM: none +interface Foo { + fun test(arg: String) +} + +open class Bar : Foo { + override fun test(arg: String) {} + open fun test(a: Int) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { + override fun test(arg: String) = super.test(arg) +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt new file mode 100644 index 00000000000..862df905e5d --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt @@ -0,0 +1,18 @@ +// PROBLEM: none +interface A + +interface B { + fun test(arg: String) +} + +interface Foo : A, B + +open class Bar : Foo { + override fun test(arg: String) {} + open fun test(a: Int) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { + override fun test(arg: String) = super.test(arg) +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt new file mode 100644 index 00000000000..5f722ab20d2 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt @@ -0,0 +1,13 @@ +interface Foo { + fun test(arg: Int) +} + +open class Bar : Foo { + override fun test(arg: Int) {} + open fun test(a: String) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { + override fun test(a: String) = super.test(a) +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt.after b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt.after new file mode 100644 index 00000000000..7c9e2e328a2 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt.after @@ -0,0 +1,12 @@ +interface Foo { + fun test(arg: Int) +} + +open class Bar : Foo { + override fun test(arg: Int) {} + open fun test(a: String) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt new file mode 100644 index 00000000000..9c56894b804 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt @@ -0,0 +1,13 @@ +interface Foo { + fun test(arg: Int) +} + +open class Bar : Foo { + override fun test(arg: Int) {} + open fun test(a: String) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { + override fun test2(arg: Int) = super.test2(arg) +} diff --git a/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt.after b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt.after new file mode 100644 index 00000000000..7c9e2e328a2 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt.after @@ -0,0 +1,12 @@ +interface Foo { + fun test(arg: Int) +} + +open class Bar : Foo { + override fun test(arg: Int) {} + open fun test(a: String) {} + open fun test2() {} +} + +class Baz(val foo: Foo) : Bar(), Foo by foo { +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index f78b909e7b3..cb98ddb079c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1466,6 +1466,30 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { doTest(fileName); } + @TestMetadata("delegatedMemberHidesSuperTypeOverride.kt") + public void testDelegatedMemberHidesSuperTypeOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt"); + doTest(fileName); + } + + @TestMetadata("delegatedMemberHidesSuperTypeOverride2.kt") + public void testDelegatedMemberHidesSuperTypeOverride2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt"); + doTest(fileName); + } + + @TestMetadata("delegatedMemberHidesSuperTypeOverride3.kt") + public void testDelegatedMemberHidesSuperTypeOverride3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt"); + doTest(fileName); + } + + @TestMetadata("delegatedMemberHidesSuperTypeOverride4.kt") + public void testDelegatedMemberHidesSuperTypeOverride4() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt"); + doTest(fileName); + } + @TestMetadata("notCallSuper.kt") public void testNotCallSuper() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/notCallSuper.kt");