avoid_constant_conditions
v0.4.0 Warning Control Flow
Flags a comparison (==, !=, <, >, <=, >=) whose operands are both compile-time constants. The answer is fixed before the program runs, so one branch is dead and the other always taken.
The usual shape is a constant that used to be a variable, or a constant compared against the value it was defined as:
abstract final class Config { static const channel = 'stable'; static const maxRetries = 3;}
void configure() { // Always true — `channel` is `'stable'` by definition. if (Config.channel == 'stable') { enableCrashReporting(); }}
void enableCrashReporting() {}Compare the constant against something that varies — a parameter, a field, a value read at runtime:
abstract final class Config { static const channel = 'stable'; static const maxRetries = 3;}
void configure(String buildChannel) { if (buildChannel == Config.channel) { enableCrashReporting(); }}
void enableCrashReporting() {}A constant threshold is fine on one side
Section titled “A constant threshold is fine on one side”Comparing a variable against a named constant is the whole point of naming it, and is never reported:
void retry(int attempt) { const maxRetries = 3;
if (attempt < maxRetries) { // Only `maxRetries` is constant, so nothing is reported. }}The leftover from a debugging session
Section titled “The leftover from a debugging session”Hard-coding both sides to force a branch is the fastest way to test one, and the easiest thing to forget to undo:
void render() { // Don't — left over from "let me see the empty state" if (1 == 1) { showEmptyState(); }}
void showEmptyState() {}Two const locals, one comparison
Section titled “Two const locals, one comparison”Naming both sides does not make the comparison meaningful — it is still decided at compile time:
void check() { const limit = 4; const ceiling = 4;
// Don't — `4 != 4`, written in two steps if (limit != ceiling) { print('never'); }}Known limitations
Section titled “Known limitations”Only the six comparison operators are checked. &&, || and arithmetic are out of scope — see avoid_contradictory_expressions for conjunctions that can never be true.
Constness is read syntactically: literals, const variables and static const fields, const collections and const constructor calls, plus prefix operators over those. A plain final local is not treated as constant, so final limit = 4; if (limit != 4) is not reported. Neither is a function call, so f() == 3 stays silent even when f is trivially constant.
There is no quick fix. Which operand should have been a variable is a question only the author can answer.
Configuration
Section titled “Configuration”This rule is in the core preset, so it is on with preset: core,
preset: recommended or preset: opinionated.
To turn it off:
rules: avoid_constant_conditions: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_contradictory_expressions— Detect logical AND conditions that always evaluate to false.avoid_equal_expressions— Both operands of a binary expression should not be identical.avoid_self_compare— Flag a value compared against itself with compareTo.avoid_constant_switches— Detect switch statements on constant expressions.