"Use destructuring declaration": fix false negative with same name references

#KT-33003 Fixed

Original commit: 1968eb95fea826ed96682163c4e1290b549fd367

GitOrigin-RevId: edd31b0d58ac4104d7d97dae73f3ae1a8c4ce34d
This commit is contained in:
Toshiaki Kameyama
2020-11-13 16:24:45 +03:00
committed by intellij-monorepo-bot
parent 684608d8f0
commit 67666dcbcb
9 changed files with 113 additions and 16 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
@@ -233,6 +234,7 @@ class DestructureIntention : SelfTargetingRangeIntention<KtDeclaration>(
usageScopeElement.iterateOverDataClassPropertiesUsagesWithIndex(
context,
nameToSearch,
variableDescriptor,
constructorParameterNameMap,
{ index, usageData -> noBadUsages = usagesToRemove[index].add(usageData, index) && noBadUsages },
{ noBadUsages = false }
@@ -285,31 +287,35 @@ class DestructureIntention : SelfTargetingRangeIntention<KtDeclaration>(
private fun PsiElement.iterateOverDataClassPropertiesUsagesWithIndex(
context: BindingContext,
parameterName: Name,
variableDescriptor: VariableDescriptor,
constructorParameterNameMap: Map<Name, ValueParameterDescriptor>,
process: (Int, SingleUsageData) -> Unit,
cancel: () -> Unit
) {
anyDescendantOfType<KtNameReferenceExpression> {
if (it.getReferencedNameAsName() != parameterName) false
else {
val applicableUsage = getDataIfUsageIsApplicable(it, context)
if (applicableUsage != null) {
val usageDescriptor = applicableUsage.descriptor
if (usageDescriptor == null) {
for (parameter in constructorParameterNameMap.values) {
when {
it.getReferencedNameAsName() != parameterName -> false
it.getResolvedCall(context)?.resultingDescriptor != variableDescriptor -> false
else -> {
val applicableUsage = getDataIfUsageIsApplicable(it, context)
if (applicableUsage != null) {
val usageDescriptor = applicableUsage.descriptor
if (usageDescriptor == null) {
for (parameter in constructorParameterNameMap.values) {
process(parameter.index, applicableUsage)
}
return@anyDescendantOfType false
}
val parameter = constructorParameterNameMap[usageDescriptor.name]
if (parameter != null) {
process(parameter.index, applicableUsage)
return@anyDescendantOfType false
}
return@anyDescendantOfType false
}
val parameter = constructorParameterNameMap[usageDescriptor.name]
if (parameter != null) {
process(parameter.index, applicableUsage)
return@anyDescendantOfType false
}
}
cancel()
true
cancel()
true
}
}
}
}
@@ -8531,6 +8531,16 @@ public abstract class IntentionTestGenerated extends AbstractIntentionTest {
runTest("testData/intentions/destructuringInLambda/pair.kt");
}
@TestMetadata("sameNameReferences.kt")
public void testSameNameReferences() throws Exception {
runTest("testData/intentions/destructuringInLambda/sameNameReferences.kt");
}
@TestMetadata("sameNameReferences2.kt")
public void testSameNameReferences2() throws Exception {
runTest("testData/intentions/destructuringInLambda/sameNameReferences2.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("testData/intentions/destructuringInLambda/simple.kt");
@@ -8579,6 +8589,11 @@ public abstract class IntentionTestGenerated extends AbstractIntentionTest {
runTest("testData/intentions/destructuringVariables/noInitializer.kt");
}
@TestMetadata("sameNameReferences.kt")
public void testSameNameReferences() throws Exception {
runTest("testData/intentions/destructuringVariables/sameNameReferences.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("testData/intentions/destructuringVariables/simple.kt");
@@ -79,4 +79,12 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Use destructuring declaration</problem_class>
<description>Use destructuring declaration</description>
</problem>
<problem>
<file>sameNameReferences.kt</file>
<line>9</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/sameNameReferences.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Use destructuring declaration</problem_class>
<description>Use destructuring declaration</description>
</problem>
</problems>
@@ -0,0 +1,13 @@
data class D(val v1: Int, val v2: Int)
fun foo(f: (D) -> Int) {
}
fun bar() {}
fun test() {
foo { <caret>bar ->
bar()
bar.v1 + bar.v2
}
}
@@ -0,0 +1,13 @@
data class D(val v1: Int, val v2: Int)
fun foo(f: (D) -> Int) {
}
fun bar() {}
fun test() {
foo { (v1, v2) ->
bar()
v1 + v2
}
}
@@ -0,0 +1,13 @@
data class D(val v1: Int, val v2: Int)
fun foo(f: (D) -> Int) {
}
fun it() {}
fun test() {
foo {<caret>
it()
it.v1 + it.v2
}
}
@@ -0,0 +1,13 @@
data class D(val v1: Int, val v2: Int)
fun foo(f: (D) -> Int) {
}
fun it() {}
fun test() {
foo { (v1, v2) ->
it()
v1 + v2
}
}
@@ -0,0 +1,8 @@
data class D(val v1: Int, val v2: Int)
fun foo(): D = D(1, 2)
fun test(): Int {
val <caret>foo = foo()
return foo.v1 + foo.v2
}
@@ -0,0 +1,8 @@
data class D(val v1: Int, val v2: Int)
fun foo(): D = D(1, 2)
fun test(): Int {
val (v1, v2) = foo()
return v1 + v2
}