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)anddo … while (true)are the idiomatic way to write an event or processing loop with an innerbreak, 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 valis 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 tokotlin.boolean_compare_with_literal, and a self-comparison such asx == xtokotlin.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-guardedifis 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")
}
}