diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt index 165d7302b4f..1ea0beec247 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt @@ -18,12 +18,13 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass -import org.jetbrains.kotlin.psi.psiUtil.findFunctionByName -import org.jetbrains.kotlin.psi.psiUtil.findPropertyByName import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.scopes.utils.findFunction import org.jetbrains.kotlin.resolve.scopes.utils.findVariable @@ -46,24 +47,25 @@ class RedundantCompanionReferenceInspection : AbstractKotlinInspection() { when (selectorDescriptor) { is PropertyDescriptor -> { val name = selectorDescriptor.name - if (containingClass.findPropertyByName(name.asString()) != null) return + if (containingClassDescriptor.findMemberVariable(name.asString()) != null) return val variable = expression.getResolutionScope().findVariable(name, NoLookupLocation.FROM_IDE) if (variable != null && variable.isLocalOrExtension(containingClassDescriptor)) return } is FunctionDescriptor -> { val name = selectorDescriptor.name - val function = containingClass.findFunctionByName(name.asString())?.descriptor - ?: expression.getResolutionScope().findFunction(name, NoLookupLocation.FROM_IDE)?.takeIf { + val functions = containingClassDescriptor.collectMemberFunction(name.asString()) + listOfNotNull( + expression.getResolutionScope().findFunction(name, NoLookupLocation.FROM_IDE)?.takeIf { it.isLocalOrExtension(containingClassDescriptor) } - if (function is FunctionDescriptor) { - val functionParams = function.valueParameters - val calleeParams = - (selectorExpression as? KtCallExpression)?.calleeExpression?.getCallableDescriptor()?.valueParameters.orEmpty() - if (functionParams.size == calleeParams.size && - functionParams.zip(calleeParams).all { it.first.type == it.second.type } - ) return - } + ) + if (functions.any { + val functionParams = it.valueParameters + val calleeParams = (selectorExpression as? KtCallExpression)?.calleeExpression?.getCallableDescriptor() + ?.valueParameters.orEmpty() + functionParams.size == calleeParams.size && functionParams.zip(calleeParams).all { param -> + param.first.type == param.second.type + } + }) return } } @@ -83,6 +85,32 @@ class RedundantCompanionReferenceInspection : AbstractKotlinInspection() { } } +private fun ClassDescriptor.findMemberVariable(name: String): PropertyDescriptor? { + val variable = unsubstitutedMemberScope.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_IDE).firstOrNull() + if (variable != null) return variable + + val variableInSuperClass = getSuperClassNotAny()?.findMemberVariable(name) + if (variableInSuperClass != null) return variableInSuperClass + + getSuperInterfaces().forEach { + val variableInInterface = it.findMemberVariable(name) + if (variableInInterface != null) return variableInInterface + } + + return null +} + +private fun ClassDescriptor.collectMemberFunction(name: String): MutableList { + val functions = mutableListOf() + fun collect(descriptor: ClassDescriptor) { + functions.addAll(descriptor.unsubstitutedMemberScope.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_IDE)) + descriptor.getSuperClassNotAny()?.let { collect(it) } + descriptor.getSuperInterfaces().forEach { collect(it) } + } + collect(this) + return functions +} + private fun CallableDescriptor.isLocalOrExtension(extensionClassDescriptor: ClassDescriptor): Boolean { return visibility == Visibilities.LOCAL || extensionReceiverParameter?.type?.constructor?.declarationDescriptor == extensionClassDescriptor diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction.kt new file mode 100644 index 00000000000..a8a762717de --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction.kt @@ -0,0 +1,15 @@ +// PROBLEM: none + +open class B { + fun foo(x: Int) = "B$x" +} + +class C : B() { + fun test(): String { + return Companion.foo(1) + } + + companion object { + fun foo(x: Int) = "C$x" + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction2.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction2.kt new file mode 100644 index 00000000000..e95aabceb23 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction2.kt @@ -0,0 +1,18 @@ +// PROBLEM: none + +open class A { + fun foo(x: Int) = "A$x" +} + +open class B: A() { +} + +class C : B() { + fun test(): String { + return Companion.foo(1) + } + + companion object { + fun foo(x: Int) = "C$x" + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction3.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction3.kt new file mode 100644 index 00000000000..05c0b57b90a --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction3.kt @@ -0,0 +1,18 @@ +// PROBLEM: none + +interface A { + fun foo(x: Int) = "A$x" +} + +open class B { +} + +class C : B(), A { + fun test(): String { + return Companion.foo(1) + } + + companion object { + fun foo(x: Int) = "C$x" + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable.kt new file mode 100644 index 00000000000..c3852a101c4 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable.kt @@ -0,0 +1,15 @@ +// PROBLEM: none + +open class B { + val foo = "B" +} + +class C : B() { + fun test(): String { + return Companion.foo + } + + companion object { + val foo = "C" + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable2.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable2.kt new file mode 100644 index 00000000000..7d07ebbc814 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable2.kt @@ -0,0 +1,18 @@ +// PROBLEM: none + +open class A { + val foo = "A" +} + +open class B: A() { +} + +class C : B() { + fun test(): String { + return Companion.foo + } + + companion object { + val foo = "C" + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable3.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable3.kt new file mode 100644 index 00000000000..8a35c43a15c --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable3.kt @@ -0,0 +1,19 @@ +// PROBLEM: none + +interface A { + val foo: String + get() = "A" +} + +open class B { +} + +class C : B(), A { + fun test(): String { + return Companion.foo + } + + companion object { + val foo = "C" + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 6f620f2989e..2ae7908297f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -4083,6 +4083,36 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { public void testSameNameMemberVariable() throws Exception { runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt"); } + + @TestMetadata("sameNameSuperMemberFunction.kt") + public void testSameNameSuperMemberFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction.kt"); + } + + @TestMetadata("sameNameSuperMemberFunction2.kt") + public void testSameNameSuperMemberFunction2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction2.kt"); + } + + @TestMetadata("sameNameSuperMemberFunction3.kt") + public void testSameNameSuperMemberFunction3() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberFunction3.kt"); + } + + @TestMetadata("sameNameSuperMemberVariable.kt") + public void testSameNameSuperMemberVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable.kt"); + } + + @TestMetadata("sameNameSuperMemberVariable2.kt") + public void testSameNameSuperMemberVariable2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable2.kt"); + } + + @TestMetadata("sameNameSuperMemberVariable3.kt") + public void testSameNameSuperMemberVariable3() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameSuperMemberVariable3.kt"); + } } @TestMetadata("idea/testData/inspectionsLocal/redundantExplicitType")