Redundant companion reference: don't report in case of name conflicts

#KT-27539 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-10-14 23:32:26 +03:00
committed by Mikhail Glukhikh
parent 6e27d7a2a5
commit 1db7a0e0cc
8 changed files with 174 additions and 13 deletions
@@ -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<FunctionDescriptor> {
val functions = mutableListOf<FunctionDescriptor>()
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
@@ -0,0 +1,15 @@
// PROBLEM: none
open class B {
fun foo(x: Int) = "B$x"
}
class C : B() {
fun test(): String {
return <caret>Companion.foo(1)
}
companion object {
fun foo(x: Int) = "C$x"
}
}
@@ -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 <caret>Companion.foo(1)
}
companion object {
fun foo(x: Int) = "C$x"
}
}
@@ -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 <caret>Companion.foo(1)
}
companion object {
fun foo(x: Int) = "C$x"
}
}
@@ -0,0 +1,15 @@
// PROBLEM: none
open class B {
val foo = "B"
}
class C : B() {
fun test(): String {
return <caret>Companion.foo
}
companion object {
val foo = "C"
}
}
@@ -0,0 +1,18 @@
// PROBLEM: none
open class A {
val foo = "A"
}
open class B: A() {
}
class C : B() {
fun test(): String {
return <caret>Companion.foo
}
companion object {
val foo = "C"
}
}
@@ -0,0 +1,19 @@
// PROBLEM: none
interface A {
val foo: String
get() = "A"
}
open class B {
}
class C : B(), A {
fun test(): String {
return <caret>Companion.foo
}
companion object {
val foo = "C"
}
}
@@ -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")