Destructure intention: entries / entrySet are now removed only for kotlin.Map inheritors #KT-14244 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-10-07 19:46:28 +03:00
parent 304f6a3b3a
commit 8188bb1e54
5 changed files with 46 additions and 4 deletions
@@ -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<KtDeclaration>(
// Note: list should contains properties in order to create destructuring declaration
val usagesToRemove = mutableListOf<UsageData>()
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<KtDeclaration>(
)
}
else if (classDescriptor.isData) {
removeSelectorInLoopRange = false
val valueParameters = classDescriptor.unsubstitutedPrimaryConstructor?.valueParameters ?: return null
valueParameters.mapTo(usagesToRemove) { UsageData(it) }
@@ -0,0 +1,11 @@
// WITH_RUNTIME
class MyMap {
val entries = listOf<Map.Entry<Int, Int>>()
}
fun foo(mm: MyMap) {
for (entry<caret> in mm.entries) {
val (key, value) = entry
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
class MyMap {
val entries = listOf<Map.Entry<Int, Int>>()
}
fun foo(mm: MyMap) {
for ((key, value) in mm.entries) {
}
}
@@ -231,4 +231,12 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Use destructuring declaration</problem_class>
<description>Use destructuring declaration</description>
</problem>
<problem>
<file>FakeEntries.kt</file>
<line>8</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/FakeEntries.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Use destructuring declaration</problem_class>
<description>Use destructuring declaration</description>
</problem>
</problems>
@@ -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");