Skip to content

WASM complexity visitor never runs for a file where every function is single-line #2285

Description

@carlos-alm

Summary

setupComplexityVisitorForFile (src/ast-analysis/engine.ts) and the analogous initWasmParsersIfNeeded/setupCfgVisitorForFile gates decide whether to run the WASM complexity/CFG visitor for a file using:

const needsWasmComplexity = defs.some((d) => hasFuncBody(d) && !d.complexity);

hasFuncBody requires d.endLine > d.line (a multi-line span) in addition to !d.bodyless. If every function/method definition in a file happens to have its entire body on one line (a common style for simple getters, one-line guard returns, or C# expression-bodied members => expr;), every definition fails hasFuncBody, needsWasmComplexity evaluates to false for the whole file, and the complexity/CFG visitor is never added to the walk at all — the file gets zero complexity/CFG data under the WASM engine, even though every function in it has a real, bodied, computable implementation.

Reproduction

interface IRepo2 {
    bool Save(string id, int value);
    bool SaveOneLine(string id, int value) => value >= 0;
}
class Repo2 : IRepo2 {
    public bool Save(string id, int value) { return true; }
    public bool SaveOneLine(string id, int value) => value >= 0;
}
$ codegraph where --file Repo2.cs
Symbols: IRepo2:1, IRepo2.Save:2, IRepo2.SaveOneLine:3, Repo2:5, Repo2.Save:6, ..., Repo2.SaveOneLine:7, ...

$ codegraph complexity --engine wasm --json
functions: 0   for anything in Repo2.cs

All four real definitions (two abstract signatures aside) are single-line, so the file-level gate never fires and none of them — including the two genuinely bodied methods — get complexity data.

This is a pre-existing, independent bug from #2055 (confirmed present before any of that issue's fix — setupComplexityVisitorForFile was not touched by that PR). It's the same hasFuncBody endLine > line heuristic, but misapplied at the file-scoping layer rather than the per-definition merge layer #2055 fixed.

Suggested fix

The file-level gate only needs to know "does this file contain at least one definition that plausibly has a body and is missing complexity" — the endLine > line heuristic is the wrong tool for that, for the same reason #2055 found it wrong for the per-definition merge: it's a proxy for "multi-line", not "has a body". Consider gating on !d.bodyless && !d.complexity directly (mirroring the def.bodyless !== true fix in #2055) instead of the stricter hasFuncBody, or auditing whether hasFuncBody's endLine > line requirement is still needed anywhere now that bodyless is a reliable direct signal from every extractor (added in #1922).

Discovery context

Found while stress-testing edge cases for #2055 (WASM complexity wrongly computed for bodyless interface methods) — that PR's own fix is unaffected by this; this is a distinct, pre-existing latent bug in the file-level visitor-setup gate, not introduced by it.

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