diff --git a/idea/resources/inspectionDescriptions/CascadeIf.html b/idea/resources/inspectionDescriptions/CascadeIf.html
new file mode 100644
index 00000000000..49c125bcf97
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/CascadeIf.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports if statements with three or more branches that can be replaced with when.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index d563bac8406..3f3390b0da7 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2369,6 +2369,15 @@
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/CascadeIfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/CascadeIfInspection.kt
new file mode 100644
index 00000000000..09e6f5b0ba8
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/CascadeIfInspection.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2017 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.kotlin.idea.inspections
+
+import com.intellij.codeInspection.IntentionWrapper
+import com.intellij.codeInspection.LocalInspectionToolSession
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.codeInspection.ProblemsHolder
+import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfToWhenIntention
+import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isIfBranch
+import org.jetbrains.kotlin.idea.intentions.branches
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
+
+class CascadeIfInspection : AbstractKotlinInspection() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
+ object : KtVisitorVoid() {
+ override fun visitIfExpression(expression: KtIfExpression) {
+ super.visitIfExpression(expression)
+
+ val branches = expression.branches
+ if (branches.size <= 2) return
+ if (branches.any {
+ it == null ||
+ it.lastBlockStatementOrThis() is KtIfExpression
+ }) return
+
+ if (expression.isIfBranch()) return
+
+ if (expression.anyDescendantOfType {
+ it is KtBreakExpression || it is KtContinueExpression
+ }) return
+
+ holder.registerProblem(
+ expression.ifKeyword,
+ "Cascade if can be replaced with when",
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ IntentionWrapper(IfToWhenIntention(), expression.containingKtFile)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/.inspection b/idea/testData/inspectionsLocal/cascadeIf/.inspection
new file mode 100644
index 00000000000..53f620aa35e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.CascadeIfInspection
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/four.kt b/idea/testData/inspectionsLocal/cascadeIf/four.kt
new file mode 100644
index 00000000000..5e44f5595e0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/four.kt
@@ -0,0 +1,16 @@
+// PROBLEM: none
+
+fun foo(a: Boolean, b: Boolean, c: Boolean) {
+ if (a) {
+
+ }
+ else if (b) {
+
+ }
+ else if (c) {
+
+ }
+ else {
+
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/ifTree.kt b/idea/testData/inspectionsLocal/cascadeIf/ifTree.kt
new file mode 100644
index 00000000000..6c164121e3e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/ifTree.kt
@@ -0,0 +1,16 @@
+// PROBLEM: none
+
+fun println(s: String) {}
+
+fun foo(a: Boolean, b: Boolean) {
+ if (a) {
+ if (b) println("ab")
+ else println("a")
+ }
+ else if (b) {
+ println("b")
+ }
+ else {
+ println("none")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt b/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt
new file mode 100644
index 00000000000..68334ba4c26
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt
@@ -0,0 +1,15 @@
+fun println(s: String) {}
+
+fun test(x: Double, a: Boolean, b: Boolean) {
+ if (x > 0.0) {
+ if (a) {
+ println("a")
+ }
+ else if (b) {
+ println("b")
+ }
+ else {
+ println("none")
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt.after b/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt.after
new file mode 100644
index 00000000000..3db0953e3e8
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt.after
@@ -0,0 +1,11 @@
+fun println(s: String) {}
+
+fun test(x: Double, a: Boolean, b: Boolean) {
+ if (x > 0.0) {
+ when {
+ a -> println("a")
+ b -> println("b")
+ else -> println("none")
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/middleIf.kt b/idea/testData/inspectionsLocal/cascadeIf/middleIf.kt
new file mode 100644
index 00000000000..d419479d610
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/middleIf.kt
@@ -0,0 +1,15 @@
+// PROBLEM: none
+
+fun println(s: String) {}
+
+fun test(a: Boolean, b: Boolean) {
+ if (a) {
+ println("a")
+ }
+ else if (b) {
+ println("b")
+ }
+ else {
+ println("none")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/noSecondElse.kt b/idea/testData/inspectionsLocal/cascadeIf/noSecondElse.kt
new file mode 100644
index 00000000000..162ce5a76cb
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/noSecondElse.kt
@@ -0,0 +1,12 @@
+// PROBLEM: none
+
+fun println(s: String) {}
+
+fun test(a: Boolean, b: Boolean) {
+ if (a) {
+ println("a")
+ }
+ else if (b) {
+ println("b")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/normal.kt b/idea/testData/inspectionsLocal/cascadeIf/normal.kt
new file mode 100644
index 00000000000..9c25978881b
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/normal.kt
@@ -0,0 +1,13 @@
+fun println(s: String) {}
+
+fun test(a: Boolean, b: Boolean) {
+ if (a) {
+ println("a")
+ }
+ else if (b) {
+ println("b")
+ }
+ else {
+ println("none")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/normal.kt.after b/idea/testData/inspectionsLocal/cascadeIf/normal.kt.after
new file mode 100644
index 00000000000..0bf6de068aa
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/normal.kt.after
@@ -0,0 +1,9 @@
+fun println(s: String) {}
+
+fun test(a: Boolean, b: Boolean) {
+ when {
+ a -> println("a")
+ b -> println("b")
+ else -> println("none")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/shortIf.kt b/idea/testData/inspectionsLocal/cascadeIf/shortIf.kt
new file mode 100644
index 00000000000..41cea1b8064
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/shortIf.kt
@@ -0,0 +1,3 @@
+// PROBLEM: none
+
+val x = if (2 > 4) 1 else -1
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/cascadeIf/withBreak.kt b/idea/testData/inspectionsLocal/cascadeIf/withBreak.kt
new file mode 100644
index 00000000000..69f1dc0d364
--- /dev/null
+++ b/idea/testData/inspectionsLocal/cascadeIf/withBreak.kt
@@ -0,0 +1,17 @@
+// PROBLEM: none
+
+fun println(s: String) {}
+
+fun foo(size: Int, a: Boolean, b: Boolean) {
+ for (i in 1..size) {
+ if (a) {
+ break
+ }
+ else if (b) {
+ println("$i")
+ }
+ else {
+ println("*")
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index df1a0ac30a5..6783597d59a 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -51,6 +51,63 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
+ @TestMetadata("idea/testData/inspectionsLocal/cascadeIf")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class CascadeIf extends AbstractLocalInspectionTest {
+ public void testAllFilesPresentInCascadeIf() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/cascadeIf"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("four.kt")
+ public void testFour() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/four.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("ifTree.kt")
+ public void testIfTree() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/ifTree.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("insideOtherIf.kt")
+ public void testInsideOtherIf() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/insideOtherIf.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("middleIf.kt")
+ public void testMiddleIf() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/middleIf.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("noSecondElse.kt")
+ public void testNoSecondElse() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/noSecondElse.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("normal.kt")
+ public void testNormal() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/normal.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("shortIf.kt")
+ public void testShortIf() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/shortIf.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("withBreak.kt")
+ public void testWithBreak() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/withBreak.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/inspectionsLocal/collections")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)