Summary
computeLOCMetrics() (TS: src/ast-analysis/metrics.ts; native: the LOC-counting logic in crates/codegraph-core/src/ast_analysis/complexity.rs) classifies a line as a comment purely by checking whether the trimmed line text starts with any of a language's comment prefixes (trimmed.startsWith(p)). For any language whose comment prefixes include a bare * (used to match /** ... */ Javadoc-style continuation lines: * some doc text), this also matches any executable line that happens to start with * after trimming — most notably pointer-dereference assignment (*ptr = 5;), which several supported languages allow as a statement.
There is no block-comment-state tracking (i.e. "are we currently inside an unterminated /* ... */ block") — it's a pure per-line, stateless prefix check.
Reproduction
This already reproduces on main, for Rust, on both engines — completely unrelated to any recent PR:
fn deref_heavy(ptr: *mut i32) -> i32 {
unsafe {
*ptr = 5;
*ptr = *ptr + 1;
return *ptr;
}
}
$ codegraph complexity --health -T --json --engine wasm
{ "name": "deref_heavy", "loc": 7, "sloc": 5 } ← 2 lines wrongly counted as comments
$ codegraph complexity --health -T --json --engine native
{ "name": "deref_heavy", "loc": 7, "sloc": 5 } ← identical, same bug on both engines
Both *ptr = 5; and *ptr = *ptr + 1; are counted as comment lines, undercounting sloc and skewing the Maintainability Index input. Rust, C#, and Go all currently use the 4-entry ["//", "/*", "*", "*/"] prefix list (needed for /** */-style doc comments) and all support a *-prefixed pointer-dereference/assignment statement shape, so all three are exposed to this same class of misclassification today, independent of language.
Scope note
Found via Greptile review on #2286 (which extended the same 4-entry prefix list to c/cpp/objc/kotlin/swift/scala for cross-engine/cross-language consistency — before that PR, those languages used an inconsistent 2-entry list, which is what #2058 was scoped to fix). Confirmed via the Rust repro above that this exact misclassification already existed on main, unrelated to #2286's own changes, for every language that already had the 4-entry list — so it's a pre-existing, shared limitation of the per-line stateless heuristic itself, not something #2286 introduced. Filing as its own issue since fixing it properly means making comment detection block-comment-state-aware (tracking whether a line is inside an unterminated /* ... */, rather than trusting a bare * prefix), which is a real algorithmic change affecting every C-style/JSDoc-style language on both engines — out of scope for a prefix-list consistency fix.
Suggested fix
Track block-comment state while scanning a function's lines: once a /* is seen without a matching */ on the same line, treat every subsequent line as a comment continuation (including bare *-prefixed ones) until a line containing */ is seen — rather than trusting a bare * prefix unconditionally on every line. This must be mirrored identically in both src/ast-analysis/metrics.ts and the native Rust LOC-counting logic to preserve engine parity.
Summary
computeLOCMetrics()(TS:src/ast-analysis/metrics.ts; native: the LOC-counting logic incrates/codegraph-core/src/ast_analysis/complexity.rs) classifies a line as a comment purely by checking whether the trimmed line text starts with any of a language's comment prefixes (trimmed.startsWith(p)). For any language whose comment prefixes include a bare*(used to match/** ... */Javadoc-style continuation lines:* some doc text), this also matches any executable line that happens to start with*after trimming — most notably pointer-dereference assignment (*ptr = 5;), which several supported languages allow as a statement.There is no block-comment-state tracking (i.e. "are we currently inside an unterminated
/* ... */block") — it's a pure per-line, stateless prefix check.Reproduction
This already reproduces on
main, for Rust, on both engines — completely unrelated to any recent PR:Both
*ptr = 5;and*ptr = *ptr + 1;are counted as comment lines, undercountingslocand skewing the Maintainability Index input. Rust, C#, and Go all currently use the 4-entry["//", "/*", "*", "*/"]prefix list (needed for/** */-style doc comments) and all support a*-prefixed pointer-dereference/assignment statement shape, so all three are exposed to this same class of misclassification today, independent of language.Scope note
Found via Greptile review on #2286 (which extended the same 4-entry prefix list to c/cpp/objc/kotlin/swift/scala for cross-engine/cross-language consistency — before that PR, those languages used an inconsistent 2-entry list, which is what #2058 was scoped to fix). Confirmed via the Rust repro above that this exact misclassification already existed on
main, unrelated to #2286's own changes, for every language that already had the 4-entry list — so it's a pre-existing, shared limitation of the per-line stateless heuristic itself, not something #2286 introduced. Filing as its own issue since fixing it properly means making comment detection block-comment-state-aware (tracking whether a line is inside an unterminated/* ... */, rather than trusting a bare*prefix), which is a real algorithmic change affecting every C-style/JSDoc-style language on both engines — out of scope for a prefix-list consistency fix.Suggested fix
Track block-comment state while scanning a function's lines: once a
/*is seen without a matching*/on the same line, treat every subsequent line as a comment continuation (including bare*-prefixed ones) until a line containing*/is seen — rather than trusting a bare*prefix unconditionally on every line. This must be mirrored identically in bothsrc/ast-analysis/metrics.tsand the native Rust LOC-counting logic to preserve engine parity.