diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index f00fb31c0cd..16b0ea4d432 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_ENTRY import org.jetbrains.kotlin.descriptors.ClassKind.OBJECT import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.JetType @@ -36,6 +37,12 @@ public fun DeclarationDescriptor.getImportableDescriptor(): DeclarationDescripto } } +public val DeclarationDescriptor.fqNameUnsafe: FqNameUnsafe + get() = DescriptorUtils.getFqName(this) + +public val DeclarationDescriptor.fqNameSafe: FqName + get() = DescriptorUtils.getFqNameSafe(this) + public val DeclarationDescriptor.isExtension: Boolean get() = this is CallableDescriptor && getExtensionReceiverParameter() != null diff --git a/idea/resources/inspectionDescriptions/RemoveForLoopIndices.html b/idea/resources/inspectionDescriptions/RemoveForLoopIndices.html new file mode 100644 index 00000000000..54ffaaedaee --- /dev/null +++ b/idea/resources/inspectionDescriptions/RemoveForLoopIndices.html @@ -0,0 +1,5 @@ + + +This inspection reports for loops iterating over a collection of values using "withIndex()" function with index variable not used in the loop body. + + diff --git a/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/after.kt.template b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/after.kt.template new file mode 100644 index 00000000000..a940c7a3e81 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/after.kt.template @@ -0,0 +1,3 @@ +for ((i, x) in foo.withIndices()) { + +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/before.kt.template b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/before.kt.template new file mode 100644 index 00000000000..ef41e9fadce --- /dev/null +++ b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/before.kt.template @@ -0,0 +1,3 @@ +for (x in foo) { + +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/description.html b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/description.html new file mode 100644 index 00000000000..2017c1d8723 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddForLoopIndicesIntention/description.html @@ -0,0 +1,5 @@ + + +This intention adds an index variable to a for loop iterating over a collection. + + diff --git a/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/after.kt.template b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/after.kt.template new file mode 100644 index 00000000000..ef41e9fadce --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/after.kt.template @@ -0,0 +1,3 @@ +for (x in foo) { + +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/before.kt.template b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/before.kt.template new file mode 100644 index 00000000000..a940c7a3e81 --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/before.kt.template @@ -0,0 +1,3 @@ +for ((i, x) in foo.withIndices()) { + +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/description.html b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/description.html new file mode 100644 index 00000000000..dfdfe1e2a0c --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveForLoopIndicesIntention/description.html @@ -0,0 +1,5 @@ + + +This intention removes the index variable from a for loop iterating over a collection. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index c800597d000..5cfd263d0af 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -794,6 +794,16 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.AddForLoopIndicesIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesIntention + Kotlin + + org.jetbrains.kotlin.idea.intentions.SwapBinaryExpressionIntention Kotlin @@ -1071,6 +1081,13 @@ cleanupTool="true" level="WARNING"/> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt new file mode 100644 index 00000000000..c327ebc3dcd --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.intentions + +import com.intellij.codeInsight.intention.LowPriorityAction +import com.intellij.codeInsight.template.TemplateBuilderImpl +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiDocumentManager +import org.jetbrains.kotlin.analyzer.analyzeInContext +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.core.replaced +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +public class AddForLoopIndicesIntention : JetSelfTargetingRangeIntention(javaClass(), "Add indices to 'for' loop"), LowPriorityAction { + private val WITH_INDEX_FQ_NAME = "kotlin.withIndex" + + override fun applicabilityRange(element: JetForExpression): TextRange? { + if (element.loopParameter == null) return null + val loopRange = element.loopRange ?: return null + + val bindingContext = element.analyze(BodyResolveMode.PARTIAL) + + val resolvedCall = loopRange.getResolvedCall(bindingContext) + if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() == WITH_INDEX_FQ_NAME) return null // already withIndex() call + + val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, element] ?: return null + val potentialExpression = createWithIndexExpression(loopRange) + + val newBindingContext = potentialExpression.analyzeInContext(resolutionScope) + val newResolvedCall = potentialExpression.getResolvedCall(newBindingContext) ?: return null + if (newResolvedCall.resultingDescriptor.fqNameUnsafe.asString() != WITH_INDEX_FQ_NAME) return null + + return TextRange(element.startOffset, element.body?.startOffset ?: element.endOffset) + } + + override fun applyTo(element: JetForExpression, editor: Editor) { + val loopRange = element.loopRange!! + val loopParameter = element.loopParameter!! + val psiFactory = JetPsiFactory(element) + + loopRange.replace(createWithIndexExpression(loopRange)) + + var multiParameter = (psiFactory.createExpressionByPattern("for((index, $0) in x){}", loopParameter.text) as JetForExpression).multiParameter!! + + multiParameter = loopParameter.replaced(multiParameter) + + val indexVariable = multiParameter.entries[0] + editor.caretModel.moveToOffset(indexVariable.startOffset) + + runTemplate(editor, element, indexVariable) + } + + private fun runTemplate(editor: Editor, forExpression: JetForExpression, indexVariable: JetMultiDeclarationEntry) { + PsiDocumentManager.getInstance(forExpression.project).doPostponedOperationsAndUnblockDocument(editor.document) + + val templateBuilder = TemplateBuilderImpl(forExpression) + templateBuilder.replaceElement(indexVariable, ChooseStringExpression(listOf("index", "i"))) + + val body = forExpression.body + when (body) { + is JetBlockExpression -> { + val statement = body.statements.firstOrNull() + if (statement != null) { + templateBuilder.setEndVariableBefore(statement) + } + else { + templateBuilder.setEndVariableAfter(body.lBrace) + } + } + + null -> forExpression.rightParenthesis.let { templateBuilder.setEndVariableAfter(it) } + + else -> templateBuilder.setEndVariableBefore(body) + } + + templateBuilder.run(editor, true) + } + + private fun createWithIndexExpression(originalExpression: JetExpression): JetExpression { + return JetPsiFactory(originalExpression).createExpressionByPattern("$0.withIndex()", originalExpression) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt index 8d0a2966598..f348afa0d4f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertForEachToForLoopIntention.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -public class ConvertForEachToForLoopIntention : JetSelfTargetingOffsetIndependentIntention(javaClass(), "Replace with a for loop") { +public class ConvertForEachToForLoopIntention : JetSelfTargetingOffsetIndependentIntention(javaClass(), "Replace with a 'for' loop") { override fun isApplicableTo(element: JetSimpleNameExpression): Boolean { if (element.getReferencedName() != "forEach") return false diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt index 0bc8076d28c..e0903266e68 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToForEachFunctionCallIntention.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.psiUtil.contentRange import org.jetbrains.kotlin.psi.psiUtil.endOffset -public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention(javaClass(), "Replace with a forEach function call") { +public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention(javaClass(), "Replace with a 'forEach' function call") { override fun isApplicableTo(element: JetForExpression, caretOffset: Int): Boolean { val rParen = element.getRightParenthesis() ?: return false if (caretOffset > rParen.endOffset) return false // available only on the loop header, not in the body diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveForLoopIndicesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveForLoopIndicesIntention.kt new file mode 100644 index 00000000000..abf076e9210 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveForLoopIndicesIntention.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.intentions + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.util.TextRange +import com.intellij.psi.search.searches.ReferencesSearch +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.editor.fixers.range +import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection +import org.jetbrains.kotlin.psi.JetDotQualifiedExpression +import org.jetbrains.kotlin.psi.JetForExpression +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.psi.createExpressionByPattern +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +public class RemoveForLoopIndicesInspection : IntentionBasedInspection( + listOf(IntentionBasedInspection.IntentionData(RemoveForLoopIndicesIntention())), + "Index is not used in the loop body", + javaClass() +) { + override val problemHighlightType: ProblemHighlightType + get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL +} + +public class RemoveForLoopIndicesIntention : JetSelfTargetingRangeIntention(javaClass(), "Remove indices in 'for' loop") { + private val WITH_INDEX_FQ_NAME = "kotlin.withIndex" + + override fun applicabilityRange(element: JetForExpression): TextRange? { + val loopRange = element.loopRange as? JetDotQualifiedExpression ?: return null + val multiParameter = element.multiParameter ?: return null + if (multiParameter.entries.size() != 2) return null + + val bindingContext = element.analyze(BodyResolveMode.PARTIAL) + + val resolvedCall = loopRange.getResolvedCall(bindingContext) + if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() != WITH_INDEX_FQ_NAME) return null + + val indexVar = multiParameter.entries[0] + if (ReferencesSearch.search(indexVar).any()) return null + + return indexVar.nameIdentifier?.range + } + + override fun applyTo(element: JetForExpression, editor: Editor) { + val multiParameter = element.multiParameter!! + val loopRange = element.loopRange as JetDotQualifiedExpression + + val elementVar = multiParameter.entries[1] + val loop = JetPsiFactory(element).createExpressionByPattern("for ($0 in _) {}", elementVar.text) as JetForExpression + multiParameter.replace(loop.loopParameter!!) + + loopRange.replace(loopRange.receiverExpression) + } +} diff --git a/idea/testData/intentions/addForLoopIndices/.intention b/idea/testData/intentions/addForLoopIndices/.intention new file mode 100644 index 00000000000..8e1d6530547 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.AddForLoopIndicesIntention \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/explicitParamType.kt b/idea/testData/intentions/addForLoopIndices/explicitParamType.kt new file mode 100644 index 00000000000..0cadfa4e63b --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/explicitParamType.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME +fun a() { + val b = listOf(1,2,3,4,5) + for (c : Int in b) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/explicitParamType.kt.after b/idea/testData/intentions/addForLoopIndices/explicitParamType.kt.after new file mode 100644 index 00000000000..0d9a18f1439 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/explicitParamType.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +fun a() { + val b = listOf(1,2,3,4,5) + for ((index, c : Int) in b.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/inapplicableExistingIndices.kt b/idea/testData/intentions/addForLoopIndices/inapplicableExistingIndices.kt new file mode 100644 index 00000000000..b67c1a2c735 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/inapplicableExistingIndices.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +fun b(c: List) { + for ((indexVariable, d) in c.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/inapplicableInBody.kt b/idea/testData/intentions/addForLoopIndices/inapplicableInBody.kt new file mode 100644 index 00000000000..587f8ff9da1 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/inapplicableInBody.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +fun foo() { + for (a in listOf(1, 2, 3)) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/inapplicableOnMap.kt b/idea/testData/intentions/addForLoopIndices/inapplicableOnMap.kt new file mode 100644 index 00000000000..42c9ecb7ee7 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/inapplicableOnMap.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: FALSE +// WITH_RUNTIME +fun foo(bar: Map) { + for (a in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/inapplicableOverridenFunction.kt b/idea/testData/intentions/addForLoopIndices/inapplicableOverridenFunction.kt new file mode 100644 index 00000000000..5ce28ace4b3 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/inapplicableOverridenFunction.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE +fun String.withIndex(): Int = 42 + +fun foo(s: String) { + for (a in s) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/inapplicableUnresolved.kt b/idea/testData/intentions/addForLoopIndices/inapplicableUnresolved.kt new file mode 100644 index 00000000000..c397c9898eb --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/inapplicableUnresolved.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// ERROR: Unresolved reference: b +fun foo() { + for (a in b) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/intArray.kt b/idea/testData/intentions/addForLoopIndices/intArray.kt new file mode 100644 index 00000000000..358656430d6 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/intArray.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: IntArray) { + for (a in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/intArray.kt.after b/idea/testData/intentions/addForLoopIndices/intArray.kt.after new file mode 100644 index 00000000000..1be0bfb6bf9 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/intArray.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: IntArray) { + for ((index, a) in bar.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/iterable.kt b/idea/testData/intentions/addForLoopIndices/iterable.kt new file mode 100644 index 00000000000..414782c9a9a --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/iterable.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: Iterable) { + for (a in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/iterable.kt.after b/idea/testData/intentions/addForLoopIndices/iterable.kt.after new file mode 100644 index 00000000000..f96fe487f34 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/iterable.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: Iterable) { + for ((index, a) in bar.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/noBody.kt b/idea/testData/intentions/addForLoopIndices/noBody.kt new file mode 100644 index 00000000000..e47e3432851 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/noBody.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun foo(bar: IntArray) { + for (a in bar) +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/noBody.kt.after b/idea/testData/intentions/addForLoopIndices/noBody.kt.after new file mode 100644 index 00000000000..66fb942fd4c --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/noBody.kt.after @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun foo(bar: IntArray) { + for ((index, a) in bar.withIndex()) +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/objectArray.kt b/idea/testData/intentions/addForLoopIndices/objectArray.kt new file mode 100644 index 00000000000..a907c08aba7 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/objectArray.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: Array) { + for (a in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/objectArray.kt.after b/idea/testData/intentions/addForLoopIndices/objectArray.kt.after new file mode 100644 index 00000000000..097db825620 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/objectArray.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: Array) { + for ((index, a) in bar.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/sequence.kt b/idea/testData/intentions/addForLoopIndices/sequence.kt new file mode 100644 index 00000000000..71f1e5be815 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/sequence.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun foo(bar: Sequence) { + for (a in bar) + print(a) +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/sequence.kt.after b/idea/testData/intentions/addForLoopIndices/sequence.kt.after new file mode 100644 index 00000000000..c1fbaf64dab --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/sequence.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun foo(bar: Sequence) { + for ((index, a) in bar.withIndex()) + print(a) +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/simpleIntList.kt b/idea/testData/intentions/addForLoopIndices/simpleIntList.kt new file mode 100644 index 00000000000..f7472f3e066 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/simpleIntList.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME +fun a() { + val b = listOf(1,2,3,4,5) + for (c in b) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/simpleIntList.kt.after b/idea/testData/intentions/addForLoopIndices/simpleIntList.kt.after new file mode 100644 index 00000000000..4a3c9653a5d --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/simpleIntList.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +fun a() { + val b = listOf(1,2,3,4,5) + for ((index, c) in b.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/string.kt b/idea/testData/intentions/addForLoopIndices/string.kt new file mode 100644 index 00000000000..6fa3a2bd2a0 --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/string.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: String) { + for (a in bar) { + print(a) + } +} \ No newline at end of file diff --git a/idea/testData/intentions/addForLoopIndices/string.kt.after b/idea/testData/intentions/addForLoopIndices/string.kt.after new file mode 100644 index 00000000000..0956ed2394a --- /dev/null +++ b/idea/testData/intentions/addForLoopIndices/string.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: String) { + for ((index, a) in bar.withIndex()) { + print(a) + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/.intention b/idea/testData/intentions/removeForLoopIndices/.intention new file mode 100644 index 00000000000..013371784a9 --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesIntention \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/inapplicableForLoop.kt b/idea/testData/intentions/removeForLoopIndices/inapplicableForLoop.kt new file mode 100644 index 00000000000..1d06d512929 --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/inapplicableForLoop.kt @@ -0,0 +1,6 @@ +// IS_APPLICABLE: false +fun foo(bar: List) { + for (a in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/inapplicableIndexUse.kt b/idea/testData/intentions/removeForLoopIndices/inapplicableIndexUse.kt new file mode 100644 index 00000000000..689db8843fb --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/inapplicableIndexUse.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: FALSE +// WITH_RUNTIME + +fun foo(b: List) : Int { + for ((i, c) in b.withIndex()) { + return i + } + return 0 +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/inapplicableOverridenFunction.kt b/idea/testData/intentions/removeForLoopIndices/inapplicableOverridenFunction.kt new file mode 100644 index 00000000000..1442ced4db1 --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/inapplicableOverridenFunction.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE + +fun Int.withIndex(): List> = linkedListOf>() + +fun foo(s: Int) { + for ((index, a) in s.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/loopWithType.kt b/idea/testData/intentions/removeForLoopIndices/loopWithType.kt new file mode 100644 index 00000000000..1c055d425a6 --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/loopWithType.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: List) { + for ((i : Int, b: Int) in bar.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/loopWithType.kt.after b/idea/testData/intentions/removeForLoopIndices/loopWithType.kt.after new file mode 100644 index 00000000000..918d3ab32f8 --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/loopWithType.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: List) { + for (b: Int in bar) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt b/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt new file mode 100644 index 00000000000..e907ccc131b --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: List) { + for ((i,a) in bar.withIndex()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt.after b/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt.after new file mode 100644 index 00000000000..8b1907b3c3d --- /dev/null +++ b/idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun foo(bar: List) { + for (a in bar) { + + } +} \ 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 9d155e4f9a2..6d1333cd1e0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -92,6 +92,93 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/addForLoopIndices") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddForLoopIndices extends AbstractIntentionTest { + public void testAllFilesPresentInAddForLoopIndices() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/addForLoopIndices"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("explicitParamType.kt") + public void testExplicitParamType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/explicitParamType.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableExistingIndices.kt") + public void testInapplicableExistingIndices() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/inapplicableExistingIndices.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableInBody.kt") + public void testInapplicableInBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/inapplicableInBody.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableOnMap.kt") + public void testInapplicableOnMap() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/inapplicableOnMap.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableOverridenFunction.kt") + public void testInapplicableOverridenFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/inapplicableOverridenFunction.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableUnresolved.kt") + public void testInapplicableUnresolved() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/inapplicableUnresolved.kt"); + doTest(fileName); + } + + @TestMetadata("intArray.kt") + public void testIntArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/intArray.kt"); + doTest(fileName); + } + + @TestMetadata("iterable.kt") + public void testIterable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/iterable.kt"); + doTest(fileName); + } + + @TestMetadata("noBody.kt") + public void testNoBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/noBody.kt"); + doTest(fileName); + } + + @TestMetadata("objectArray.kt") + public void testObjectArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/objectArray.kt"); + doTest(fileName); + } + + @TestMetadata("sequence.kt") + public void testSequence() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/sequence.kt"); + doTest(fileName); + } + + @TestMetadata("simpleIntList.kt") + public void testSimpleIntList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/simpleIntList.kt"); + doTest(fileName); + } + + @TestMetadata("string.kt") + public void testString() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addForLoopIndices/string.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/addNameToArgument") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -6089,6 +6176,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } + @TestMetadata("idea/testData/intentions/removeForLoopIndices") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RemoveForLoopIndices extends AbstractIntentionTest { + public void testAllFilesPresentInRemoveForLoopIndices() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeForLoopIndices"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("inapplicableForLoop.kt") + public void testInapplicableForLoop() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/inapplicableForLoop.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableIndexUse.kt") + public void testInapplicableIndexUse() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/inapplicableIndexUse.kt"); + doTest(fileName); + } + + @TestMetadata("inapplicableOverridenFunction.kt") + public void testInapplicableOverridenFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/inapplicableOverridenFunction.kt"); + doTest(fileName); + } + + @TestMetadata("loopWithType.kt") + public void testLoopWithType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/loopWithType.kt"); + doTest(fileName); + } + + @TestMetadata("simpleLoopWithIndices.kt") + public void testSimpleLoopWithIndices() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/removeUnnecessaryParentheses") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)