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>inserter</w>
<w>pparent</w> <w>pparent</w>
<w>processings</w> <w>processings</w>
<w>rbracket</w>
<w>rparenth</w> <w>rparenth</w>
<w>selectioner</w> <w>selectioner</w>
</words> </words>
@@ -57,7 +57,8 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpressi
private fun isApplicableArrayAccess(element: JetArrayAccessExpression, caretOffset: Int): Boolean { private fun isApplicableArrayAccess(element: JetArrayAccessExpression, caretOffset: Int): Boolean {
val lbracket = element.getLeftBracket() ?: return false 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 { 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 val expression = element.getTargetExpression(caretOffset) ?: return false
if (expression is JetBlockExpression) 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") setText("Add braces to '$description' statement")
return true 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") { public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<JetCallExpression>(javaClass(), "Replace 'assert' with 'if' statement") {
override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean {
val callee = element.getCalleeExpression() ?: return false val callee = element.getCalleeExpression() ?: return false
if (callee.getText() != "assert") return false
if (!callee.getTextRange().containsOffset(caretOffset)) return false if (!callee.getTextRange().containsOffset(caretOffset)) return false
val argumentSize = element.getValueArguments().size() val argumentSize = element.getValueArguments().size()
if (argumentSize !in 1..2) return false 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 val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).asString() == "kotlin.assert" return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).asString() == "kotlin.assert"
@@ -42,14 +43,14 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<Jet
override fun applyTo(element: JetCallExpression, editor: Editor) { override fun applyTo(element: JetCallExpression, editor: Editor) {
val args = element.getValueArguments() val args = element.getValueArguments()
val conditionText = args[0]?.getArgumentExpression()?.getText() ?: return val conditionText = args[0]?.getArgumentExpression()?.getText() ?: return
val functionLiterals = element.getFunctionLiteralArguments() val functionLiteral = element.getFunctionLiteralArguments().singleOrNull()
val messageIsFunction = messageIsFunction(element) val messageIsFunction = messageIsFunction(element)
val psiFactory = JetPsiFactory(element) val psiFactory = JetPsiFactory(element)
val messageExpr = when { val messageExpr = when {
args.size() == 2 -> args[1]?.getArgumentExpression() ?: return args.size() == 2 -> args[1]?.getArgumentExpression() ?: return
functionLiterals.isNotEmpty() -> functionLiterals.first() functionLiteral != null -> functionLiteral!!
else -> psiFactory.createExpression("\"Assertion failed\"") else -> psiFactory.createExpression("\"Assertion failed\"")
} }
@@ -58,34 +59,27 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<Jet
// shorten java.lang.AssertionError // shorten java.lang.AssertionError
ShortenReferences.DEFAULT.process(ifExpression.getThen()!!) ShortenReferences.DEFAULT.process(ifExpression.getThen()!!)
fun replaceMessage() { val ifCondition = ifExpression.getCondition() as JetPrefixExpression
val thrownExpression = ((ifExpression.getThen() as JetBlockExpression).getStatements().single() as JetThrowExpression).getThrownExpression() ifCondition.getBaseExpression()!!.replace(psiFactory.createExpression(conditionText))
val assertionErrorCall = if (thrownExpression is JetCallExpression)
thrownExpression
else
(thrownExpression as JetDotQualifiedExpression).getSelectorExpression() as JetCallExpression
val message = psiFactory.createExpression( val thrownExpression = ((ifExpression.getThen() as JetBlockExpression).getStatements().single() as JetThrowExpression).getThrownExpression()
if (messageIsFunction && messageExpr is JetCallableReferenceExpression) { val assertionErrorCall = if (thrownExpression is JetCallExpression)
messageExpr.getCallableReference().getText() + "()" thrownExpression
} else
else if (messageIsFunction) { (thrownExpression as JetDotQualifiedExpression).getSelectorExpression() as JetCallExpression
messageExpr.getText() + "()"
}
else {
messageExpr.getText()
}
)
assertionErrorCall.getValueArguments().single().getArgumentExpression()!!.replace(message)
}
fun replaceCondition() { val message = psiFactory.createExpression(
val ifCondition = ifExpression.getCondition() as JetPrefixExpression if (messageIsFunction && messageExpr is JetCallableReferenceExpression) {
ifCondition.getBaseExpression()!!.replace(psiFactory.createExpression(conditionText)) messageExpr.getCallableReference().getText() + "()"
} }
else if (messageIsFunction) {
replaceCondition() messageExpr.getText() + "()"
replaceMessage() }
else {
messageExpr.getText()
}
)
assertionErrorCall.getValueArguments().single().getArgumentExpression()!!.replace(message)
simplifyConditionIfPossible(ifExpression) simplifyConditionIfPossible(ifExpression)
} }
@@ -20,44 +20,38 @@ import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils 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.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 { override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean {
val data = extractData(element) ?: return false val functionLiteral = extractFunctionLiteral(element) ?: return false
if (data.functionLiteral.getValueParameters().size() > 1) return false if (functionLiteral.getValueParameters().size() > 1) return false
if (data.functionLiteral.getValueParameters().size() > 1 || data.functionLiteral.getBodyExpression() == null) 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 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) { override fun applyTo(element: JetExpression, editor: Editor) {
val data = extractData(element)!! val functionLiteral = extractFunctionLiteral(element)!!
val loopText = generateLoopText(data.functionLiteral, data.receiver) val receiver = element.getCall(element.analyze())!!.getExplicitReceiver() as ExpressionReceiver
element.replace(JetPsiFactory(element).createExpression(loopText)) 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 extractFunctionLiteral(element: JetExpression): JetFunctionLiteralExpression? {
return when (element) {
private fun extractData(element: JetExpression): Data? { is JetCallExpression -> element.getValueArguments().singleOrNull()?.getArgumentExpression()
when (element) { is JetBinaryExpression -> element.getRight()
is JetDotQualifiedExpression -> { else -> null
val selector = element.getSelectorExpression() as? JetCallExpression ?: return null } as? JetFunctionLiteralExpression
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 generateLoopText(functionLiteral: JetFunctionLiteralExpression, receiver: JetExpression): String { private fun generateLoopText(functionLiteral: JetFunctionLiteralExpression, receiver: JetExpression): String {
@@ -38,7 +38,7 @@ public class ConvertNegatedBooleanSequenceIntention : JetSelfTargetingOffsetInde
val operatorText = when(element.getOperationToken()) { val operatorText = when(element.getOperationToken()) {
JetTokens.ANDAND -> JetTokens.OROR.getValue() JetTokens.ANDAND -> JetTokens.OROR.getValue()
JetTokens.OROR -> JetTokens.ANDAND.getValue() JetTokens.OROR -> JetTokens.ANDAND.getValue()
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException() // checked in isApplicableTo
} }
val elements = splitBooleanSequence(element)!! 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.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import kotlin.platform.platformName import kotlin.platform.platformName
@@ -35,17 +35,10 @@ public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention<J
is JetBlockExpression -> body.getStatements().map { it.getText() }.joinToString("\n") is JetBlockExpression -> body.getStatements().map { it.getText() }.joinToString("\n")
else -> body.getText() else -> body.getText()
} }
val bodyText = buildFunctionLiteralBodyText(loopParameter, functionBodyText) val bodyText = "${loopParameter.getText()} -> $functionBodyText"
val foreachExpression = factory.createExpression("x.forEach { $bodyText }") as JetDotQualifiedExpression val foreachExpression = factory.createExpression("x.forEach { $bodyText }") as JetDotQualifiedExpression
foreachExpression.getReceiverExpression().replace(element.getLoopRange()!!) foreachExpression.getReceiverExpression().replace(element.getLoopRange()!!)
element.replace(foreachExpression) 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 val rBrace = element.getRBrace() ?: return false
if (!lBrace.getTextRange().containsOffset(caretOffset) && !rBrace.getTextRange().containsOffset(caretOffset)) 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 return true
} }
@@ -2,5 +2,5 @@
fun main() { fun main() {
val x = 1..4 val x = 1..4
<caret>x.reverse().forEach { it } x.reverse().forEach<caret> { it }
} }
@@ -2,5 +2,5 @@
fun foo() { fun foo() {
val x = 1..4 val x = 1..4
<caret>x.forEach({ y -> y }) x.<caret>forEach({ y -> y })
} }
@@ -2,5 +2,5 @@
fun foo() { fun foo() {
val x = 1..4 val x = 1..4
<caret>x.forEach { it } x.<caret>forEach { it }
} }
@@ -1,4 +1,4 @@
// WITH_RUNTIME // WITH_RUNTIME
fun main() { fun main() {
<caret>(1 rangeTo 2).forEach { x -> x } (1 rangeTo 2).<caret>forEach { x -> x }
} }
@@ -2,5 +2,5 @@
fun foo() { fun foo() {
val x = 1..4 val x = 1..4
<caret>x.forEach { it.equals(1) } x.forEach<caret> { it.equals(1) }
} }
@@ -2,5 +2,5 @@
fun foo() { fun foo() {
val x = 1..4 val x = 1..4
<caret>x.forEach<Int>({ it }) x.forEach<Int><caret>({ it })
} }
@@ -2,5 +2,5 @@
fun main() { fun main() {
val list = 1..4 val list = 1..4
list.forEach {(x: Int) -> x } list.forEach { x: Int -> x }
} }
@@ -2,5 +2,5 @@
fun main() { fun main() {
val list = 1..4 val list = 1..4
list.forEach {(x: Int) -> 11 } list.forEach { x: Int -> 11 }
} }