Skip to content

Commit

Permalink
ConvertToForEachFunctionCallIntention - smaller availability range + …
Browse files Browse the repository at this point in the history
…code refactoring
  • Loading branch information
valentinkip committed Apr 16, 2015
1 parent c233579 commit fc8b046
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 38 deletions.
Expand Up @@ -333,8 +333,6 @@ invert.if.condition=Invert If Condition
invert.if.condition.family=Invert If Condition
convert.to.for.each.loop.intention=Replace with a for each loop
convert.to.for.each.loop.intention.family=Replace with a For Each Loop
convert.to.for.each.function.call.intention=Replace with a forEach function call
convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call
convert.to.string.template=Convert concatenation to template
convert.to.string.template.family=Convert Concatenation to Template

Expand Down
Expand Up @@ -16,52 +16,36 @@

package org.jetbrains.kotlin.idea.intentions

import org.jetbrains.kotlin.psi.JetForExpression
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetBlockExpression
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetOperationExpression
import org.jetbrains.kotlin.psi.*

public class ConvertToForEachFunctionCallIntention : JetSelfTargetingOffsetIndependentIntention<JetForExpression>("convert.to.for.each.function.call.intention", javaClass()) {
override fun isApplicableTo(element: JetForExpression): Boolean {
public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention<JetForExpression>(javaClass(), "Replace with a forEach function call") {
override fun isApplicableTo(element: JetForExpression, caretOffset: Int): Boolean {
val rParen = element.getRightParenthesis() ?: return false
if (caretOffset > rParen.getTextRange().getEndOffset()) return false // available only on the loop header, not in the body
return element.getLoopRange() != null && element.getLoopParameter() != null && element.getBody() != null
}

override fun applyTo(element: JetForExpression, editor: Editor) {
fun buildStatements(statements: List<JetElement>): String {
return when {
statements.isEmpty() -> ""
statements.size() == 1 -> statements[0].getText() ?: throw AssertionError("Statements in ForExpression shouldn't be empty: expressionText = ${element.getText()}")
else -> statements.fold(StringBuilder(), { acc, h -> acc.append("${h.getText()}\n") }).toString()
}
}
val body = element.getBody()!!
val loopParameter = element.getLoopParameter()!!
val factory = JetPsiFactory(element)

fun buildReplacementBodyText(loopParameter: JetParameter, functionBodyText: String): String {
return when {
loopParameter.getTypeReference() != null -> " (${loopParameter.getText()}) -> $functionBodyText"
else -> "${loopParameter.getText()} -> $functionBodyText"
}
val functionBodyText = when (body) {
is JetBlockExpression -> body.getStatements().map { it.getText() }.joinToString("\n")
else -> body.getText()
}
val bodyText = buildFunctionLiteralBodyText(loopParameter, functionBodyText)

fun buildReceiverText(element: JetForExpression): String {
val loopRange = element.getLoopRange()!!
val foreachExpression = factory.createExpression("x.forEach { $bodyText }") as JetDotQualifiedExpression
foreachExpression.getReceiverExpression().replace(element.getLoopRange()!!)
element.replace(foreachExpression)
}

return when (loopRange) {
is JetOperationExpression -> "(${loopRange.getText()})"
else -> loopRange.getText() ?: throw AssertionError("LoopRange in ForExpression shouldn't be empty: expressionText = ${element.getText()}")
}
private fun buildFunctionLiteralBodyText(loopParameter: JetParameter, functionBodyText: String): String {
return when {
loopParameter.getTypeReference() != null -> " (${loopParameter.getText()}) -> $functionBodyText"
else -> "${loopParameter.getText()} -> $functionBodyText"
}

val body = element.getBody()!!
val loopParameter = element.getLoopParameter()!!

val bodyText = buildReplacementBodyText(loopParameter, when (body) {
is JetBlockExpression -> buildStatements(body.getStatements())
else -> body.getText() ?: throw AssertionError("Body of ForExpression shouldn't be empty: expressionText = ${element.getText()}")
})

element.replace(JetPsiFactory(element).createExpression("${buildReceiverText(element)}.forEach { $bodyText }"))
}
}

0 comments on commit fc8b046

Please sign in to comment.