Skip to content

LOC comment-line detection misclassifies code lines starting with a comment-prefix character (e.g. pointer deref *ptr =) #2287

Description

@carlos-alm

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions