diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt index c1010a75f48..8793aea9498 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.intentions.loopToCallChain import com.intellij.openapi.util.Key import com.intellij.openapi.util.UserDataHolderBase import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.idea.analysis.analyzeInContext @@ -190,18 +191,34 @@ enum class CollectionKind { } fun KtExpression.isSimpleCollectionInstantiation(): CollectionKind? { - //TODO: support mutableListOf() etc val callExpression = this as? KtCallExpression ?: return null //TODO: it can be qualified too if (callExpression.valueArguments.isNotEmpty()) return null + val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL) val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return null - val constructorDescriptor = resolvedCall.resultingDescriptor as? ConstructorDescriptor ?: return null - val classDescriptor = constructorDescriptor.containingDeclaration - val classFqName = classDescriptor.importableFqName?.asString() - return when (classFqName) { - "java.util.ArrayList" -> CollectionKind.LIST - "java.util.HashSet", "java.util.LinkedHashSet" -> CollectionKind.SET - else -> null + val descriptor = resolvedCall.resultingDescriptor + + when (descriptor) { + is ConstructorDescriptor -> { + val classDescriptor = descriptor.containingDeclaration + val classFqName = classDescriptor.importableFqName?.asString() + return when (classFqName) { + "java.util.ArrayList" -> CollectionKind.LIST + "java.util.HashSet", "java.util.LinkedHashSet" -> CollectionKind.SET + else -> null + } + } + + is FunctionDescriptor -> { + val fqName = descriptor.importableFqName?.asString() + return when (fqName) { + "kotlin.collections.arrayListOf", "kotlin.collections.mutableListOf" -> CollectionKind.LIST + "kotlin.collections.hashSetOf", "kotlin.collections.mutableSetOf" -> CollectionKind.SET + else -> null + } + } + + else -> return null } } diff --git a/idea/testData/intentions/loopToCallChain/toList2.kt b/idea/testData/intentions/loopToCallChain/toList2.kt new file mode 100644 index 00000000000..a5678d1d699 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toList2.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toList()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): List { + val result = arrayListOf() + for (s in map.values) { + result.add(s) + } + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toList2.kt.after b/idea/testData/intentions/loopToCallChain/toList2.kt.after new file mode 100644 index 00000000000..4625051cac9 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toList2.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toList()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): List { + val result = map.values.toList() + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toList3.kt b/idea/testData/intentions/loopToCallChain/toList3.kt new file mode 100644 index 00000000000..cf919d786e6 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toList3.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toList()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): List { + val result = mutableListOf() + for (s in map.values) { + result.add(s) + } + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toList3.kt.after b/idea/testData/intentions/loopToCallChain/toList3.kt.after new file mode 100644 index 00000000000..4625051cac9 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toList3.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toList()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): List { + val result = map.values.toList() + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toMutableSet2.kt b/idea/testData/intentions/loopToCallChain/toMutableSet2.kt new file mode 100644 index 00000000000..a0422f564f6 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toMutableSet2.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toMutableSet()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): MutableCollection { + val result = hashSetOf() + for (s in map.values) { + result.add(s) + } + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toMutableSet2.kt.after b/idea/testData/intentions/loopToCallChain/toMutableSet2.kt.after new file mode 100644 index 00000000000..712bf84a06f --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toMutableSet2.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toMutableSet()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): MutableCollection { + val result = map.values.toMutableSet() + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toMutableSet3.kt b/idea/testData/intentions/loopToCallChain/toMutableSet3.kt new file mode 100644 index 00000000000..7ed2fe38d06 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toMutableSet3.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toMutableSet()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): MutableCollection { + val result = mutableSetOf() + for (s in map.values) { + result.add(s) + } + return result +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/toMutableSet3.kt.after b/idea/testData/intentions/loopToCallChain/toMutableSet3.kt.after new file mode 100644 index 00000000000..712bf84a06f --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/toMutableSet3.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Replace with 'toMutableSet()'" +// IS_APPLICABLE_2: false +fun foo(map: Map): MutableCollection { + val result = map.values.toMutableSet() + return result +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java index 0f9ad145297..26f0364e466 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java @@ -1055,12 +1055,36 @@ public class IntentionTest2Generated extends AbstractIntentionTest2 { doTest(fileName); } + @TestMetadata("toList2.kt") + public void testToList2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toList2.kt"); + doTest(fileName); + } + + @TestMetadata("toList3.kt") + public void testToList3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toList3.kt"); + doTest(fileName); + } + @TestMetadata("toMutableSet.kt") public void testToMutableSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet.kt"); doTest(fileName); } + @TestMetadata("toMutableSet2.kt") + public void testToMutableSet2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet2.kt"); + doTest(fileName); + } + + @TestMetadata("toMutableSet3.kt") + public void testToMutableSet3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet3.kt"); + doTest(fileName); + } + @TestMetadata("toSet.kt") public void testToSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toSet.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 7e203561701..288a2d95581 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -8173,12 +8173,36 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("toList2.kt") + public void testToList2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toList2.kt"); + doTest(fileName); + } + + @TestMetadata("toList3.kt") + public void testToList3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toList3.kt"); + doTest(fileName); + } + @TestMetadata("toMutableSet.kt") public void testToMutableSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet.kt"); doTest(fileName); } + @TestMetadata("toMutableSet2.kt") + public void testToMutableSet2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet2.kt"); + doTest(fileName); + } + + @TestMetadata("toMutableSet3.kt") + public void testToMutableSet3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toMutableSet3.kt"); + doTest(fileName); + } + @TestMetadata("toSet.kt") public void testToSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/toSet.kt");