Merge branch 'for-loop-indices' of https://github.com/ElliotM/kotlin into ElliotM-for-loop-indices
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
for ((i, x) in foo.withIndices()) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
for (x in foo) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention adds an index variable to a for loop iterating over a collection.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
for (x in foo) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
for ((i, x) in foo.withIndices()) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention removes the index variable from a for loop iterating over a collection.
|
||||
</body>
|
||||
</html>
|
||||
@@ -793,6 +793,21 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.AddForLoopIndicesIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>S
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>S
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.jet.plugin.intentions.SwapBinaryExpression</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.SwapBinaryExpressionIntention</className>
|
||||
<category>Kotlin</category>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.openapi.editor.Editor
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.psi.JetParenthesizedExpression
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.analyzer.analyzeInContext
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression
|
||||
|
||||
public class AddForLoopIndicesIntention : JetSelfTargetingIntention<JetForExpression>(
|
||||
"add.for.loop.indices", javaClass()) {
|
||||
override fun applyTo(element: JetForExpression, editor: Editor) {
|
||||
val loopRange = element.getLoopRange()!!
|
||||
val newRangeText = "${loopRange.getText()}.withIndices()"
|
||||
val newRange = JetPsiFactory.createExpression(editor.getProject(), newRangeText)
|
||||
|
||||
//Roundabout way to create new multiparameter element so as not to incorrectly trigger syntax error highlighting
|
||||
val loopParameter = element.getLoopParameter()!!
|
||||
val parenthesizedParam = JetPsiFactory.createExpression(editor.getProject(), "(index)") as JetParenthesizedExpression
|
||||
val indexElement = parenthesizedParam.getExpression()!!
|
||||
val comma = JetPsiFactory.createComma(editor.getProject())
|
||||
val newParamElement = JetPsiFactory.createExpression(editor.getProject(), " ${loopParameter.getText()}")
|
||||
parenthesizedParam.addAfter(newParamElement, indexElement)
|
||||
parenthesizedParam.addAfter(comma, indexElement)
|
||||
|
||||
loopParameter.replace(parenthesizedParam)
|
||||
loopRange.replace(newRange)
|
||||
|
||||
val multiParameter = PsiTreeUtil.findChildOfType(element, indexElement.javaClass)!!
|
||||
|
||||
editor.getCaretModel().moveToOffset(multiParameter.getTextOffset())
|
||||
val templateBuilder = TemplateBuilderImpl(multiParameter)
|
||||
templateBuilder.replaceElement(multiParameter, "index")
|
||||
val manager = TemplateManagerImpl(editor.getProject())
|
||||
PsiDocumentManager.getInstance(editor.getProject()!!).doPostponedOperationsAndUnblockDocument(editor.getDocument())
|
||||
manager.startTemplate(editor, templateBuilder.buildInlineTemplate()!!)
|
||||
}
|
||||
|
||||
override fun isApplicableTo(element: JetForExpression): Boolean {
|
||||
if (element.getLoopParameter() == null) return false
|
||||
val range = element.getLoopRange() ?: return false
|
||||
if (range is JetDotQualifiedExpression) {
|
||||
val selector = range.getSelectorExpression() ?: return true
|
||||
if (selector.getText() == "withIndices()") return false
|
||||
}
|
||||
|
||||
val potentialExpression = JetPsiFactory.createExpression(element.getProject(),
|
||||
"${range.getText()}.withIndices()") as JetDotQualifiedExpression
|
||||
|
||||
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element)
|
||||
val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, element] ?: return false
|
||||
val functionSelector = potentialExpression.getSelectorExpression() as JetCallExpression
|
||||
val updatedContext = potentialExpression.analyzeInContext(scope)
|
||||
val callScope = updatedContext[BindingContext.RESOLVED_CALL, functionSelector.getCalleeExpression()!!] ?: return false
|
||||
val callFqName = DescriptorUtils.getFqNameSafe(callScope.getCandidateDescriptor())
|
||||
return callFqName.toString() == "kotlin.withIndices"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 org.jetbrains.jet.lang.psi.JetForExpression
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import com.intellij.find.FindManager
|
||||
import com.intellij.find.impl.FindManagerImpl
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.jet.plugin.findUsages.KotlinPropertyFindUsagesOptions
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
|
||||
public class RemoveForLoopIndicesIntention : JetSelfTargetingIntention<JetForExpression>(
|
||||
"remove.for.loop.indices", javaClass()) {
|
||||
override fun applyTo(element: JetForExpression, editor: Editor) {
|
||||
val parameter = element.getMultiParameter()!!
|
||||
val range = element.getLoopRange() as JetDotQualifiedExpression
|
||||
val parameters = parameter.getEntries()
|
||||
if (parameters.size() == 2) {
|
||||
parameter.replace(parameters[1])
|
||||
}
|
||||
else {
|
||||
JetPsiUtil.deleteElementWithDelimiters(parameters[0])
|
||||
}
|
||||
|
||||
range.replace(range.getReceiverExpression())
|
||||
}
|
||||
|
||||
override fun isApplicableTo(element: JetForExpression): Boolean {
|
||||
val multiParameter = element.getMultiParameter() ?: return false
|
||||
val range = element.getLoopRange() as? JetDotQualifiedExpression ?: return false
|
||||
val selector = range.getSelectorExpression() as? JetCallExpression ?: return false
|
||||
|
||||
if (!selector.textMatches("withIndices()")) return false
|
||||
|
||||
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element)
|
||||
val callResolution = bindingContext[BindingContext.RESOLVED_CALL, selector.getCalleeExpression()!!] ?: return false
|
||||
val fqName = DescriptorUtils.getFqNameSafe(callResolution.getCandidateDescriptor())
|
||||
if (fqName.toString() != "kotlin.withIndices") return false
|
||||
|
||||
val indexVar = multiParameter.getEntries()[0]
|
||||
val findManager = FindManager.getInstance(element.getProject()) as FindManagerImpl
|
||||
val findHandler = findManager.getFindUsagesManager().getFindUsagesHandler(indexVar, false) ?: return false
|
||||
val options = KotlinPropertyFindUsagesOptions(element.getProject())
|
||||
var usageCount = 0
|
||||
val processorLambda: (UsageInfo?) -> Boolean = { t -> usageCount++; false }
|
||||
findHandler.processElementUsages(indexVar, processorLambda, options)
|
||||
return usageCount == 0
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
//IS_APPLICABLE: FALSE
|
||||
// WITH_RUNTIME
|
||||
fun b(c: List<String>) {
|
||||
for ((<caret>indexVariable, d) in c.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: FALSE
|
||||
fun String.withIndices(): Int = 42
|
||||
|
||||
fun foo(s: String) {
|
||||
for (<caret>a in s) {
|
||||
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
//IS_APPLICABLE: FALSE
|
||||
//ERROR: Unresolved reference: b
|
||||
fun foo() {
|
||||
for (a <caret>in b) {
|
||||
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: FALSE
|
||||
// WITH_RUNTIME
|
||||
fun foo(bar: Map<String, String>) {
|
||||
for (a <caret>in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: IntArray) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: IntArray) {
|
||||
for ((index, a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Iterable<Int>) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Iterable<Int>) {
|
||||
for ((index, a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
fun a() {
|
||||
val b = listOf(1,2,3,4,5)
|
||||
for (<caret>c : Int in b) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
fun a() {
|
||||
val b = listOf(1,2,3,4,5)
|
||||
for ((index, c : Int) in b.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Array<Object>) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Array<Object>) {
|
||||
for ((index, a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
fun a() {
|
||||
val b = listOf(1,2,3,4,5)
|
||||
for (<caret>c in b) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
fun a() {
|
||||
val b = listOf(1,2,3,4,5)
|
||||
for ((index, c) in b.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Stream<String>) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: Stream<String>) {
|
||||
for ((index, a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: String) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: String) {
|
||||
for ((index, a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//IS_APPLICABLE: FALSE
|
||||
fun foo(bar: List<String>) {
|
||||
for (<caret>a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: FALSE
|
||||
//WITH_RUNTIME
|
||||
|
||||
fun foo(b: List<Int>) : Int {
|
||||
for ((i, <caret>c) in b.withIndices()) {
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: FALSE
|
||||
import java.util.LinkedList
|
||||
|
||||
fun Int.withIndices(): List<Pair<Int, Int>> = LinkedList<Pair<Int, Int>>()
|
||||
|
||||
fun foo(s: Int) {
|
||||
for ((index<caret>, a) in s.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: List<Int>) {
|
||||
for ((i : <caret>Int, b: Int) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: List<Int>) {
|
||||
for (b: Int in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: List<String>) {
|
||||
for ((i,<caret>a) in bar.withIndices()) {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
fun foo(bar: List<String>) {
|
||||
for (a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user