Intention to convert assert to an if with throw

This commit is contained in:
Tal Man
2014-04-10 13:17:09 -04:00
parent db38f420f3
commit 9cff3ba049
40 changed files with 402 additions and 1 deletions
@@ -392,6 +392,7 @@ fun main(args: Array<String>) {
model("intentions/simplifyBooleanWithConstants", testMethod = "doTestSimplifyBooleanWithConstants")
model("intentions/insertExplicitTypeArguments", testMethod = "doTestInsertExplicitTypeArguments")
model("intentions/removeExplicitTypeArguments", testMethod = "doTestRemoveExplicitTypeArguments")
model("intentions/convertAssertToIf", testMethod = "doTestConvertAssertToIfWithThrowIntention")
}
testClass(javaClass<AbstractJetInspectionTest>()) {
@@ -0,0 +1,5 @@
fun foo() {
<spot>if (!true) {
throw AssertionException("text")
}</spot>
}
@@ -0,0 +1,3 @@
fun foo() {
<spot>assert(true, "text")</spot>
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts an assert into an if statement that throws an exception if the condition is false
</body>
</html>
+5
View File
@@ -664,6 +664,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.ConvertAssertToIfWithThrowIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.jet.plugin.inspections.ExplicitGetInspection"
displayName="Explicit 'get'"
groupName="Kotlin"
@@ -297,6 +297,8 @@ insert.explicit.type.arguments=Add explicit type arguments
insert.explicit.type.arguments.family=Add explicit type arguments
remove.explicit.type.arguments=Remove explicit type arguments
remove.explicit.type.arguments.family=Remove explicit type arguments
convert.assert.to.if.with.throw=Convert assert to if with throw
convert.assert.to.if.with.throw.family=Convert assert to if with throw
property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses
@@ -0,0 +1,100 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.psi.JetPrefixExpression
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression
import org.jetbrains.jet.lang.psi.JetBinaryExpression
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
import org.jetbrains.jet.lang.psi.JetCallableReferenceExpression
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import kotlin.properties.Delegates
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<JetCallExpression>(
"convert.assert.to.if.with.throw", javaClass()) {
private var messageIsAFunction : Boolean by Delegates.notNull()
override fun isApplicableTo(element: JetCallExpression): Boolean {
if (element.getCalleeExpression()?.getText() != "assert") return false
val arguments = element.getValueArguments().size
val lambdas = element.getFunctionLiteralArguments().size
if (!(arguments == 1 && (lambdas == 1 || lambdas == 0)) && arguments != 2) return false
val context = AnalyzerFacadeWithCache.getContextForElement(element)
val resolvedCall = context[BindingContext.RESOLVED_CALL, element.getCalleeExpression()]
if (resolvedCall == null) return false
val valParameters = resolvedCall.getResultingDescriptor().getValueParameters()
if (valParameters.size > 1) {
messageIsAFunction = (valParameters[1].getType() != KotlinBuiltIns.getInstance().getAnyType())
} else {
messageIsAFunction = false
}
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() == "kotlin.assert"
}
override fun applyTo(element: JetCallExpression, editor: Editor) {
val args = element.getValueArguments()
val condition = args[0]?.getArgumentExpression()
val lambdas = element.getFunctionLiteralArguments()
val messageExpr: JetExpression?
if (args.size == 2) {
messageExpr = args[1]?.getArgumentExpression()
} else if (lambdas.isNotEmpty()) {
messageExpr = element.getFunctionLiteralArguments()[0]
} else {
messageExpr = JetPsiFactory.createExpression(element.getProject(), "\"Assertion failed\"")
}
if (condition == null || messageExpr == null) return
val message: String
if (messageIsAFunction && messageExpr is JetCallableReferenceExpression) {
message = "${messageExpr.getCallableReference().getText()}()"
} else if (messageIsAFunction) {
message = "${messageExpr.getText()}()"
} else {
message = "${messageExpr.getText()}"
}
val negatedCondition = JetPsiFactory.createExpression(element.getProject(), "!true") as JetPrefixExpression
negatedCondition.getBaseExpression()?.replace(condition)
val simplifier = SimplifyNegatedBinaryExpressionIntention()
if (simplifier.isApplicableTo(negatedCondition)) {
simplifier.applyTo(negatedCondition, editor)
}
val assertTypeRef = JetPsiFactory.createType(element.getProject(), "java.lang.AssertionError")
ShortenReferences.process(assertTypeRef)
val text = "if (${negatedCondition.getText()}) { throw ${assertTypeRef.getText()}(${message}) }"
element.replace(JetPsiFactory.createExpression(element.getProject(), text))
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true, "text")
}
class AssertionError
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw lang.AssertionError("text")
}
}
class AssertionError
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true && false, "text")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!(true && false)) {
throw AssertionError("text")
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(1 > 0, "text")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (1 <= 0) {
throw AssertionError("text")
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(0 != 1, "text")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (0 == 1) {
throw AssertionError("text")
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
val x = true
val y = false
<caret>assert(x || y, "text")
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun foo() {
val x = true
val y = false
if (!(x || y)) {
throw AssertionError("text")
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(bar(), "text")
}
fun bar(): Boolean = true
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun foo() {
if (!bar()) {
throw AssertionError("text")
}
}
fun bar(): Boolean = true
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true, ::message)
}
fun message(): String = "text"
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw AssertionError(message())
}
}
fun message(): String = "text"
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
fun foo() {
<caret>assert(true, "")
}
fun assert(b: Boolean, s: String) {}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
package pr442.kotlin
fun foo() {
<caret>assert(true, "")
}
fun assert(b: Boolean, s: String) {}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
// ERROR: No value passed for parameter value
fun foo() {
<caret>assert { "text" }
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true, { "text" })
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw AssertionError({ "text" }())
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true) { "text" }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw AssertionError({ "text" }())
}
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun foo() {
val f = { "text" }
<caret>assert(true, f)
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun foo() {
val f = { "text" }
if (!true) {
throw AssertionError(f())
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true)
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw AssertionError("Assertion failed")
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert((true && false), "text")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!(true && false)) {
throw AssertionError("text")
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo() {
<caret>assert(true, "text")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo() {
if (!true) {
throw AssertionError("text")
}
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun foo() {
val f = "text"
<caret>assert(true, f)
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun foo() {
val f = "text"
if (!true) {
throw AssertionError(f)
}
}
@@ -225,6 +225,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes
doTestIntention(path, new InsertExplicitTypeArguments());
}
public void doTestConvertAssertToIfWithThrowIntention(@NotNull String path) throws Exception {
doTestIntention(path, new ConvertAssertToIfWithThrowIntention());
}
public void doTestSplitIf(@NotNull String path) throws Exception {
doTestIntention(path, new SplitIfIntention());
}
@@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@InnerTestClasses({CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class, CodeTransformationTestGenerated.InsertExplicitTypeArguments.class, CodeTransformationTestGenerated.RemoveExplicitTypeArguments.class})
@InnerTestClasses({CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class, CodeTransformationTestGenerated.InsertExplicitTypeArguments.class, CodeTransformationTestGenerated.RemoveExplicitTypeArguments.class, CodeTransformationTestGenerated.ConvertAssertToIf.class})
public class CodeTransformationTestGenerated extends AbstractCodeTransformationTest {
@TestMetadata("idea/testData/intentions/branched/elvisToIfThen")
public static class ElvisToIfThen extends AbstractCodeTransformationTest {
@@ -3510,6 +3510,99 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
}
@TestMetadata("idea/testData/intentions/convertAssertToIf")
public static class ConvertAssertToIf extends AbstractCodeTransformationTest {
public void testAllFilesPresentInConvertAssertToIf() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/intentions/convertAssertToIf"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("assertErrorOverloaded.kt")
public void testAssertErrorOverloaded() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/assertErrorOverloaded.kt");
}
@TestMetadata("booleanCondition.kt")
public void testBooleanCondition() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/booleanCondition.kt");
}
@TestMetadata("booleanConditionSimplified.kt")
public void testBooleanConditionSimplified() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/booleanConditionSimplified.kt");
}
@TestMetadata("booleanConditionSimplified2.kt")
public void testBooleanConditionSimplified2() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/booleanConditionSimplified2.kt");
}
@TestMetadata("booleanConditionWithVariables.kt")
public void testBooleanConditionWithVariables() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/booleanConditionWithVariables.kt");
}
@TestMetadata("functionCallCondition.kt")
public void testFunctionCallCondition() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/functionCallCondition.kt");
}
@TestMetadata("functionMessageInsideParentheses.kt")
public void testFunctionMessageInsideParentheses() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/functionMessageInsideParentheses.kt");
}
@TestMetadata("inapplicableAssertOverloaded.kt")
public void testInapplicableAssertOverloaded() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/inapplicableAssertOverloaded.kt");
}
@TestMetadata("inapplicableAssertOverloadedWithPackage.kt")
public void testInapplicableAssertOverloadedWithPackage() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/inapplicableAssertOverloadedWithPackage.kt");
}
@TestMetadata("inapplicableNoCondition.kt")
public void testInapplicableNoCondition() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/inapplicableNoCondition.kt");
}
@TestMetadata("lambdaMessageInsideParentheses.kt")
public void testLambdaMessageInsideParentheses() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/lambdaMessageInsideParentheses.kt");
}
@TestMetadata("lambdaMessageOutsideParentheses.kt")
public void testLambdaMessageOutsideParentheses() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/lambdaMessageOutsideParentheses.kt");
}
@TestMetadata("lambdaVariable.kt")
public void testLambdaVariable() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/lambdaVariable.kt");
}
@TestMetadata("noMessage.kt")
public void testNoMessage() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/noMessage.kt");
}
@TestMetadata("parenthesizedCondition.kt")
public void testParenthesizedCondition() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/parenthesizedCondition.kt");
}
@TestMetadata("simpleConvert.kt")
public void testSimpleConvert() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/simpleConvert.kt");
}
@TestMetadata("stringVariable.kt")
public void testStringVariable() throws Exception {
doTestConvertAssertToIfWithThrowIntention("idea/testData/intentions/convertAssertToIf/stringVariable.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("CodeTransformationTestGenerated");
suite.addTestSuite(ElvisToIfThen.class);
@@ -3562,6 +3655,7 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
suite.addTestSuite(SimplifyBooleanWithConstants.class);
suite.addTestSuite(InsertExplicitTypeArguments.class);
suite.addTestSuite(RemoveExplicitTypeArguments.class);
suite.addTestSuite(ConvertAssertToIf.class);
return suite;
}
}