From 0ec18b4a33ae49170bffbac67cf9032d1de6abc7 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 10 Jul 2019 13:44:05 +0900 Subject: [PATCH] Explicit this inspection: fix false negative with local variable #KT-30136 Fixed --- .../inspections/ExplicitThisInspection.kt | 19 ++++++++++++++++++- .../functionWithSameNameInvocableVariable.kt | 14 ++++++++++++++ .../functionWithSameNameVariable.kt | 9 +++++++++ .../functionWithSameNameVariable.kt.after | 9 +++++++++ .../variableWithSameNameFunction.kt | 9 +++++++++ .../variableWithSameNameFunction.kt.after | 9 +++++++++ .../LocalInspectionTestGenerated.java | 15 +++++++++++++++ 7 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 idea/testData/inspectionsLocal/explicitThis/functionWithSameNameInvocableVariable.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt index 1b7c440b8d6..5d567433b4c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt @@ -22,13 +22,18 @@ import com.intellij.codeInspection.ProblemHighlightType.LIKE_UNUSED_SYMBOL import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project import org.jetbrains.kotlin.config.LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf @@ -60,7 +65,14 @@ class ExplicitThisInspection : AbstractKotlinInspection() { //we avoid overload-related problems by enforcing that there is only one candidate val name = referenceExpression.getReferencedNameAsName() - val candidates = scope.getAllAccessibleVariables(name) + scope.getAllAccessibleFunctions(name) + val candidates = if (reference is KtCallExpression + || (expression is KtCallableReferenceExpression && reference.mainReference.resolve() is KtFunction) + ) { + scope.getAllAccessibleFunctions(name) + + scope.getAllAccessibleVariables(name).filter { it is LocalVariableDescriptor && it.canInvoke() } + } else { + scope.getAllAccessibleVariables(name) + } if (referenceExpression.getCallableDescriptor() is SyntheticJavaPropertyDescriptor) { if (candidates.map { it.containingDeclaration }.distinct().size != 1) return } else { @@ -76,6 +88,11 @@ class ExplicitThisInspection : AbstractKotlinInspection() { holder.registerProblem(thisExpression, "Redundant explicit this", LIKE_UNUSED_SYMBOL, Fix(thisExpression.text)) } + + private fun VariableDescriptor.canInvoke(): Boolean { + val declarationDescriptor = this.type.constructor.declarationDescriptor as? LazyClassDescriptor ?: return false + return declarationDescriptor.declaredCallableMembers.any { (it as? FunctionDescriptor)?.isOperator == true } + } private fun ReceiverExpressionFactory.matchesLabel(label: String): Boolean { val implicitLabel = expressionText.substringAfter("@", "") diff --git a/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameInvocableVariable.kt b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameInvocableVariable.kt new file mode 100644 index 00000000000..983a2bef2cd --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameInvocableVariable.kt @@ -0,0 +1,14 @@ +// PROBLEM: none +class Some { + operator fun invoke() {} +} + +class Other { + fun foo() { + val a = Some() + this.a() + a() + } + + fun a() {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt new file mode 100644 index 00000000000..9cad9da3c28 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt @@ -0,0 +1,9 @@ +class Foo { + fun foo() { + val a = 1 + this.a() + } + + fun a() { + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt.after b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt.after new file mode 100644 index 00000000000..43586d12f1d --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt.after @@ -0,0 +1,9 @@ +class Foo { + fun foo() { + val a = 1 + a() + } + + fun a() { + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt b/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt new file mode 100644 index 00000000000..0a557744eef --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt @@ -0,0 +1,9 @@ +class Foo { + fun foo() { + fun a() { + } + this.a + } + + val a = 1 +} diff --git a/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt.after b/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt.after new file mode 100644 index 00000000000..df84d1bbe37 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt.after @@ -0,0 +1,9 @@ +class Foo { + fun foo() { + fun a() { + } + a + } + + val a = 1 +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 574710ca1b9..0f610050f18 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -4196,6 +4196,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/explicitThis/functionReference.kt"); } + @TestMetadata("functionWithSameNameInvocableVariable.kt") + public void testFunctionWithSameNameInvocableVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/functionWithSameNameInvocableVariable.kt"); + } + + @TestMetadata("functionWithSameNameVariable.kt") + public void testFunctionWithSameNameVariable() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/functionWithSameNameVariable.kt"); + } + @TestMetadata("multipleReceivers.kt") public void testMultipleReceivers() throws Exception { runTest("idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt"); @@ -4265,6 +4275,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { public void testVariableWithSameName() throws Exception { runTest("idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt"); } + + @TestMetadata("variableWithSameNameFunction.kt") + public void testVariableWithSameNameFunction() throws Exception { + runTest("idea/testData/inspectionsLocal/explicitThis/variableWithSameNameFunction.kt"); + } } @TestMetadata("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis")