Condition Always True

ID

kotlin.condition_always_true

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Kotlin

Tags

reliability, suspicious-comparison

Description

Reports an if whose condition is a boolean literal — true or false, optionally wrapped in parentheses. The branch is decided at parse time: one arm always runs and the other is dead.

Rationale

fun alwaysRuns() {
    if (true) {
        println("always")
    }
}

fun neverRuns() {
    if (false) println("never")
}

The if carries no semantics at all — it reads as conditional and is not. Such a guard is nearly always a leftover: a temporary switch used while debugging, or a feature flag that was inlined and never taken out. Either way the next reader has to work out that the condition is fixed before they can see which code actually runs, and the dead arm keeps compiling long after it stopped being maintained.

Notes

The trigger is narrow on purpose: the condition must be a boolean literal. Anything the compiler would have to fold is left alone.

  • Loops are out of scope. while (true) and do …​ while (true) are the idiomatic way to write an event or processing loop with an inner break, and are never reported.

  • if (!true) is not reported — the condition is a prefix-unary expression, not a literal. Skipping this rare shape buys a rule that never has to reason about operator semantics.

  • A condition naming a const val is not reported. The value is fixed at compile time, but the name states an intent the literal does not, and a build-configuration constant guarding a block is deliberate.

  • if (flag == true) belongs to kotlin.boolean_compare_with_literal, and a self-comparison such as x == x to kotlin.compare_value_to_itself. Neither is duplicated here.

  • This is a different finding from kotlin.unreachable_code, which reports statements written after a terminating statement in the same block. The dead arm of a literal-guarded if is not such a statement, so the two rules never report the same line.

Remediation

Decide what the condition was standing in for, then remove it.

If the branch should always run, keep the body and drop the guard:

fun alwaysRuns() {
    println("always")
}

If it should never run, delete it — version control keeps the history:

fun neverRuns() {
}

If the decision is a real build-time choice, name it, so the intent survives:

private const val VERBOSE_LOGGING = true

fun alwaysRuns() {
    if (VERBOSE_LOGGING) {
        println("always")
    }
}

© 2026 Xygeni. All rights reserved