diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt index 3f981181c2e..793b36da5a2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt @@ -14,7 +14,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isElseIf import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext @@ -116,12 +120,42 @@ class ConstantConditionIfInspection : AbstractKotlinInspection() { private fun KtIfExpression.branch(thenBranch: Boolean) = if (thenBranch) then else `else` private fun KtExpression.constantBooleanValue(context: BindingContext): Boolean? { + val enumEntriesComparison = enumEntriesComparison() + if (enumEntriesComparison != null) { + return enumEntriesComparison + } val type = getType(context) ?: return null - val constantValue = ConstantExpressionEvaluator.getConstant(this, context)?.toConstantValue(type) return constantValue?.value as? Boolean } +private fun KtExpression.enumEntriesComparison(): Boolean? { + if (this !is KtBinaryExpression) return null + val leftEnumEntry = left?.enumEntry() ?: return null + val rightEnumEntry = right?.enumEntry() ?: return null + + val leftEnum = leftEnumEntry.containingClass() ?: return null + val rightEnum = rightEnumEntry.containingClass() ?: return null + if (leftEnum != rightEnum) return null + + val enumEntries = leftEnum.body?.getChildrenOfType() ?: return null + val leftIndex = enumEntries.indexOf(leftEnumEntry) + val rightIndex = enumEntries.indexOf(rightEnumEntry) + return when (operationToken) { + KtTokens.EQEQ -> leftIndex == rightIndex + KtTokens.GT -> leftIndex > rightIndex + KtTokens.GTEQ -> leftIndex >= rightIndex + KtTokens.LT -> leftIndex < rightIndex + KtTokens.LTEQ -> leftIndex <= rightIndex + KtTokens.EXCLEQ -> leftIndex != rightIndex + else -> null + } +} + +private fun KtExpression.enumEntry(): KtEnumEntry? { + return ((this as? KtDotQualifiedExpression)?.selectorExpression ?: this).mainReference?.resolve() as? KtEnumEntry +} + fun KtExpression.replaceWithBranch(branch: KtExpression, isUsedAsExpression: Boolean, keepBraces: Boolean = false) { val lastExpression = when { branch !is KtBlockExpression -> replaced(branch) diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt new file mode 100644 index 00000000000..521bb884c5c --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.A == Enum.A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt new file mode 100644 index 00000000000..85deade13a6 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt @@ -0,0 +1,5 @@ +package test + +enum class Enum { + A, B, C +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt.after new file mode 100644 index 00000000000..85deade13a6 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.1.kt.after @@ -0,0 +1,5 @@ +package test + +enum class Enum { + A, B, C +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt new file mode 100644 index 00000000000..b3d68b72938 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt @@ -0,0 +1,6 @@ +// PROBLEM: Condition is always 'true' +fun foo(x: Int) {} + +fun bar() { + foo(if (test.Enum.A == test.Enum.A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt.after new file mode 100644 index 00000000000..d520a02e06f --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt.after @@ -0,0 +1,6 @@ +// PROBLEM: Condition is always 'true' +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt new file mode 100644 index 00000000000..85deade13a6 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt @@ -0,0 +1,5 @@ +package test + +enum class Enum { + A, B, C +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt.after new file mode 100644 index 00000000000..85deade13a6 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.1.kt.after @@ -0,0 +1,5 @@ +package test + +enum class Enum { + A, B, C +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt new file mode 100644 index 00000000000..a8fdd98005f --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt @@ -0,0 +1,8 @@ +// PROBLEM: Condition is always 'true' +import test.Enum.* + +fun foo(x: Int) {} + +fun bar() { + foo(if (A == A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt.after new file mode 100644 index 00000000000..58d3981f2e4 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt.after @@ -0,0 +1,8 @@ +// PROBLEM: Condition is always 'true' +import test.Enum.* + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt new file mode 100644 index 00000000000..0a05c4e02b3 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B > Enum.A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt new file mode 100644 index 00000000000..b06ae1dd5b0 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B >= Enum.A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt new file mode 100644 index 00000000000..821879d0335 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B >= Enum.B) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt new file mode 100644 index 00000000000..b076b2c7778 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B < Enum.C) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt new file mode 100644 index 00000000000..efae7b1012e --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B <= Enum.C) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt new file mode 100644 index 00000000000..b812afe0191 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.B <= Enum.B) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt.after new file mode 100644 index 00000000000..aa1d1851a9d --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'true' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(1) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt new file mode 100644 index 00000000000..d96c509d3d2 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'false' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(if (Enum.A != Enum.A) 1 else 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt.after b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt.after new file mode 100644 index 00000000000..98530c484d9 --- /dev/null +++ b/idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt.after @@ -0,0 +1,10 @@ +// PROBLEM: Condition is always 'false' +enum class Enum { + A, B, C +} + +fun foo(x: Int) {} + +fun bar() { + foo(2) +} \ 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 d63b3bff6d8..2615d9b50c8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1524,6 +1524,56 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/constantConditionIf/endWithElseIfNoBraces.kt"); } + @TestMetadata("enumEntryEq.kt") + public void testEnumEntryEq() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq.kt"); + } + + @TestMetadata("enumEntryEq2.kt") + public void testEnumEntryEq2() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq2.kt"); + } + + @TestMetadata("enumEntryEq3.kt") + public void testEnumEntryEq3() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryEq3.kt"); + } + + @TestMetadata("enumEntryGt.kt") + public void testEnumEntryGt() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryGt.kt"); + } + + @TestMetadata("enumEntryGtEq.kt") + public void testEnumEntryGtEq() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq.kt"); + } + + @TestMetadata("enumEntryGtEq2.kt") + public void testEnumEntryGtEq2() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryGtEq2.kt"); + } + + @TestMetadata("enumEntryLt.kt") + public void testEnumEntryLt() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryLt.kt"); + } + + @TestMetadata("enumEntryLtEq.kt") + public void testEnumEntryLtEq() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq.kt"); + } + + @TestMetadata("enumEntryLtEq2.kt") + public void testEnumEntryLtEq2() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryLtEq2.kt"); + } + + @TestMetadata("enumEntryNotEq.kt") + public void testEnumEntryNotEq() throws Exception { + runTest("idea/testData/inspectionsLocal/constantConditionIf/enumEntryNotEq.kt"); + } + @TestMetadata("expression.kt") public void testExpression() throws Exception { runTest("idea/testData/inspectionsLocal/constantConditionIf/expression.kt");