From 5ad98a139d9070c40afa30f821c1a3c17d6b0649 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 6 Jun 2018 16:37:27 +0300 Subject: [PATCH] "Redundant Companion": Don't suggest if same callable name is in use So #KT-24425 Fixed --- .../RedundantCompanionReferenceInspection.kt | 48 +++++++++++++++++- .../sameNameDifferentArgsFunction.kt | 11 ++++ .../sameNameDifferentArgsFunction.kt.after | 11 ++++ .../sameNameExtensionFunction.kt | 13 +++++ .../sameNameExtensionVariable.kt | 14 ++++++ .../sameNameGlobalFunction.kt | 11 ++++ .../sameNameGlobalFunction.kt.after | 11 ++++ .../sameNameGlobalVariable.kt | 11 ++++ .../sameNameGlobalVariable.kt.after | 11 ++++ .../sameNameLocalFunction.kt | 13 +++++ .../sameNameLocalVariable.kt | 13 +++++ .../sameNameLocalVariable2.kt | 11 ++++ .../sameNameMemberFunction.kt | 13 +++++ .../sameNameMemberVariable.kt | 13 +++++ .../LocalInspectionTestGenerated.java | 50 +++++++++++++++++++ 15 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionFunction.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionVariable.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalFunction.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable2.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberFunction.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt index e291455075b..8a307591858 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt @@ -11,24 +11,59 @@ import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor 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.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass +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.scopes.utils.findFunction +import org.jetbrains.kotlin.resolve.scopes.utils.findVariable class RedundantCompanionReferenceInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { return referenceExpressionVisitor(fun(expression) { val parent = expression.parent as? KtDotQualifiedExpression ?: return - if (expression == parent.selectorExpression && parent.parent !is KtDotQualifiedExpression) return + val selectorExpression = parent.selectorExpression + if (expression == selectorExpression && parent.parent !is KtDotQualifiedExpression) return if (parent.getStrictParentOfType() != null) return val objectDeclaration = expression.mainReference.resolve() as? KtObjectDeclaration ?: return if (!objectDeclaration.isCompanion()) return if (expression.text != objectDeclaration.name) return + val containingClass = objectDeclaration.containingClass() ?: return + val selectorDescriptor = selectorExpression?.getCallableDescriptor() + when (selectorDescriptor) { + is PropertyDescriptor -> { + val name = selectorDescriptor.name + if (containingClass.findPropertyByName(name.asString()) != null) return + val variable = expression.getResolutionScope().findVariable(name, NoLookupLocation.FROM_IDE) + if (variable.isLocalOrExtension(containingClass)) return + } + is FunctionDescriptor -> { + val name = selectorDescriptor.name + val function = containingClass.findFunctionByName(name.asString())?.descriptor + ?: expression.getResolutionScope().findFunction(name, NoLookupLocation.FROM_IDE)?.takeIf { + it.isLocalOrExtension(containingClass) + } + 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 + } + } + } + val grandParent = parent.parent as? KtQualifiedExpression if (grandParent != null) { val grandParentDescriptor = grandParent.resolveToCall()?.resultingDescriptor ?: return @@ -45,6 +80,15 @@ class RedundantCompanionReferenceInspection : AbstractKotlinInspection() { } } +private fun KtClass.findFunctionByName(name: String): KtDeclaration? { + return declarations.firstOrNull { it is KtNamedFunction && it.name == name } +} + +private fun CallableDescriptor?.isLocalOrExtension(extensionClass: KtClass): Boolean { + return this?.visibility == Visibilities.LOCAL + || this?.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == extensionClass.descriptor +} + private class RemoveRedundantCompanionReferenceFix : LocalQuickFix { override fun getName() = "Remove redundant Companion reference" diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt new file mode 100644 index 00000000000..66afe4550ef --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt @@ -0,0 +1,11 @@ +class Test { + companion object { + fun f(x: Int, y: Int) = 1 + } + + fun f(x: Int, y: String) = 2 + + fun test() { + Companion.f(1, 2) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt.after b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt.after new file mode 100644 index 00000000000..51212a26c4c --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt.after @@ -0,0 +1,11 @@ +class Test { + companion object { + fun f(x: Int, y: Int) = 1 + } + + fun f(x: Int, y: String) = 2 + + fun test() { + f(1, 2) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionFunction.kt new file mode 100644 index 00000000000..b836c92ea01 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionFunction.kt @@ -0,0 +1,13 @@ +// PROBLEM: none + +class Test { + companion object { + fun extentionFun() = 1 + } + + fun test() { + Companion.extentionFun() + } +} + +fun Test.extentionFun() = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionVariable.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionVariable.kt new file mode 100644 index 00000000000..20776456ba8 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionVariable.kt @@ -0,0 +1,14 @@ +// PROBLEM: none + +class Test { + companion object { + val extentionVar = 1 + } + + fun test() { + Companion.extentionVar + } +} + +val Test.extentionVar: Int + get() = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt new file mode 100644 index 00000000000..8b40e446ab1 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt @@ -0,0 +1,11 @@ +class Test { + companion object { + fun globalFun() = 1 + } + + fun test() { + Companion.globalFun() + } +} + +fun globalFun() = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt.after b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt.after new file mode 100644 index 00000000000..f92fe2fe9db --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt.after @@ -0,0 +1,11 @@ +class Test { + companion object { + fun globalFun() = 1 + } + + fun test() { + globalFun() + } +} + +fun globalFun() = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt new file mode 100644 index 00000000000..9b1ac68bd0d --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt @@ -0,0 +1,11 @@ +class Test { + companion object { + val globalVar = 1 + } + + fun test() { + Companion.globalVar + } +} + +val globalVar = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt.after b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt.after new file mode 100644 index 00000000000..d1c1213284e --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt.after @@ -0,0 +1,11 @@ +class Test { + companion object { + val globalVar = 1 + } + + fun test() { + globalVar + } +} + +val globalVar = 2 \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalFunction.kt new file mode 100644 index 00000000000..4fa0d021145 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalFunction.kt @@ -0,0 +1,13 @@ +// PROBLEM: none + +class Test { + companion object { + fun localFun() = 1 + } + + fun test() { + fun localFun() = 2 + + Companion.localFun() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable.kt new file mode 100644 index 00000000000..b850508a310 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable.kt @@ -0,0 +1,13 @@ +// PROBLEM: none + +class Test { + companion object { + val localVar = 1 + } + + fun test() { + var localVar = 2 + + Companion.localVar + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable2.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable2.kt new file mode 100644 index 00000000000..e788708237f --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable2.kt @@ -0,0 +1,11 @@ +// PROBLEM: none + +class Test { + companion object { + val localVar = 1 + } + + fun test(localVar: Int) { + Companion.localVar + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberFunction.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberFunction.kt new file mode 100644 index 00000000000..d91daaa2fda --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberFunction.kt @@ -0,0 +1,13 @@ +// PROBLEM: none + +class Test { + companion object { + fun memberFun(x: Int) = 1 + } + + fun memberFun(x: Int) = 2 + + fun test() { + Companion.memberFun(0) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt new file mode 100644 index 00000000000..6f031ecf84e --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt @@ -0,0 +1,13 @@ +// PROBLEM: none + +class Test { + companion object { + val memberVar = 1 + } + + val memberVar = 2 + + fun test() { + Companion.memberVar + } +} \ 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 df27eb3eeb3..88ea97f6000 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -3024,6 +3024,56 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { public void testOnlyCompanion() throws Exception { runTest("idea/testData/inspectionsLocal/redundantCompanionReference/onlyCompanion.kt"); } + + @TestMetadata("sameNameDifferentArgsFunction.kt") + public void testSameNameDifferentArgsFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameDifferentArgsFunction.kt"); + } + + @TestMetadata("sameNameExtensionFunction.kt") + public void testSameNameExtensionFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionFunction.kt"); + } + + @TestMetadata("sameNameExtensionVariable.kt") + public void testSameNameExtensionVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameExtensionVariable.kt"); + } + + @TestMetadata("sameNameGlobalFunction.kt") + public void testSameNameGlobalFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalFunction.kt"); + } + + @TestMetadata("sameNameGlobalVariable.kt") + public void testSameNameGlobalVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameGlobalVariable.kt"); + } + + @TestMetadata("sameNameLocalFunction.kt") + public void testSameNameLocalFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalFunction.kt"); + } + + @TestMetadata("sameNameLocalVariable.kt") + public void testSameNameLocalVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable.kt"); + } + + @TestMetadata("sameNameLocalVariable2.kt") + public void testSameNameLocalVariable2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameLocalVariable2.kt"); + } + + @TestMetadata("sameNameMemberFunction.kt") + public void testSameNameMemberFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberFunction.kt"); + } + + @TestMetadata("sameNameMemberVariable.kt") + public void testSameNameMemberVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/sameNameMemberVariable.kt"); + } } @TestMetadata("idea/testData/inspectionsLocal/redundantExplicitType")