avoid_deep_nesting
This rule flags control flow nested more deeply than the configured budget. Each level of if, for, while, do, try or switch counts.
Each level is another condition the reader has to hold to know why a line runs at all. Depth is also more actionable than a complexity score: an early return, a guard clause or an extracted method removes a whole level, where a complexity count only says something is wrong.
This rule is in the pedantic preset. The default budget is max_depth: 4, and one diagnostic is reported per function, anchored at the statement that first crosses the limit.
Five levels. Nothing on the handle(cell) line says why it runs:
void process(List<List<int>> rows, bool enabled) { if (enabled) { for (final row in rows) { for (final cell in row) { if (cell > 0) { while (cell > 1) { // reported here — level 5 handle(cell); } } } } }}
void handle(int cell) {}Invert the outer guard, continue past the filter, and lift the inner loop
into its own function. Same behaviour, two levels each:
void process(List<List<int>> rows, bool enabled) { if (!enabled) return;
for (final row in rows) { _processRow(row); }}
void _processRow(List<int> row) { for (final cell in row) { if (cell <= 0) continue; _handleRepeatedly(cell); }}
void _handleRepeatedly(int cell) { while (cell > 1) { handle(cell); }}
void handle(int cell) {}More examples
Section titled “More examples”else if is a sibling, not another level
Section titled “else if is a sibling, not another level”A dispatch chain reads flat and is counted flat, however long it grows:
// Not reported — this is one level, not five.String label(int code) { if (code < 100) { return 'informational'; } else if (code < 200) { return 'success'; } else if (code < 300) { return 'redirect'; } else if (code < 400) { return 'client error'; } else if (code < 500) { return 'server error'; } else { return 'unknown'; }}A nested function starts its own count
Section titled “A nested function starts its own count”A callback’s body is not reached through the enclosing nest, so it is measured against the budget on its own:
// Not reported — the outer function has one level, the callback three.void install(List<int> rows) { rows.forEach((row) { if (row > 0) { for (var i = 0; i < row; i++) { if (i.isEven) { print(i); } } } });}Tightening the budget
Section titled “Tightening the budget”Four is a guard, a loop, a branch and the work. Drop it to three if you want the work itself at the shallowest level:
rules: avoid_deep_nesting: max_depth: 3Known limitations
Section titled “Known limitations”Only block bodies are examined. A function written with an expression body
(=>) is skipped entirely, however much nesting a conditional expression hides
in it.
else if never adds a level, but an else { if (...) } written with braces
does.
Enabling this rule
Section titled “Enabling this rule”This rule is in the pedantic preset, so it is enabled by preset: pedantic or by name:
rules: avoid_deep_nesting: enabled: trueOptions
Section titled “Options”many_lints: rules: avoid_deep_nesting: max_depth: 4rules: avoid_deep_nesting: max_depth: 4| Option | Type | Default | Description |
|---|---|---|---|
max_depth |
int | 4 |
How many levels of control flow may nest |
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: avoid_deep_nesting: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_complex_conditions— Keep boolean conditions within an operand budget.avoid_high_cyclomatic_complexity— Keep a function within a complexity budget.avoid_long_functions— Keep function bodies within a line budget.max_statements— Keep a function within a statement budget.