Skip to main content

MAINT016 — Unreachable Code

PropertyValue
Rule IDMAINT016-unreachable-code
DimensionMaintainability
SeverityLow
CWECWE-561
LanguagesRust, Python, JavaScript/TypeScript
Sincev0.4.0

Summary​

Flags the first statement that follows a terminating statement in the same block. Code that appears after a return, throw / raise, break, or continue can never be executed at run time. One finding is emitted per block, pointing at the first dead statement.

Why this matters​

Unreachable code is a maintenance hazard:

  • It confuses readers and code reviewers who expect every line to have effect.
  • It may hide logic errors (e.g. a return placed before the value it was supposed to return is calculated).
  • It silently accumulates as code evolves, making diffs noisier and testing coverage metrics misleading.

Terminating statements​

LanguageTerminators
Rustreturn, break, continue, panic!(), unreachable!(), todo!(), unimplemented!()
Pythonreturn, raise, break, continue
JavaScript / TypeScriptreturn, throw, break, continue

Detection rule​

Within a single flat block, the analyzer finds the index of the first terminating statement. If at least one more statement follows it, a single finding is emitted pointing at that first dead statement. Multiple dead statements produce one finding, not many.

The rule does not fire when a terminator appears inside a nested block (e.g. the body of an if branch) and the following statement is in the outer block — that outer statement is reachable when the condition is false.

Example — flagged (Rust)​

fn f() -> i32 {
return 1;
let x = 2; // ← finding here
x
}

Example — not flagged (Rust)​

fn f(cond: bool) -> i32 {
if cond {
return 1; // inside nested block
}
let x = 2; // reachable when !cond — no finding
x
}

Example — flagged (Python)​

def f():
return 1
x = 2 # ← finding here

pass after a terminator is not flagged — it is idiomatic (e.g. generated stubs) and ruff already handles it.

Example — flagged (JavaScript)​

function f() {
throw new Error('fatal');
console.log('done'); // ← finding here
}

Nested blocks​

The analyzer recurses into all nested function/method bodies, loop bodies, and (for Python) class bodies. Each block is checked independently, so dead code inside an inner function emits its own finding.

Scope limitations (v1)​

The following cases are deferred to a future release that includes a control-flow graph (CFG):

  • Rust: !-typed function calls (std::process::exit(1)) are not detected as terminators at the syntactic level — only the macro-based divergers listed above are checked.
  • Cross-block reachability (e.g. unconditional while true loops) is not analysed.

Configuration​

This rule has no configuration options. Use suppression comments to silence specific findings when the dead code is intentional.

References​