Commit graph

7 commits

Author SHA1 Message Date
Gergo Magyar
908798af0b feat(csharp-scope): parity Unit 1 — this/base receiver-binding synthesis
Closes 3 parity failures (51 → 48). Target bucket: Category C from the
parity plan.

Changes:
- `languages/csharp/receiver-binding.ts` (new): walks up from a
  function node to the enclosing class/struct/record/interface,
  synthesizes `@type-binding.self` captures with boundName `'this'`
  (and `'base'` when the enclosing type is a class/record with an
  explicit base_list entry). Skips static methods and interface /
  struct `base` cases. Anchors to the method's `body` block so the
  scope-extractor's positionIndex places the binding inside the
  function scope (not the enclosing class scope).
- `languages/csharp/captures.ts`: route `@scope.function` matches
  through the synth, emitting the receiver captures as separate
  matches.
- `languages/csharp/interpret.ts`: map `@type-binding.self` to
  `source: 'self'` (parity with Python).
- `languages/csharp/query.ts`: explicit patterns for `this.X()`,
  `base.X()`, and `this.X = ...` / `base.X = ...` assignment writes.
  `this` and `base` are anonymous tokens in tree-sitter-c-sharp so
  the existing `expression: (_)` pattern (named-only) didn't match.

Tests:
- 8 new unit tests for receiver-binding synthesis edge cases
  (class/struct/record/interface, static, nested, constructor,
  local function inside method).
- Parity: 48 failed | 127 passed (175) under REGISTRY_PRIMARY_CSHARP=1;
  legacy path 175/175 green.
2026-04-21 18:26:00 +01:00
Gergo Magyar
ac8b55ba2c feat(csharp-scope): Unit 5 — arity metadata synthesis + compatibility
Adversarial review flagged overload narrowing as a blocker for the Unit
7 flip. This lands the declaration-side metadata; callsite-side arity
synthesis is a separate gap we'll address if the parity gate surfaces
overload misresolution.

- `arity-metadata.ts` — reads `csharpMethodConfig.extractParameters`
  and produces `{ parameterCount, requiredParameterCount,
  parameterTypes }`. `params` variadic collapses parameterCount to
  undefined (matches Python's `*args` treatment) and appends a literal
  `'params'` marker to parameterTypes so the compatibility hook can
  detect it without re-reading the AST. Default-valued parameters
  contribute to optionalCount → requiredParameterCount = total − optional.
- `arity.ts` — `csharpArityCompatibility(def, callsite)` returns
  compatible / incompatible / unknown. Mirrors Python's three-verdict
  shape so the central registry's arity filter works without adapter
  logic per-verdict.
- `captures.ts` — on every @declaration.method / @declaration.constructor
  / @declaration.function match, synthesize
  @declaration.parameter-count, @declaration.required-parameter-count,
  and @declaration.parameter-types captures. Covers method_declaration,
  constructor_declaration, destructor_declaration, operator_declaration,
  conversion_operator_declaration, and local_function_statement.

12 new tests: 5 on captures-side synthesis (method + params + types +
variadic + constructor + local function), 7 on the compatibility hook.
66/66 C# scope-resolution unit tests pass; tsc clean.
2026-04-21 17:27:36 +01:00
Gergo Magyar
3c79058088 feat(csharp-scope): Unit 4 — mergeBindings (using precedence)
Three-tier shadowing, same shape as Python's LEGB merge:
  0: local      — class members, locals, parameters
  1: using      — namespace / named / reexport (equal tier; compiler
                  requires explicit qualifier if two using collide)
  2: wildcard   — `using static X.Y;` static-member imports

Within the surviving tier, de-dup by DefId (last-write-wins) so a
re-declared `using` cleanly replaces its earlier binding. Explicit
interface implementations bind under their qualified name in the
extractor layer, so they don't collide with plain simple names here.

7 new tests pin precedence + dedup semantics. 54/54 C# scope-resolution
unit tests pass.
2026-04-21 17:22:40 +01:00
Gergo Magyar
dd7e553d07 feat(csharp-scope): Unit 3 — simple hooks (binding/import/receiver)
Adds simple-hooks.ts mirroring Python's pattern:

- `csharpBindingScopeFor` — delegates to innermost (block scope is
  already captured by @scope.block in the query).
- `csharpImportOwningScope` — binds `using` inside a namespace to that
  namespace's scope so imports don't leak into sibling namespaces.
  File-level using delegates to module. Function-body using (not legal
  C# but possible from malformed input) attaches to the function.
- `csharpReceiverBinding` — looks up `this` / `base` in the function
  scope's type bindings; returns null for statics, free functions, and
  non-Function scopes. `this` / `base` synthesis itself is deferred to
  a follow-up (matches Python's receiver-binding.ts pattern).

9 new tests pin delegation semantics. 47/47 C# scope-resolution unit
tests pass; tsc clean.
2026-04-21 17:10:41 +01:00
Gergo Magyar
a3a2c65cc7 feat(csharp-scope): Unit 2 — import interpret + target resolver
Adds the three files Unit 2 of the C# scope-resolution plan calls for:

- `import-decomposer.ts` — inspects each `using_directive` node and
  synthesizes `@import.kind/source/name/alias` markers. Kinds:
    `namespace`  — `using X;` / `using X.Y.Z;`
    `alias`      — `using Alias = X.Y.Z;`         (generics stripped)
    `static`     — `using static X.Y;`
  `global using` maps to namespace (plan's deferred decision); the
  `global::` qualifier is stripped before emitting.
- `interpret.ts` — reads the markers and builds `ParsedImport`. Static
  using maps to `kind: 'wildcard'` since it brings members into
  unqualified scope; Unit 4's merge-bindings tiers wildcards lowest.
  Also provides `interpretCsharpTypeBinding` with nullable/single-arg
  generic/qualifier stripping so receiver-typed resolution sees the
  concrete class name.
- `import-target.ts` — suffix-match adapter returning a single primary
  file. Cross-file partial-class aggregation runs later at graph-bridge
  time (Unit 6). The csproj-based `resolveCSharpImportInternal` stays
  on the legacy path until Unit 7's parity gate surfaces a gap.
- `captures.ts` routes `@import.statement` matches through the
  decomposer so the interpreter sees the markers it needs.

Tests cover every using flavor + resolution edge cases. 38/38 scope-
resolution C# unit tests pass; tsc clean.
2026-04-21 17:04:24 +01:00
Gergo Magyar
8f5f7cf228 fix(csharp-scope): capture null-conditional receiver + operator decls
Adversarial review surfaced two Unit 1 bugs that would silently
corrupt the graph once C# is flipped on the scope-resolution path:

- `obj?.Save()` only emitted @reference.name, so receiver-bound
  resolution downgraded to the free-call fallback and could mis-link
  to an imported `Save`. Capture the conditional_access_expression
  receiver under @reference.receiver.
- `operator_declaration` had @scope.function but no @declaration.method
  owner, so calls inside operator bodies were attributed to the
  enclosing class and the operator itself disappeared from method
  lookup. Capture the operator token as @declaration.name (downstream
  csharpMethodConfig normalizes to op_Addition etc.).
- `conversion_operator_declaration` was missing from both scope and
  declaration sets. Added with the target type as the name anchor.

Arity metadata for overload resolution remains deferred to Unit 5 and
gated behind Unit 7's parity flip, as documented in captures.ts.
2026-04-21 16:47:06 +01:00
Gergo Magyar
9cec7d16a2 feat(csharp-scope): unit 1 — scope query + captures orchestrator
First slice of the C# scope-resolution migration (issue #934, RFC #909
Ring 3). Closes `Unit 1` of
docs/plans/2026-04-21-004-feat-csharp-scope-resolution-plan.md.

Adds:
- src/core/ingestion/languages/csharp/query.ts — tree-sitter scope
  query covering compilation_unit, namespace (block + file-scoped),
  class-like (class/interface/struct/record/enum), method-like
  (method/constructor/destructor/local_function/operator), property
  and field declarations, using directives, type bindings (parameter
  annotations, local variable annotations, constructor inference,
  invocation alias), and references (free call, member call including
  null-conditional, constructor call, member write).
- src/core/ingestion/languages/csharp/captures.ts — pass-through
  orchestrator mirroring python/captures.ts. Import decomposition
  (Unit 2), receiver-type-binding synthesis (Unit 3), and arity
  metadata synthesis (Unit 5) stub out for future units.
- src/core/ingestion/languages/csharp/cache-stats.ts — PROF
  instrumentation mirror of python/cache-stats.ts.

Design notes:
- Return-type / field-type / property-type captures deferred.
  tree-sitter-c-sharp does not expose these under a clean named field
  that pattern-matches. When Unit 7 parity gate surfaces a gap, add
  positional patterns or a post-hoc extractor lookup.
- object_creation_expression with qualified_name type — the qualified
  name itself is the reference text; captured as a whole via a
  dedicated tag so interpretation in later units can split namespace
  + name.
- Null-conditional calls use positional descendant patterns because
  tree-sitter-c-sharp's member_binding_expression and
  conditional_access_expression don't expose named fields.

Coverage:
- 23/23 new unit tests in
  test/unit/scope-resolution/csharp/csharp-captures.test.ts cover
  every capture tag. Confirmed against tree-sitter-c-sharp via the
  probe-script loop during development; grammar drift would surface
  as a capture-shape assertion failure.
- tsc --noEmit clean.

No changes to shared infrastructure. Resolver wiring + registration
land in Unit 6.
2026-04-21 16:06:00 +01:00