diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/SetterBackingFieldAssignmentInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/SetterBackingFieldAssignmentInspection.kt index 052455990de..93328c68daa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/SetterBackingFieldAssignmentInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/SetterBackingFieldAssignmentInspection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,7 +10,6 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.lexer.KtTokens @@ -21,8 +20,8 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall class SetterBackingFieldAssignmentInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { - override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { - return propertyAccessorVisitor(fun(accessor) { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor = + propertyAccessorVisitor(fun(accessor) { if (!accessor.isSetter) return val bodyExpression = accessor.bodyBlockExpression ?: return @@ -31,24 +30,23 @@ class SetterBackingFieldAssignmentInspection : AbstractKotlinInspection(), Clean val propertyDescriptor = propertyContext[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? PropertyDescriptor ?: return if (propertyContext[BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor] == false) return - val accessorContext = accessor.analyze() + val accessorContext by lazy { accessor.analyze() } val parameter = accessor.valueParameters.singleOrNull() - val parameterDescriptor = accessorContext[BindingContext.VALUE_PARAMETER, parameter] as? ValueParameterDescriptor if (bodyExpression.anyDescendantOfType { when (it) { is KtBinaryExpression -> it.left.isBackingFieldReference(property) && it.operationToken in assignmentOperators is KtUnaryExpression -> it.baseExpression.isBackingFieldReference(property) && it.operationToken in incrementAndDecrementOperators - is KtCallExpression -> + is KtCallExpression -> { it.valueArguments.any { arg -> - arg.text == parameter?.text && run { - val argumentResultingDescriptor = - arg.getArgumentExpression().getResolvedCall(accessorContext)?.resultingDescriptor - argumentResultingDescriptor == parameterDescriptor - } + val argumentResultingDescriptor = arg.getArgumentExpression() + .getResolvedCall(accessorContext) + ?.resultingDescriptor + argumentResultingDescriptor != null && argumentResultingDescriptor == accessorContext[BindingContext.VALUE_PARAMETER, parameter] } + } else -> false } }) return @@ -60,7 +58,6 @@ class SetterBackingFieldAssignmentInspection : AbstractKotlinInspection(), Clean AssignBackingFieldFix() ) }) - } private fun KtExpression?.isBackingFieldReference(property: KtProperty) = with(SuspiciousVarPropertyInspection) { this@isBackingFieldReference != null && isBackingFieldReference(property) @@ -85,6 +82,7 @@ private class AssignBackingFieldFix : LocalQuickFix { ?.takeWhile { it != bodyExpression.rBrace } ?.singleOrNull { it is PsiWhiteSpace } ?.also { it.delete() } - bodyExpression.addBefore(KtPsiFactory(setter).createExpression("field = ${parameter.text}"), bodyExpression.rBrace) + + bodyExpression.addBefore(KtPsiFactory(setter).createExpression("field = ${parameter.name}"), bodyExpression.rBrace) } } \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/setterBackingFieldAssignment/functionCallWithSetterParam2.kt b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/functionCallWithSetterParam2.kt new file mode 100644 index 00000000000..1edf707c14a --- /dev/null +++ b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/functionCallWithSetterParam2.kt @@ -0,0 +1,9 @@ +// PROBLEM: none +class Test { + var foo: Int = 10 + set(value: Int) { + bar(value = value) + } + + fun bar(value: Int) {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt new file mode 100644 index 00000000000..be4d994798e --- /dev/null +++ b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt @@ -0,0 +1,5 @@ +class Test { + var foo: Int = 1 + set(value: Int) { + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt.after b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt.after new file mode 100644 index 00000000000..64c19c6498f --- /dev/null +++ b/idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt.after @@ -0,0 +1,6 @@ +class Test { + var foo: Int = 1 + set(value: Int) { + field = value + } +} \ 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 a542e6633f9..930d4beb2bb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -11826,6 +11826,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/functionCallWithSetterParam.kt"); } + @TestMetadata("functionCallWithSetterParam2.kt") + public void testFunctionCallWithSetterParam2() throws Exception { + runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/functionCallWithSetterParam2.kt"); + } + @TestMetadata("increment.kt") public void testIncrement() throws Exception { runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/increment.kt"); @@ -11861,6 +11866,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment3.kt"); } + @TestMetadata("noAssignment4.kt") + public void testNoAssignment4() throws Exception { + runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/noAssignment4.kt"); + } + @TestMetadata("noBackingField.kt") public void testNoBackingField() throws Exception { runTest("idea/testData/inspectionsLocal/setterBackingFieldAssignment/noBackingField.kt");