From f892e17d6bba3d948794b9b48ac72ad97709c01e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 5 May 2015 18:33:32 +0300 Subject: [PATCH] Refactored ConvertIfWithThrowToAssertIntention --- .../kotlin/idea/JetBundle.properties | 2 - .../ConvertIfWithThrowToAssertIntention.kt | 63 +++++++------------ .../branchedTransformations/IfThenUtils.kt | 22 ++----- .../intentions/IfThenToDoubleBangIntention.kt | 8 +-- .../intentions/IfThenToElvisIntention.kt | 9 ++- .../intentions/IfThenToSafeAccessIntention.kt | 2 +- 6 files changed, 38 insertions(+), 68 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index 92b4ca3b045..c8ca9b4994f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -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() with T::class replace.java.class.argument.family=Replace javaClass() with T::class diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertIfWithThrowToAssertIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertIfWithThrowToAssertIntention.kt index eb08b9dfafc..a86569b88b9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertIfWithThrowToAssertIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertIfWithThrowToAssertIntention.kt @@ -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("convert.if.with.throw.to.assert", javaClass()) { +public class ConvertIfWithThrowToAssertIntention : JetSelfTargetingOffsetIndependentIntention(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." } 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) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt index 68db5fffbb5..b7567318179 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt @@ -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 { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToDoubleBangIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToDoubleBangIntention.kt index 10c4f0ad2ed..364130e85ab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToDoubleBangIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToDoubleBangIntention.kt @@ -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) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToElvisIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToElvisIntention.kt index 4233d81f29e..8be3a09a0de 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToElvisIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToElvisIntention.kt @@ -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()) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt index e8b9be75bda..59d7580896f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt @@ -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