From 8188bb1e5498367fc19da5ea533f98958141ba28 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 7 Oct 2016 19:46:28 +0300 Subject: [PATCH] Destructure intention: entries / entrySet are now removed only for kotlin.Map inheritors #KT-14244 Fixed --- .../idea/intentions/DestructureIntention.kt | 15 +++++++++++---- .../intentions/iterationOverMap/FakeEntries.kt | 11 +++++++++++ .../iterationOverMap/FakeEntries.kt.after | 10 ++++++++++ .../iterationOverMap/inspectionData/expected.xml | 8 ++++++++ .../idea/intentions/IntentionTestGenerated.java | 6 ++++++ 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 idea/testData/intentions/iterationOverMap/FakeEntries.kt create mode 100644 idea/testData/intentions/iterationOverMap/FakeEntries.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt index b5584e98a9a..2bd5278edfa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/DestructureIntention.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.utils.singletonOrEmptyList import java.util.* @@ -161,10 +162,17 @@ class DestructureIntention : SelfTargetingRangeIntention( // Note: list should contains properties in order to create destructuring declaration val usagesToRemove = mutableListOf() var noBadUsages = true - val removeSelectorInLoopRange: Boolean + var removeSelectorInLoopRange = false if (forLoop != null && DescriptorUtils.isSubclass(classDescriptor, mapEntryClassDescriptor)) { - val loopRangeDescriptorName = forLoop.loopRange.getResolvedCall(context)?.resultingDescriptor?.name - removeSelectorInLoopRange = loopRangeDescriptorName?.asString().let { it == "entries" || it == "entrySet" } + val loopRangeDescriptor = forLoop.loopRange.getResolvedCall(context)?.resultingDescriptor + if (loopRangeDescriptor != null) { + val loopRangeDescriptorOwner = loopRangeDescriptor.containingDeclaration + val mapClassDescriptor = classDescriptor.builtIns.map + if (loopRangeDescriptorOwner is ClassDescriptor && + DescriptorUtils.isSubclass(loopRangeDescriptorOwner, mapClassDescriptor)) { + removeSelectorInLoopRange = loopRangeDescriptor.name.asString().let { it == "entries" || it == "entrySet" } + } + } listOf("key", "value").mapTo(usagesToRemove) { UsageData(mapEntryClassDescriptor.unsubstitutedMemberScope.getContributedVariables( @@ -178,7 +186,6 @@ class DestructureIntention : SelfTargetingRangeIntention( ) } else if (classDescriptor.isData) { - removeSelectorInLoopRange = false val valueParameters = classDescriptor.unsubstitutedPrimaryConstructor?.valueParameters ?: return null valueParameters.mapTo(usagesToRemove) { UsageData(it) } diff --git a/idea/testData/intentions/iterationOverMap/FakeEntries.kt b/idea/testData/intentions/iterationOverMap/FakeEntries.kt new file mode 100644 index 00000000000..3bcc6fa0162 --- /dev/null +++ b/idea/testData/intentions/iterationOverMap/FakeEntries.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class MyMap { + val entries = listOf>() +} + +fun foo(mm: MyMap) { + for (entry in mm.entries) { + val (key, value) = entry + } +} \ No newline at end of file diff --git a/idea/testData/intentions/iterationOverMap/FakeEntries.kt.after b/idea/testData/intentions/iterationOverMap/FakeEntries.kt.after new file mode 100644 index 00000000000..12166d2b716 --- /dev/null +++ b/idea/testData/intentions/iterationOverMap/FakeEntries.kt.after @@ -0,0 +1,10 @@ +// WITH_RUNTIME + +class MyMap { + val entries = listOf>() +} + +fun foo(mm: MyMap) { + for ((key, value) in mm.entries) { + } +} \ No newline at end of file diff --git a/idea/testData/intentions/iterationOverMap/inspectionData/expected.xml b/idea/testData/intentions/iterationOverMap/inspectionData/expected.xml index b613095ddf0..1f2211c2b66 100644 --- a/idea/testData/intentions/iterationOverMap/inspectionData/expected.xml +++ b/idea/testData/intentions/iterationOverMap/inspectionData/expected.xml @@ -231,4 +231,12 @@ Use destructuring declaration Use destructuring declaration + + FakeEntries.kt + 8 + light_idea_test_case + + Use destructuring declaration + Use destructuring declaration + \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 2fdc9901d4b..40b382951ed 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -7699,6 +7699,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("FakeEntries.kt") + public void testFakeEntries() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterationOverMap/FakeEntries.kt"); + doTest(fileName); + } + @TestMetadata("Getters.kt") public void testGetters() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterationOverMap/Getters.kt");