From 3a8a288ba768b57f0ba0d308136d0bb0b870493b Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Wed, 22 Apr 2026 09:13:35 +0100 Subject: [PATCH] docs(csharp-scope): justify regex-based namespace-sibling detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record why `namespace-siblings.ts` uses regex over AST walks and enumerate the known misses so the next reader has ground to stand on: * `global using static X.Y;` — no plain `using static` token. * Aliased `using static X = Y.Z;` — `=` breaks the pattern. * Attributed namespace declarations between `]` and `{`. * Multi-namespace files — first-wins attribution. * Preprocessor-gated namespace declarations — textual branch only. Rationale: the pass is file-path-driven and the tree-sitter tree isn't available at its call site (the orchestrator feeds raw fileContents); re-parsing to count namespaces would cost more than the regex walk. Refactor to AST-driven detection is deferred to a separate PR. Mirrored the known-miss list into `csharp/index.ts`'s limitations ledger so the operator-visible surface and the in-code justification stay in sync. No code change. --- .../core/ingestion/languages/csharp/index.ts | 13 ++++++++ .../languages/csharp/namespace-siblings.ts | 31 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/gitnexus/src/core/ingestion/languages/csharp/index.ts b/gitnexus/src/core/ingestion/languages/csharp/index.ts index 5c396002d..c7f7d3207 100644 --- a/gitnexus/src/core/ingestion/languages/csharp/index.ts +++ b/gitnexus/src/core/ingestion/languages/csharp/index.ts @@ -53,6 +53,19 @@ * 8. **Expression-bodied `=>` members** — handled by the method * extractor, but receiver synthesis for `=> this.Field` shortcuts * follows the same path as block-bodied methods. + * 9. **Regex-based namespace-sibling detection** — + * `namespace-siblings.ts` scans raw file content for `namespace X` + * and `using static X.Y` to compute same-namespace cross-file + * visibility. Known misses (each acknowledged in-file): + * a. `global using static X.Y;` is not detected. + * b. Aliased `using static X = Y.Z;` is not detected. + * c. Multi-namespace files: classes are attributed to the first + * declared namespace only. + * d. Preprocessor-gated `namespace` declarations are seen as + * whichever branch is textually present. + * See `namespace-siblings.ts`'s file-head comment for the full + * rationale; refactor to AST-driven detection is deferred to a + * separate PR. * * Shadow-harness corpus parity is the authoritative signal for which * of these matter in practice. The CI parity gate blocks any PR that diff --git a/gitnexus/src/core/ingestion/languages/csharp/namespace-siblings.ts b/gitnexus/src/core/ingestion/languages/csharp/namespace-siblings.ts index 4a15eecfa..e2217ac1c 100644 --- a/gitnexus/src/core/ingestion/languages/csharp/namespace-siblings.ts +++ b/gitnexus/src/core/ingestion/languages/csharp/namespace-siblings.ts @@ -19,6 +19,37 @@ * sibling classes into each Namespace scope's finalized bindings * with `origin: 'namespace'` — a tier below `local` so a local * declaration still shadows a cross-file sibling with the same name. + * + * ## Why regex and not the AST + * + * The pass is file-path-driven and only needs two pieces of info per + * file: which `namespace X` it declares, and which `using static X.Y` + * it pulls in. The tree-sitter tree isn't available at the pass's + * call site (the scope-resolution orchestrator feeds raw + * `fileContents` — re-parsing just to count namespaces would cost + * more than the regex walk). We accept the regex's known misses (see + * below) in exchange for a cheap, allocation-free pass. + * + * ## Known misses + * + * The regex-based detection silently skips: + * - `global using static X.Y;` (no plain `using static` token). + * - Aliased `using static X = Y.Z;` (the `=` breaks the pattern). + * - Attributed namespace declarations like `[assembly: X] + * namespace Y` — the regex still matches `namespace Y` but any + * trailing `[attr]` before `{` on the same line would fail. + * - Multi-namespace files: the `first-wins` attribution below + * groups all top-level classes under the first declared + * namespace; truly interleaved namespaces are rare but lose + * fidelity here. + * - `namespace` identifiers split by preprocessor `#if` / + * conditional compilation — the regex sees whichever branch is + * textually present. + * + * The limitations are mirrored in `csharp/index.ts`'s ledger so the + * operator-visible surface and the in-code justification stay in sync. + * If additional precision is required, refactor to consume the + * `@namespace.name` capture via the extractor (deferred — separate PR). */ import type { BindingRef, ParsedFile, Scope, ScopeId, SymbolDefinition } from 'gitnexus-shared';