From 6a6c67dd5f0f4865b525494b89e68708e084c433 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 10 Aug 2016 14:26:45 +0300 Subject: [PATCH] Convert to expression body is forbidden for if without else #KT-12951 Fixed --- .../ConvertToExpressionBodyIntention.kt | 3 ++ .../jetbrains/kotlin/idea/intentions/Utils.kt | 9 ++++ .../elvisIfElseUnit.kt | 9 ++++ .../elvisIfElseUnit.kt.after | 7 ++++ .../convertToExpressionBody/elvisIfUnit.kt | 9 ++++ .../convertToExpressionBody/ifElseUnit.kt | 7 ++++ .../ifElseUnit.kt.after | 5 +++ .../convertToExpressionBody/ifUnit.kt | 7 ++++ .../convertToExpressionBody/lambdaIfUnit.kt | 12 ++++++ .../lambdaIfUnit.kt.after | 10 +++++ .../whenIfUnitExhaustive.kt | 10 +++++ .../whenIfUnitExhaustive.kt.after | 8 ++++ .../whenIfUnitNonExhaustive.kt | 10 +++++ .../intentions/IntentionTestGenerated.java | 42 +++++++++++++++++++ 14 files changed, 148 insertions(+) create mode 100644 idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt.after create mode 100644 idea/testData/intentions/convertToExpressionBody/elvisIfUnit.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt.after create mode 100644 idea/testData/intentions/convertToExpressionBody/ifUnit.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt.after create mode 100644 idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt create mode 100644 idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt.after create mode 100644 idea/testData/intentions/convertToExpressionBody/whenIfUnitNonExhaustive.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt index f1dfaf13405..9334d6fcc85 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt @@ -109,6 +109,9 @@ class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIntention val isUnit = KotlinBuiltIns.isUnit(expressionType) if (!isUnit && !KotlinBuiltIns.isNothing(expressionType)) return null if (isUnit) { + if (statement.hasResultingIfWithoutElse()) { + return null + } val resultingWhens = statement.resultingWhens() if (resultingWhens.any { it.elseExpression == null && context.get(BindingContext.EXHAUSTIVE_WHEN, it) != true}) { return null diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index ee81e359438..7c9ac25d722 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -141,6 +141,15 @@ fun KtExpression.resultingWhens(): List = when (this) { else -> listOf() } +fun KtExpression?.hasResultingIfWithoutElse(): Boolean = when (this) { + is KtIfExpression -> `else` == null || then.hasResultingIfWithoutElse() || `else`.hasResultingIfWithoutElse() + is KtWhenExpression -> entries.any { it.expression.hasResultingIfWithoutElse() } + is KtBinaryExpression -> left.hasResultingIfWithoutElse() || right.hasResultingIfWithoutElse() + is KtUnaryExpression -> baseExpression.hasResultingIfWithoutElse() + is KtBlockExpression -> statements.lastOrNull().hasResultingIfWithoutElse() + else -> false +} + private fun KtExpression.specialNegation(): KtExpression? { val factory = KtPsiFactory(this) when (this) { diff --git a/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt b/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt new file mode 100644 index 00000000000..e4c6531c4c1 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: true + +fun nullable() {} + +fun bar() {} + +fun foo(f: Boolean) { + nullable() ?: if (f) bar() else bar() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt.after b/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt.after new file mode 100644 index 00000000000..4666e3e6d92 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt.after @@ -0,0 +1,7 @@ +// IS_APPLICABLE: true + +fun nullable() {} + +fun bar() {} + +fun foo(f: Boolean) = nullable() ?: if (f) bar() else bar() diff --git a/idea/testData/intentions/convertToExpressionBody/elvisIfUnit.kt b/idea/testData/intentions/convertToExpressionBody/elvisIfUnit.kt new file mode 100644 index 00000000000..0fd4a72843e --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/elvisIfUnit.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false + +fun nullable() {} + +fun bar() {} + +fun foo(f: Boolean) { + nullable() ?: if (f) bar() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt b/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt new file mode 100644 index 00000000000..d85f7c03649 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: true + +fun bar() {} + +fun foo(f: Boolean) { + if (f) bar() else bar() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt.after b/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt.after new file mode 100644 index 00000000000..c0f5a3e5182 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt.after @@ -0,0 +1,5 @@ +// IS_APPLICABLE: true + +fun bar() {} + +fun foo(f: Boolean) = if (f) bar() else bar() diff --git a/idea/testData/intentions/convertToExpressionBody/ifUnit.kt b/idea/testData/intentions/convertToExpressionBody/ifUnit.kt new file mode 100644 index 00000000000..09b9ab321ee --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/ifUnit.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false + +fun bar() {} + +fun foo(f: Boolean) { + if (f) bar() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt b/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt new file mode 100644 index 00000000000..9b0ee7970ce --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt @@ -0,0 +1,12 @@ +// IS_APPLICABLE: true + +fun run(f: () -> T) = f() +fun whenExpr(flag: Boolean) { + run { + println("run") + if (flag) { + println("flag") + } + } +} +fun println(s: String) {} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt.after b/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt.after new file mode 100644 index 00000000000..b09c41758f5 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt.after @@ -0,0 +1,10 @@ +// IS_APPLICABLE: true + +fun run(f: () -> T) = f() +fun whenExpr(flag: Boolean) = run { + println("run") + if (flag) { + println("flag") + } +} +fun println(s: String) {} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt b/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt new file mode 100644 index 00000000000..4e9d3821f77 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: true +enum class AccessMode { READ, WRITE, RW } +fun whenExpr(mode: Boolean, access: AccessMode) { + when (access) { + AccessMode.READ -> if (mode) println("read") else println("noread") + AccessMode.WRITE -> if (mode) println("write") else println("nowrite") + AccessMode.RW -> if (mode) println("both") else println("no both") + } +} +fun println(s: String) {} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt.after b/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt.after new file mode 100644 index 00000000000..774bec4f7e0 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt.after @@ -0,0 +1,8 @@ +// IS_APPLICABLE: true +enum class AccessMode { READ, WRITE, RW } +fun whenExpr(mode: Boolean, access: AccessMode) = when (access) { + AccessMode.READ -> if (mode) println("read") else println("noread") + AccessMode.WRITE -> if (mode) println("write") else println("nowrite") + AccessMode.RW -> if (mode) println("both") else println("no both") +} +fun println(s: String) {} \ No newline at end of file diff --git a/idea/testData/intentions/convertToExpressionBody/whenIfUnitNonExhaustive.kt b/idea/testData/intentions/convertToExpressionBody/whenIfUnitNonExhaustive.kt new file mode 100644 index 00000000000..7d522cff374 --- /dev/null +++ b/idea/testData/intentions/convertToExpressionBody/whenIfUnitNonExhaustive.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +enum class AccessMode { READ, WRITE, RW } +fun whenExpr(mode: Boolean, access: AccessMode) { + when (access) { + AccessMode.READ -> if (mode) println("read") else println("noread") + AccessMode.WRITE -> if (mode) println("write") + AccessMode.RW -> if (mode) println("both") else println("no both") + } +} +fun println(s: String) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 2594b39009e..bd3acbec144 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -4774,6 +4774,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("elvisIfElseUnit.kt") + public void testElvisIfElseUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/elvisIfElseUnit.kt"); + doTest(fileName); + } + + @TestMetadata("elvisIfUnit.kt") + public void testElvisIfUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/elvisIfUnit.kt"); + doTest(fileName); + } + @TestMetadata("elvisWhenUnitNonExhaustive.kt") public void testElvisWhenUnitNonExhaustive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/elvisWhenUnitNonExhaustive.kt"); @@ -4852,6 +4864,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("ifElseUnit.kt") + public void testIfElseUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/ifElseUnit.kt"); + doTest(fileName); + } + + @TestMetadata("ifUnit.kt") + public void testIfUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/ifUnit.kt"); + doTest(fileName); + } + @TestMetadata("ifWhenUnitExhaustive.kt") public void testIfWhenUnitExhaustive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/ifWhenUnitExhaustive.kt"); @@ -4864,6 +4888,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("lambdaIfUnit.kt") + public void testLambdaIfUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/lambdaIfUnit.kt"); + doTest(fileName); + } + @TestMetadata("lambdaWhenUnitNonExhaustive.kt") public void testLambdaWhenUnitNonExhaustive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/lambdaWhenUnitNonExhaustive.kt"); @@ -4900,6 +4930,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("whenIfUnitExhaustive.kt") + public void testWhenIfUnitExhaustive() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/whenIfUnitExhaustive.kt"); + doTest(fileName); + } + + @TestMetadata("whenIfUnitNonExhaustive.kt") + public void testWhenIfUnitNonExhaustive() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/whenIfUnitNonExhaustive.kt"); + doTest(fileName); + } + @TestMetadata("whenUnitExhaustive.kt") public void testWhenUnitExhaustive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertToExpressionBody/whenUnitExhaustive.kt");