diff --git a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java index 528ea1342f73..f54d6395fa2a 100644 --- a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java +++ b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/inspections/tests/K2LocalInspectionTestGenerated.java @@ -9702,6 +9702,26 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/complexReceiver.kt"); } + @TestMetadata("elementNameCollision.kt") + public void testElementNameCollision() throws Exception { + runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt"); + } + + @TestMetadata("elementNameCollisionMultiple.kt") + public void testElementNameCollisionMultiple() throws Exception { + runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt"); + } + + @TestMetadata("elementNameCollisionNestedLoop.kt") + public void testElementNameCollisionNestedLoop() throws Exception { + runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt"); + } + + @TestMetadata("elementNameCollisionParameter.kt") + public void testElementNameCollisionParameter() throws Exception { + runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt"); + } + @TestMetadata("forNotTarget.kt") public void testForNotTarget() throws Exception { runTest("../../../idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/forNotTarget.kt"); diff --git a/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/ReplaceManualRangeWithIndicesCallsInspection.kt b/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/ReplaceManualRangeWithIndicesCallsInspection.kt index 176c660ead44..ac0527e8fbff 100644 --- a/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/ReplaceManualRangeWithIndicesCallsInspection.kt +++ b/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/ReplaceManualRangeWithIndicesCallsInspection.kt @@ -9,6 +9,9 @@ import com.intellij.psi.search.searches.ReferencesSearch import org.jetbrains.kotlin.analysis.api.KaSession import org.jetbrains.kotlin.analysis.api.resolution.successfulVariableAccessCall import org.jetbrains.kotlin.analysis.api.types.KaType +import org.jetbrains.kotlin.idea.base.codeInsight.KotlinDeclarationNameValidator +import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggester +import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggestionProvider import org.jetbrains.kotlin.idea.base.psi.replaced import org.jetbrains.kotlin.idea.base.psi.safeDeparenthesize import org.jetbrains.kotlin.idea.base.resources.KotlinBundle @@ -51,6 +54,7 @@ class ReplaceManualRangeWithIndicesCallsInspection : AbstractRangeInspection + val nameValidator = KotlinDeclarationNameValidator( + loopParameter, + true, + KotlinNameSuggestionProvider.ValidatorTarget.VARIABLE, + ) + KotlinNameSuggester.suggestNameByName("element") { nameValidator.validate(it) } + } + } else null + + return Context(explicitReceiver, suggestElementLoop, implicitReceiverInfo, suggestedElementName) } private fun KaSession.rightBound(type: RangeKtExpressionType, expression: KtExpression): KtExpression? { @@ -245,13 +262,14 @@ class ReplaceManualRangeWithIndicesCallsInspection : AbstractRangeInspection() ?: return val loopParameter = forExpression.loopParameter ?: return val loopRange = forExpression.loopRange ?: return + val elementName = context.suggestedElementName ?: return val collection = resolveCollectionExpression(project) // Try a single usage first val singleUsageInfo = LoopToCollectionTransformUtils.findSingleArrayAccessUsage(loopParameter) if (singleUsageInfo != null) { - LoopToCollectionTransformUtils.transformLoop(project, listOf(singleUsageInfo), loopParameter, loopRange, collection) + LoopToCollectionTransformUtils.transformLoop(project, listOf(singleUsageInfo), loopParameter, loopRange, collection, elementName) return } @@ -267,7 +285,7 @@ class ReplaceManualRangeWithIndicesCallsInspection : AbstractRangeInspection, loopParameter: KtParameter, loopRange: KtExpression, - newLoopRange: KtExpression + newLoopRange: KtExpression, + elementName: String ) { val factory = KtPsiFactory(project) - val newParameter = factory.createLoopParameter("element") - val newReferenceExpression = factory.createExpression("element") - + + val newParameter = factory.createLoopParameter(elementName) + val newReferenceExpression = factory.createExpression(elementName) + // Replace all array access expressions with direct element references usageInfos.forEach { usageInfo -> usageInfo.arrayAccessElement.replace(newReferenceExpression.copy()) } - + loopParameter.replace(newParameter) loopRange.replace(newLoopRange) } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 1c8939d61f5e..27cc9c3d913e 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -14386,6 +14386,26 @@ public abstract class LocalInspectionTestGenerated extends AbstractK1LocalInspec runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/complexReceiver.kt"); } + @TestMetadata("elementNameCollision.kt") + public void testElementNameCollision() throws Exception { + runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt"); + } + + @TestMetadata("elementNameCollisionMultiple.kt") + public void testElementNameCollisionMultiple() throws Exception { + runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt"); + } + + @TestMetadata("elementNameCollisionNestedLoop.kt") + public void testElementNameCollisionNestedLoop() throws Exception { + runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt"); + } + + @TestMetadata("elementNameCollisionParameter.kt") + public void testElementNameCollisionParameter() throws Exception { + runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt"); + } + @TestMetadata("forNotTarget.kt") public void testForNotTarget() throws Exception { runTest("testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/forNotTarget.kt"); diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt new file mode 100644 index 000000000000..57b8043fa190 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt @@ -0,0 +1,9 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val element = mutableListOf("hello", "world") + for (i in 0 until element.size) { + element[i].length + element.size + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt.after new file mode 100644 index 000000000000..1b993e01d020 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollision.kt.after @@ -0,0 +1,9 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val element = mutableListOf("hello", "world") + for (element1 in element) { + element1.length + element.size + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt new file mode 100644 index 000000000000..04a2749129ad --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt @@ -0,0 +1,10 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val element = "first" + val element1 = "second" + val list = mutableListOf("hello", "world") + for (i in 0 until list.size) { + list[i].length + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt.after new file mode 100644 index 000000000000..da001875cc3f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionMultiple.kt.after @@ -0,0 +1,10 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val element = "first" + val element1 = "second" + val list = mutableListOf("hello", "world") + for (element2 in list) { + element2.length + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt new file mode 100644 index 000000000000..001f4ec883fc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt @@ -0,0 +1,10 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val outer = listOf(listOf("a", "b"), listOf("c", "d")) + for (element in outer) { + for (j in 0 until element.size) { + element[j].length + } + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt.after new file mode 100644 index 000000000000..d4dc5730f1b3 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionNestedLoop.kt.after @@ -0,0 +1,10 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test() { + val outer = listOf(listOf("a", "b"), listOf("c", "d")) + for (element in outer) { + for (element1 in element) { + element1.length + } + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt new file mode 100644 index 000000000000..a1f79803a27d --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt @@ -0,0 +1,8 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test(element: String, list: List) { + for (i in 0 until list.size) { + list[i].length + element.length + } +} diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt.after new file mode 100644 index 000000000000..d19afd2c078a --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceManualRangeWithIndicesCalls/elementNameCollisionParameter.kt.after @@ -0,0 +1,8 @@ +// WITH_STDLIB +// IGNORE_K1 +fun test(element: String, list: List) { + for (element1 in list) { + element1.length + element.length + } +}