diff --git a/idea/resources/inspectionDescriptions/ConstantConditionIf.html b/idea/resources/inspectionDescriptions/ConstantConditionIf.html
new file mode 100644
index 00000000000..10f7633dc62
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/ConstantConditionIf.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports 'if' expressions whose condition is constant and therefore the expression can be simplified.
+
+
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 9da82dee92f..12719ca678c 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2387,6 +2387,15 @@
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt
new file mode 100644
index 00000000000..9d8b6b6525a
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.LocalQuickFix
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElementVisitor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.core.replaced
+import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
+import org.jetbrains.kotlin.resolve.calls.callUtil.getType
+import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+class ConstantConditionIfInspection : AbstractKotlinInspection() {
+
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
+ return object : KtVisitorVoid() {
+ override fun visitIfExpression(expression: KtIfExpression) {
+ super.visitIfExpression(expression)
+
+ val condition = expression.condition ?: return
+
+ val context = condition.analyze(BodyResolveMode.PARTIAL)
+ val constantValue = condition.constantBooleanValue(context) ?: return
+
+ val fixes = mutableListOf()
+
+ if (expression.branch(constantValue) != null) {
+ fixes += SimplifyFix(constantValue, expression.isUsedAsExpression(context))
+ }
+
+ if (!constantValue && expression.`else` == null) {
+ fixes += RemoveFix()
+ }
+
+ holder.registerProblem(condition,
+ "Condition is always '$constantValue'",
+ *fixes.toTypedArray())
+ }
+ }
+ }
+
+ private class SimplifyFix(
+ private val conditionValue: Boolean,
+ private val isUsedAsExpression: Boolean
+ ) : LocalQuickFix {
+ override fun getFamilyName() = name
+
+ override fun getName() = "Simplify expression"
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ val ifExpression = descriptor.psiElement.getParentOfType(strict = true) ?: return
+ val caretModel = ifExpression.findExistingEditor()?.caretModel
+
+ val branch = ifExpression.branch(conditionValue)?.unwrapBlockOrParenthesis() ?: return
+
+ val lastExpression = when {
+ branch !is KtBlockExpression -> ifExpression.replaced(branch)
+ isUsedAsExpression -> {
+ val factory = KtPsiFactory(ifExpression)
+ ifExpression.replaced(factory.createExpressionByPattern("run $0", branch.text))
+ }
+ else -> {
+ val firstChild = branch.firstChild.nextSibling
+
+ if (firstChild == branch.lastChild) {
+ ifExpression.delete()
+ }
+ else {
+ val lastChild = branch.lastChild.prevSibling
+ val parent = ifExpression.parent
+ parent.addRangeAfter(firstChild, lastChild, ifExpression)
+ ifExpression.delete()
+ }
+
+ null
+ }
+ }
+
+ caretModel?.moveToOffset(lastExpression?.startOffset ?: return)
+ }
+ }
+
+ private class RemoveFix : LocalQuickFix {
+ override fun getFamilyName() = name
+
+ override fun getName() = "Delete expression"
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ val ifExpression = descriptor.psiElement.getParentOfType(strict = true) ?: return
+ ifExpression.delete()
+ }
+ }
+
+ private companion object {
+ private fun KtIfExpression.branch(thenBranch: Boolean) = if (thenBranch) then else `else`
+
+ private fun KtExpression.constantBooleanValue(context: BindingContext): Boolean? {
+ val type = getType(context) ?: return null
+
+ val constantValue = ConstantExpressionEvaluator.getConstant(this, context)?.toConstantValue(type)
+ return constantValue?.value as? Boolean
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspections/constantConditionIf/inspectionData/expected.xml b/idea/testData/inspections/constantConditionIf/inspectionData/expected.xml
new file mode 100644
index 00000000000..d639626e8d3
--- /dev/null
+++ b/idea/testData/inspections/constantConditionIf/inspectionData/expected.xml
@@ -0,0 +1,42 @@
+
+
+ test.kt
+ 7
+ light_idea_test_case
+
+ Condition of 'if' expression is constant
+ Condition is always 'true'
+
+
+ test.kt
+ 9
+ light_idea_test_case
+
+ Condition of 'if' expression is constant
+ Condition is always 'false'
+
+
+ test.kt
+ 14
+ light_idea_test_case
+
+ Condition of 'if' expression is constant
+ Condition is always 'true'
+
+
+ test.kt
+ 20
+ light_idea_test_case
+
+ Condition of 'if' expression is constant
+ Condition is always 'false'
+
+
+ test.kt
+ 24
+ light_idea_test_case
+
+ Condition of 'if' expression is constant
+ Condition is always 'true'
+
+
\ No newline at end of file
diff --git a/idea/testData/inspections/constantConditionIf/inspectionData/inspections.test b/idea/testData/inspections/constantConditionIf/inspectionData/inspections.test
new file mode 100644
index 00000000000..146c170c7c4
--- /dev/null
+++ b/idea/testData/inspections/constantConditionIf/inspectionData/inspections.test
@@ -0,0 +1 @@
+// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.ConstantConditionIfInspection
\ No newline at end of file
diff --git a/idea/testData/inspections/constantConditionIf/test.kt b/idea/testData/inspections/constantConditionIf/test.kt
new file mode 100644
index 00000000000..e6b763eeffd
--- /dev/null
+++ b/idea/testData/inspections/constantConditionIf/test.kt
@@ -0,0 +1,28 @@
+fun foo(x: Int) {}
+fun baz(s: String) {}
+
+const val TRUE = true
+
+fun bar() {
+ foo(if (TRUE) 1 else 2)
+
+ foo(if (false && TRUE) {
+ baz("a")
+ 1
+ } else 2)
+
+ if (true) {
+ //asd
+ baz("a")
+ baz("b")
+ }
+
+ if (false) {
+ baz("a")
+ }
+
+ foo(if (TRUE) {
+ baz("a")
+ 1
+ } else 2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/.inspection b/idea/testData/inspectionsLocal/constantConditionIf/.inspection
new file mode 100644
index 00000000000..f06df936fa7
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.ConstantConditionIfInspection
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/delete.kt b/idea/testData/inspectionsLocal/constantConditionIf/delete.kt
new file mode 100644
index 00000000000..191b95875ab
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/delete.kt
@@ -0,0 +1,8 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ if (false) {
+ foo(1)
+ foo(2)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/delete.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/delete.kt.after
new file mode 100644
index 00000000000..38e0afc1da9
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/delete.kt.after
@@ -0,0 +1,4 @@
+fun foo(x: Int) {}
+
+fun bar() {
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/expression.kt b/idea/testData/inspectionsLocal/constantConditionIf/expression.kt
new file mode 100644
index 00000000000..4c355519f65
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/expression.kt
@@ -0,0 +1,11 @@
+// WITH_RUNTIME
+
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(if (true) {
+ foo(1)
+ foo(2)
+ 1
+ } else 2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/expression.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/expression.kt.after
new file mode 100644
index 00000000000..c0e4ab06db7
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/expression.kt.after
@@ -0,0 +1,11 @@
+// WITH_RUNTIME
+
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(run {
+ foo(1)
+ foo(2)
+ 1
+ })
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt b/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt
new file mode 100644
index 00000000000..f5f240b304a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt
@@ -0,0 +1,6 @@
+fun foo(s: String) {}
+
+fun bar() {
+ if (true) {
+ } else 2
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt.after
new file mode 100644
index 00000000000..36d056ff2fa
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt.after
@@ -0,0 +1,5 @@
+fun foo(s: String) {}
+
+fun bar() {
+
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt b/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt
new file mode 100644
index 00000000000..c610b52a01a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(if (true) { 1 } else 2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt.after
new file mode 100644
index 00000000000..3c9abb1728b
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt.after
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(1)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt b/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt
new file mode 100644
index 00000000000..dec225ab02b
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(if (false) 1 else 2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt.after
new file mode 100644
index 00000000000..3d6b0e57f74
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt.after
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt b/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt
new file mode 100644
index 00000000000..f294e957ba4
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(if (true) 1 else 2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt.after
new file mode 100644
index 00000000000..3c9abb1728b
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt.after
@@ -0,0 +1,5 @@
+fun foo(x: Int) {}
+
+fun bar() {
+ foo(1)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/statement.kt b/idea/testData/inspectionsLocal/constantConditionIf/statement.kt
new file mode 100644
index 00000000000..d000660c0b5
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/statement.kt
@@ -0,0 +1,8 @@
+fun foo(s: String) {}
+
+fun bar() {
+ if (true) {
+ foo("a")
+ foo("b")
+ } else 2
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/constantConditionIf/statement.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/statement.kt.after
new file mode 100644
index 00000000000..9db0fce960c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/constantConditionIf/statement.kt.after
@@ -0,0 +1,6 @@
+fun foo(s: String) {}
+
+fun bar() {
+ foo("a")
+ foo("b")
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
index 6fc821ef3aa..65b33c2f867 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
@@ -161,6 +161,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
doTest(fileName);
}
+ @TestMetadata("constantConditionIf/inspectionData/inspections.test")
+ public void testConstantConditionIf_inspectionData_Inspections_test() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/constantConditionIf/inspectionData/inspections.test");
+ doTest(fileName);
+ }
+
@TestMetadata("convertLambdaToReference/inspectionData/inspections.test")
public void testConvertLambdaToReference_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/convertLambdaToReference/inspectionData/inspections.test");
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index e2c39f4e9fa..d7fbf2a6089 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -408,6 +408,57 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
+ @TestMetadata("idea/testData/inspectionsLocal/constantConditionIf")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ConstantConditionIf extends AbstractLocalInspectionTest {
+ public void testAllFilesPresentInConstantConditionIf() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/constantConditionIf"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("delete.kt")
+ public void testDelete() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/delete.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("expression.kt")
+ public void testExpression() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/expression.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("noStatements.kt")
+ public void testNoStatements() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/noStatements.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simpleBlock.kt")
+ public void testSimpleBlock() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/simpleBlock.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simpleFalse.kt")
+ public void testSimpleFalse() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/simpleFalse.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simpleTrue.kt")
+ public void testSimpleTrue() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/simpleTrue.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("statement.kt")
+ public void testStatement() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/constantConditionIf/statement.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/inspectionsLocal/copyWithoutNamedArguments")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)