Refactored ConvertIfWithThrowToAssertIntention

This commit is contained in:
Valentin Kipyatkov
2015-05-05 18:33:32 +03:00
parent 392a1f52eb
commit f892e17d6b
6 changed files with 38 additions and 68 deletions
@@ -286,8 +286,6 @@ add.name.to.argument.action=Add name to argument...
add.name.to.parameter.name.chooser.title=Choose parameter name
remove.explicit.type.arguments=Remove explicit type arguments
remove.explicit.type.arguments.family=Remove Explicit Type Arguments
convert.if.with.throw.to.assert=Replace 'if' with 'assert' statement
convert.if.with.throw.to.assert.family=Replace 'if' with 'assert' Statement
replace.java.class.argument=Replace javaClass<T>() with T::class
replace.java.class.argument.family=Replace javaClass<T>() with T::class
@@ -17,75 +17,54 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.JetCallExpression
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetPrefixExpression
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.psi.JetIfExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.extractExpressionIfSingle
import org.jetbrains.kotlin.psi.JetThrowExpression
import org.jetbrains.kotlin.psi.JetDotQualifiedExpression
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlock
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.copied
import org.jetbrains.kotlin.psi.psiUtil.replaced
public class ConvertIfWithThrowToAssertIntention :
JetSelfTargetingOffsetIndependentIntention<JetIfExpression>("convert.if.with.throw.to.assert", javaClass()) {
public class ConvertIfWithThrowToAssertIntention : JetSelfTargetingOffsetIndependentIntention<JetIfExpression>(javaClass(), "Replace 'if' with 'assert' statement") {
override fun isApplicableTo(element: JetIfExpression): Boolean {
if (element.getElse() != null) return false
val thenExpr = element.getThen()?.extractExpressionIfSingle()
if (thenExpr !is JetThrowExpression) return false
val thrownExpr = getSelector(thenExpr.getThrownExpression())
val throwExpr = element.getThen()?.unwrapBlock() as? JetThrowExpression
val thrownExpr = getSelector(throwExpr?.getThrownExpression())
if (thrownExpr !is JetCallExpression) return false
if (thrownExpr.getCalleeExpression()?.getText() != "AssertionError") return false
val paramAmount = thrownExpr.getValueArguments().size
if (paramAmount > 1) return false
val context = thenExpr.analyze()
val resolvedCall = thrownExpr.getResolvedCall(context)
if (resolvedCall == null) return false
if (thrownExpr.getValueArguments().size() > 1) return false
val resolvedCall = thrownExpr.getResolvedCall(thrownExpr.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() == "java.lang.AssertionError.<init>"
}
override fun applyTo(element: JetIfExpression, editor: Editor) {
val condition = element.getCondition()
if (condition == null) return
val condition = element.getCondition() ?: return
val thenExpr = element.getThen()?.extractExpressionIfSingle() as JetThrowExpression
val thenExpr = element.getThen()?.unwrapBlock() as JetThrowExpression
val thrownExpr = getSelector(thenExpr.getThrownExpression()) as JetCallExpression
val args = thrownExpr.getValueArguments()
val paramText =
if (args.isNotEmpty()) {
val param = args.first!!.getArgumentExpression()!!
if (param.isNullExpression()) "" else ", ${param.getText()}"
} else {
""
}
val psiFactory = JetPsiFactory(element)
val negatedCondition = psiFactory.createExpression("!true") as JetPrefixExpression
negatedCondition.getBaseExpression()!!.replace(condition)
condition.replace(negatedCondition)
condition.replace(psiFactory.createExpressionByPattern("!$0", condition))
val newCondition = element.getCondition() as JetPrefixExpression
var newCondition = element.getCondition()!!
val simplifier = SimplifyNegatedBinaryExpressionIntention()
if (simplifier.isApplicableTo(newCondition)) {
if (simplifier.isApplicableTo(newCondition as JetPrefixExpression)) {
simplifier.applyTo(newCondition, editor)
newCondition = element.getCondition()!!
}
val assertText = "kotlin.assert(${element.getCondition()?.getText()} $paramText)"
val assertExpr = psiFactory.createExpression(assertText)
val arg = thrownExpr.getValueArguments().singleOrNull()?.getArgumentExpression()
val assertExpr = if (arg != null && !arg.isNullExpression())
psiFactory.createExpressionByPattern("kotlin.assert($0, $1)", newCondition, arg)
else
psiFactory.createExpressionByPattern("kotlin.assert($0)", newCondition)
val newExpr = element.replace(assertExpr) as JetExpression
val newExpr = element.replaced(assertExpr)
ShortenReferences.DEFAULT.process(newExpr)
}
@@ -48,15 +48,12 @@ fun JetBinaryExpression.comparesNonNullToNull(): Boolean {
return leftIsNull != rightIsNull && (operationToken == JetTokens.EQEQ || operationToken == JetTokens.EXCLEQ)
}
fun JetExpression.extractExpressionIfSingle(): JetExpression? {
val innerExpression = JetPsiUtil.deparenthesize(this)
fun JetExpression.unwrapBlock(): JetExpression {
val innerExpression = JetPsiUtil.safeDeparenthesize(this)
if (innerExpression is JetBlockExpression) {
return if (innerExpression.getStatements().size() == 1)
JetPsiUtil.deparenthesize(innerExpression.getStatements().firstOrNull() as? JetExpression)
else
null
val statement = innerExpression.getStatements().singleOrNull() as? JetExpression ?: return this
return JetPsiUtil.safeDeparenthesize(statement)
}
return innerExpression
}
@@ -71,12 +68,10 @@ fun JetBinaryExpression.getNonNullExpression(): JetExpression? = when {
null
}
fun JetExpression.isNullExpression(): Boolean = this.extractExpressionIfSingle()?.getText() == "null"
fun JetExpression.isNullExpression(): Boolean = this.unwrapBlock().getText() == "null"
fun JetExpression.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is JetBlockExpression && this.getStatements().isEmpty()
fun JetExpression.isThrowExpression(): Boolean = this.extractExpressionIfSingle() is JetThrowExpression
fun JetThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean {
val thrownExpression = this.getThrownExpression()
if (thrownExpression !is JetCallExpression) return false
@@ -90,13 +85,8 @@ fun JetThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean {
return (exceptionName == NULL_PTR_EXCEPTION_FQ || exceptionName == KOTLIN_NULL_PTR_EXCEPTION_FQ) && thrownExpression.getValueArguments().isEmpty()
}
fun JetExpression.isNotNullExpression(): Boolean {
val innerExpression = this.extractExpressionIfSingle()
return innerExpression != null && innerExpression.getText() != "null"
}
fun JetExpression.evaluatesTo(other: JetExpression): Boolean {
return this.extractExpressionIfSingle()?.getText() == other.getText()
return this.unwrapBlock().getText() == other.getText()
}
fun JetExpression.convertToIfNotNullExpression(conditionLhs: JetExpression, thenClause: JetExpression, elseClause: JetExpression?): JetIfExpression {
@@ -44,12 +44,10 @@ public class IfThenToDoubleBangIntention : JetSelfTargetingOffsetIndependentInte
val throwExpression =
when (token) {
JetTokens.EQEQ -> thenClause?.extractExpressionIfSingle()
JetTokens.EXCLEQ -> elseClause?.extractExpressionIfSingle()
JetTokens.EQEQ -> thenClause?.unwrapBlock()
JetTokens.EXCLEQ -> elseClause?.unwrapBlock()
else -> throw IllegalStateException("Token must be either '!=' or '==' ")
} as? JetThrowExpression
if (throwExpression == null) return false
} as? JetThrowExpression ?: return false
val matchingClause =
when (token) {
@@ -47,6 +47,11 @@ public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention
}
}
private fun JetExpression.isNotNullExpression(): Boolean {
val innerExpression = this.unwrapBlock()
return innerExpression !is JetBlockExpression && innerExpression.getText() != "null"
}
override fun applyTo(element: JetIfExpression, editor: Editor) {
val elvis = applyTo(element)
elvis.inlineLeftSideIfApplicableWithPrompt(editor)
@@ -57,8 +62,8 @@ public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention
val thenClause = checkNotNull(element.getThen(), "The then clause cannot be null")
val elseClause = checkNotNull(element.getElse(), "The else clause cannot be null")
val thenExpression = checkNotNull(thenClause.extractExpressionIfSingle(), "Then clause must contain expression")
val elseExpression = checkNotNull(elseClause.extractExpressionIfSingle(), "Else clause must contain expression")
val thenExpression = thenClause.unwrapBlock()
val elseExpression = elseClause.unwrapBlock()
val (left, right) =
when(condition.getOperationToken()) {
@@ -81,7 +81,7 @@ public class IfThenToSafeAccessIntention : JetSelfTargetingOffsetIndependentInte
findSelectorExpressionInClause(clause, receiverExpression) != null
fun findSelectorExpressionInClause(clause: JetExpression, receiverExpression: JetExpression): JetExpression? {
val expression = clause.extractExpressionIfSingle() as? JetDotQualifiedExpression
val expression = clause.unwrapBlock() as? JetDotQualifiedExpression
if (expression?.getReceiverExpression()?.getText() != receiverExpression.getText()) return null