Further code improvements during review

This commit is contained in:
Valentin Kipyatkov
2015-04-16 19:06:44 +03:00
parent 1aa123dadb
commit 6421f48c07
17 changed files with 62 additions and 77 deletions
+1
View File
@@ -6,6 +6,7 @@
<w>inserter</w>
<w>pparent</w>
<w>processings</w>
<w>rbracket</w>
<w>rparenth</w>
<w>selectioner</w>
</words>
@@ -57,7 +57,8 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpressi
private fun isApplicableArrayAccess(element: JetArrayAccessExpression, caretOffset: Int): Boolean {
val lbracket = element.getLeftBracket() ?: return false
return lbracket.getTextRange().containsOffset(caretOffset)
val rbracket = element.getRightBracket() ?: return false
return lbracket.getTextRange().containsOffset(caretOffset) || rbracket.getTextRange().containsOffset(caretOffset)
}
private fun isApplicableCall(element: JetCallExpression, caretOffset: Int): Boolean {
@@ -25,7 +25,7 @@ public class AddBracesIntention : JetSelfTargetingIntention<JetExpression>(javaC
val expression = element.getTargetExpression(caretOffset) ?: return false
if (expression is JetBlockExpression) return false
val description = (expression.getParent() as JetContainerNode).description()
val description = (expression.getParent() as JetContainerNode).description()!!
setText("Add braces to '$description' statement")
return true
}
@@ -28,12 +28,13 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<JetCallExpression>(javaClass(), "Replace 'assert' with 'if' statement") {
override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean {
val callee = element.getCalleeExpression() ?: return false
if (callee.getText() != "assert") return false
if (!callee.getTextRange().containsOffset(caretOffset)) return false
val argumentSize = element.getValueArguments().size()
if (argumentSize !in 1..2) return false
if (element.getFunctionLiteralArguments().size() == 1 && argumentSize == 1) return false
val functionLiterals = element.getFunctionLiteralArguments()
if (functionLiterals.size() > 1) return false
if (functionLiterals.size() == 1 && argumentSize == 1) return false // "assert {...}" is incorrect
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).asString() == "kotlin.assert"
@@ -42,14 +43,14 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<Jet
override fun applyTo(element: JetCallExpression, editor: Editor) {
val args = element.getValueArguments()
val conditionText = args[0]?.getArgumentExpression()?.getText() ?: return
val functionLiterals = element.getFunctionLiteralArguments()
val functionLiteral = element.getFunctionLiteralArguments().singleOrNull()
val messageIsFunction = messageIsFunction(element)
val psiFactory = JetPsiFactory(element)
val messageExpr = when {
args.size() == 2 -> args[1]?.getArgumentExpression() ?: return
functionLiterals.isNotEmpty() -> functionLiterals.first()
functionLiteral != null -> functionLiteral!!
else -> psiFactory.createExpression("\"Assertion failed\"")
}
@@ -58,34 +59,27 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<Jet
// shorten java.lang.AssertionError
ShortenReferences.DEFAULT.process(ifExpression.getThen()!!)
fun replaceMessage() {
val thrownExpression = ((ifExpression.getThen() as JetBlockExpression).getStatements().single() as JetThrowExpression).getThrownExpression()
val assertionErrorCall = if (thrownExpression is JetCallExpression)
thrownExpression
else
(thrownExpression as JetDotQualifiedExpression).getSelectorExpression() as JetCallExpression
val ifCondition = ifExpression.getCondition() as JetPrefixExpression
ifCondition.getBaseExpression()!!.replace(psiFactory.createExpression(conditionText))
val message = psiFactory.createExpression(
if (messageIsFunction && messageExpr is JetCallableReferenceExpression) {
messageExpr.getCallableReference().getText() + "()"
}
else if (messageIsFunction) {
messageExpr.getText() + "()"
}
else {
messageExpr.getText()
}
)
assertionErrorCall.getValueArguments().single().getArgumentExpression()!!.replace(message)
}
val thrownExpression = ((ifExpression.getThen() as JetBlockExpression).getStatements().single() as JetThrowExpression).getThrownExpression()
val assertionErrorCall = if (thrownExpression is JetCallExpression)
thrownExpression
else
(thrownExpression as JetDotQualifiedExpression).getSelectorExpression() as JetCallExpression
fun replaceCondition() {
val ifCondition = ifExpression.getCondition() as JetPrefixExpression
ifCondition.getBaseExpression()!!.replace(psiFactory.createExpression(conditionText))
}
replaceCondition()
replaceMessage()
val message = psiFactory.createExpression(
if (messageIsFunction && messageExpr is JetCallableReferenceExpression) {
messageExpr.getCallableReference().getText() + "()"
}
else if (messageIsFunction) {
messageExpr.getText() + "()"
}
else {
messageExpr.getText()
}
)
assertionErrorCall.getValueArguments().single().getArgumentExpression()!!.replace(message)
simplifyConditionIfPossible(ifExpression)
}
@@ -20,44 +20,38 @@ import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
public class ConvertForEachToForLoopIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Replace with a for each loop") {
public class ConvertForEachToForLoopIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Replace with a for loop") {
override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean {
val data = extractData(element) ?: return false
if (data.functionLiteral.getValueParameters().size() > 1) return false
if (data.functionLiteral.getValueParameters().size() > 1 || data.functionLiteral.getBodyExpression() == null) return false
val functionLiteral = extractFunctionLiteral(element) ?: return false
if (functionLiteral.getValueParameters().size() > 1) return false
if (functionLiteral.getBodyExpression() == null) return false
if (caretOffset > data.functionLiteral.getTextRange().getStartOffset()) return false // not available within function literal body
if (caretOffset > functionLiteral.getTextRange().getStartOffset()) return false // not available within function literal body
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() == "kotlin.forEach"
if (DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() != "kotlin.forEach") return false
return resolvedCall.getCall().getExplicitReceiver() is ExpressionReceiver
}
override fun applyTo(element: JetExpression, editor: Editor) {
val data = extractData(element)!!
val loopText = generateLoopText(data.functionLiteral, data.receiver)
element.replace(JetPsiFactory(element).createExpression(loopText))
val functionLiteral = extractFunctionLiteral(element)!!
val receiver = element.getCall(element.analyze())!!.getExplicitReceiver() as ExpressionReceiver
val receiverExpression = receiver.getExpression()
val loopText = generateLoopText(functionLiteral, receiverExpression)
val expressionToReplace = receiverExpression.getParent() // it's correct for both JetDotQualifiedExpression and JetBinaryExpression
expressionToReplace.replace(JetPsiFactory(element).createExpression(loopText))
}
private data class Data(val functionLiteral: JetFunctionLiteralExpression, val receiver: JetExpression)
private fun extractData(element: JetExpression): Data? {
when (element) {
is JetDotQualifiedExpression -> {
val selector = element.getSelectorExpression() as? JetCallExpression ?: return null
val argument = selector.getValueArguments().singleOrNull() ?: return null
val functionLiteral = argument.getArgumentExpression() as? JetFunctionLiteralExpression ?: return null
return Data(functionLiteral, element.getReceiverExpression())
}
is JetBinaryExpression -> {
val functionLiteral = element.getRight() as? JetFunctionLiteralExpression ?: return null
return Data(functionLiteral, element.getLeft() ?: return null)
}
else -> return null
}
private fun extractFunctionLiteral(element: JetExpression): JetFunctionLiteralExpression? {
return when (element) {
is JetCallExpression -> element.getValueArguments().singleOrNull()?.getArgumentExpression()
is JetBinaryExpression -> element.getRight()
else -> null
} as? JetFunctionLiteralExpression
}
private fun generateLoopText(functionLiteral: JetFunctionLiteralExpression, receiver: JetExpression): String {
@@ -38,7 +38,7 @@ public class ConvertNegatedBooleanSequenceIntention : JetSelfTargetingOffsetInde
val operatorText = when(element.getOperationToken()) {
JetTokens.ANDAND -> JetTokens.OROR.getValue()
JetTokens.OROR -> JetTokens.ANDAND.getValue()
else -> throw IllegalArgumentException()
else -> throw IllegalArgumentException() // checked in isApplicableTo
}
val elements = splitBooleanSequence(element)!!
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import kotlin.platform.platformName
@@ -35,17 +35,10 @@ public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention<J
is JetBlockExpression -> body.getStatements().map { it.getText() }.joinToString("\n")
else -> body.getText()
}
val bodyText = buildFunctionLiteralBodyText(loopParameter, functionBodyText)
val bodyText = "${loopParameter.getText()} -> $functionBodyText"
val foreachExpression = factory.createExpression("x.forEach { $bodyText }") as JetDotQualifiedExpression
foreachExpression.getReceiverExpression().replace(element.getLoopRange()!!)
element.replace(foreachExpression)
}
private fun buildFunctionLiteralBodyText(loopParameter: JetParameter, functionBodyText: String): String {
return when {
loopParameter.getTypeReference() != null -> " (${loopParameter.getText()}) -> $functionBodyText"
else -> "${loopParameter.getText()} -> $functionBodyText"
}
}
}
@@ -32,7 +32,8 @@ public class RemoveBracesIntention : JetSelfTargetingIntention<JetBlockExpressio
val rBrace = element.getRBrace() ?: return false
if (!lBrace.getTextRange().containsOffset(caretOffset) && !rBrace.getTextRange().containsOffset(caretOffset)) return false
setText("Remove braces from '${containerNode.description()}' statement")
val description = containerNode.description() ?: return false
setText("Remove braces from '$description' statement")
return true
}
@@ -2,5 +2,5 @@
fun main() {
val x = 1..4
<caret>x.reverse().forEach { it }
x.reverse().forEach<caret> { it }
}
@@ -2,5 +2,5 @@
fun foo() {
val x = 1..4
<caret>x.forEach({ y -> y })
x.<caret>forEach({ y -> y })
}
@@ -2,5 +2,5 @@
fun foo() {
val x = 1..4
<caret>x.forEach { it }
x.<caret>forEach { it }
}
@@ -1,4 +1,4 @@
// WITH_RUNTIME
fun main() {
<caret>(1 rangeTo 2).forEach { x -> x }
(1 rangeTo 2).<caret>forEach { x -> x }
}
@@ -2,5 +2,5 @@
fun foo() {
val x = 1..4
<caret>x.forEach { it.equals(1) }
x.forEach<caret> { it.equals(1) }
}
@@ -2,5 +2,5 @@
fun foo() {
val x = 1..4
<caret>x.forEach<Int>({ it })
x.forEach<Int><caret>({ it })
}
@@ -2,5 +2,5 @@
fun main() {
val list = 1..4
list.forEach {(x: Int) -> x }
list.forEach { x: Int -> x }
}
@@ -2,5 +2,5 @@
fun main() {
val list = 1..4
list.forEach {(x: Int) -> 11 }
list.forEach { x: Int -> 11 }
}