Nested functions inflate their enclosing function's complexity
|
|
| Severity |
medium |
| Confidence |
99% (confirmed) |
| Kind |
logic-bug |
| Location |
src/parsers/shared/metrics-base.ts → computeComplexity |
| Module |
src/parsers/shared |
| Finding ID |
f-097c56 |
Failure scenario
A Python function containing a nested function with an if is reported with complexity 2 even when the outer function has no decisions. The recursive walk enters the nested function_definition and attributes its decisions to the outer function; the same boundary problem applies to Go function literals and Rust closures.
Evidence
src/parsers/shared/metrics-base.ts:11-17 defines an unrestricted recursive walk: if (decisionTypes.has(n.type)) complexity++;, followed by for (const child of n.namedChildren || []) walk(child);, then starts it at the enclosing callable's body with if (body) walk(body);. src/parsers/python/py-metrics.ts:11-24 counts if_statement and delegates directly to this walker. src/parsers/python/py-parser.ts:269 assigns that result to the outer function via complexity: computePyComplexity(funcNode). No nested-callable boundary is checked.
Reproduction
Generate a codemap for Python containing def outer():\n def inner(x):\n if x:\n return 1\n return inner. The outer function receives complexity 2, although its own control flow has no decision and should produce the baseline complexity 1.
Suggested fix direction
Stop the shared traversal when it reaches a nested callable boundary, using the relevant tree-sitter node types for each language (Python function_definition, Go func_literal, Rust closure_expression). Keep traversing the original function body and add one focused regression test covering an outer function with a conditional only inside a nested callable.
Why this matters here
Accurate per-function complexity is necessary for trustworthy relationship maps, health scores, and hotspot reporting.
Suggested test
Parse def outer():\n def inner(x):\n if x:\n return 1\n return inner and assert that outer has complexity 1, not 2.
How to work this issue
Open a Claude Code session in this repo and say
"work the dev-cli finding f-097c56 in src/parsers/shared/metrics-base.ts".
Start from the evidence above rather than re-investigating: it was produced by reading this
exact commit. Done means the suggested test fails before your change and passes after, and the
next scan marks the finding fixed.
If this is not a real defect, close the issue with the false-positive label — dev-cli
records the fingerprint and will never raise it again. Closing it without that label marks the
finding fixed instead.
Raised by dev-cli · repo codemap-cli · branch main · commit c8cf294 · scan 2026-08-15T14-12-31 · fingerprint 097c56c73143
Nested functions inflate their enclosing function's complexity
medium99% (confirmed)logic-bugsrc/parsers/shared/metrics-base.ts→computeComplexitysrc/parsers/sharedf-097c56Failure scenario
A Python function containing a nested function with an
ifis reported with complexity 2 even when the outer function has no decisions. The recursive walk enters the nestedfunction_definitionand attributes its decisions to the outer function; the same boundary problem applies to Go function literals and Rust closures.Evidence
src/parsers/shared/metrics-base.ts:11-17 defines an unrestricted recursive walk:
if (decisionTypes.has(n.type)) complexity++;, followed byfor (const child of n.namedChildren || []) walk(child);, then starts it at the enclosing callable's body withif (body) walk(body);. src/parsers/python/py-metrics.ts:11-24 countsif_statementand delegates directly to this walker. src/parsers/python/py-parser.ts:269 assigns that result to the outer function viacomplexity: computePyComplexity(funcNode). No nested-callable boundary is checked.Reproduction
Generate a codemap for Python containing
def outer():\n def inner(x):\n if x:\n return 1\n return inner. The outer function receives complexity 2, although its own control flow has no decision and should produce the baseline complexity 1.Suggested fix direction
Stop the shared traversal when it reaches a nested callable boundary, using the relevant tree-sitter node types for each language (Python
function_definition, Gofunc_literal, Rustclosure_expression). Keep traversing the original function body and add one focused regression test covering an outer function with a conditional only inside a nested callable.Why this matters here
Accurate per-function complexity is necessary for trustworthy relationship maps, health scores, and hotspot reporting.
Suggested test
Parse
def outer():\n def inner(x):\n if x:\n return 1\n return innerand assert thatouterhas complexity 1, not 2.How to work this issue
Open a Claude Code session in this repo and say
"work the dev-cli finding
f-097c56insrc/parsers/shared/metrics-base.ts".Start from the evidence above rather than re-investigating: it was produced by reading this
exact commit. Done means the suggested test fails before your change and passes after, and the
next scan marks the finding fixed.
If this is not a real defect, close the issue with the
false-positivelabel — dev-clirecords the fingerprint and will never raise it again. Closing it without that label marks the
finding fixed instead.
Raised by dev-cli · repo
codemap-cli· branchmain· commitc8cf294· scan2026-08-15T14-12-31· fingerprint097c56c73143