Skip to content

fix(parsers): parse C# fields and locals - #1584

Merged
Shashankss1205 merged 2 commits into
mainfrom
fix/parser-csharp-variables
Aug 5, 2026
Merged

Shashankss1205 merged 2 commits into
mainfrom
fix/parser-csharp-variables

Conversation

@Shashankss1205

Copy link
Copy Markdown
Collaborator

Fixes #1525. Full suite: 1136 passed, 7 skipped, no failures.

The bug

variables was hardcoded to [] and CSHARP_QUERIES had no variables entry at all — C# produced zero Variable nodes.

The larger cost was downstream. resolution/calls.py uses local-variable declarations to infer a receiver's type, so:

var svc = new UserService();
svc.Save();

could not resolve Save to UserService.Save, and C# method calls fell back to name-only heuristics.

The fix

Fields and locals share a shape — variable_declaration carries the type and holds one variable_declarator per name — so one query covers both:

  L2 _count   type=int      value=1                   ctx=None  cls=UserService
  L3 Name     type=string   value=None                ctx=None  cls=UserService
  L4 A        type=int      value=1                   ctx=None  cls=UserService
  L4 B        type=int      value=2                   ctx=None  cls=UserService
  L6 total    type=int      value=0                   ctx=Save  cls=UserService
  L7 svc      type=var      value=new UserService()   ctx=Save  cls=UserService

int A = 1, B = 2; correctly yields two rows sharing a type, and locals carry their enclosing method as context.

One grammar detail worth recording: tree-sitter-c-sharp has no equals_value_clause — the initialiser is a direct sibling after the = token. My first attempt looked for that node and returned value: None for everything. Capturing it is what makes var svc = new UserService() usable for receiver-type inference.

Golden — please read this bit

The raw diff looks larger than the change. The committed C# golden was already stale, which I only found by controlling for it: regenerating on an unmodified main alone produces

Directory   6 ->  9      CALLS     12 ->  7
File       15 -> 20      IMPORTS   21 -> 32
Module      9 -> 12      CONTAINS 132 -> 140

That drift is unrelated to this PR and is carried along because the file had to be regenerated. Measured against a clean-main regeneration, this change contributes exactly:

nodes  Variable    0 -> 15  (+15)
edges  CONTAINS  140 -> 155 (+15)
(nothing else changed)

Purely additive, and in particular the CALLS 12 -> 7 drop is not from this change — I checked, because a CALLS regression is what made me abandon the JS/TS import fix in #1526.

I also confirmed the regeneration is deterministic (two identical runs, identical counts), so none of the above is golden noise.

The stale baseline is worth its own issue — a golden that no longer matches what the code produces means the C# parity signal has been silently degraded for a while.

Tests

tests/unit/parsers/test_csharp_variables.py — 8 tests covering fields, locals, multi-declarator, method/class context, initialisers, and the var x = new T() inference case specifically.

🤖 Generated with Claude Code

`variables` was hardcoded to `[]` and CSHARP_QUERIES had no `variables`
entry at all, so C# produced zero Variable nodes.

The larger cost was downstream: `resolution/calls.py` uses local-variable
declarations to infer a receiver's type, so

    var svc = new UserService();
    svc.Save();

could not resolve Save to UserService.Save — C# method calls fell back to
name-only heuristics.

Fields and locals share a shape: `variable_declaration` carries the type
and holds one `variable_declarator` per name, so `int A = 1, B = 2;`
yields two rows sharing a type. Both are captured, with the enclosing
method as `context` and the enclosing type as `class_context`.

One grammar detail worth recording: tree-sitter-c-sharp has no
`equals_value_clause`. The initialiser is a direct sibling after the `=`
token, which is what makes `var svc = new UserService()` usable for
receiver-type inference.

Golden for sample_project_csharp regenerated: +15 Variable nodes and the
+15 File->CONTAINS->Variable edges, nothing else.

Note the committed golden was already stale before this change —
regenerating on an unmodified main alone yields +3 Directory, +5 File,
+3 Module, CALLS 12->7 and IMPORTS 21->32. That drift is unrelated to this
work and is carried along here because the file had to be regenerated;
measured against a clean-main regeneration, this change contributes only
the Variable nodes and their CONTAINS edges.

Co-Authored-By: Claude Fable 5 <[email protected]>
@vercel

vercel Bot commented Aug 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
code-graph-context-pack Ready Ready Preview Aug 5, 2026 7:54pm

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Hi! 👋 Join our CodeGraphContext Discord channel to collaborate: https://discord.gg/dR4QY32uYQ

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Code Graph Analysis

fix(parsers): parse C# fields and locals (#1584)

📊 Interactive Visualization

View the blast radius graph: PR Reviewer Dashboard

📦 Artifacts

The graph JSON has been uploaded as a build artifact: pr-code-graph-1584


Generated by CodeGraphContext using FalkorDB Lite

@Shashankss1205
Shashankss1205 merged commit e367db2 into main Aug 5, 2026
18 checks passed
@Shashankss1205
Shashankss1205 deleted the fix/parser-csharp-variables branch August 5, 2026 20:02
@github-project-automation github-project-automation Bot moved this from Backlog tasks to Done in CGC Progress Board Aug 5, 2026
Shashankss1205 added a commit that referenced this pull request Aug 8, 2026
Ten PRs since 0.5.6 — mostly parser correctness, all with regression tests.

Parsers
- Ruby nested classes no longer delete their parent; method parameters
  extracted at all (#1523, #1527, #1581)
- C/C++ functions returning a pointer or reference are extracted, and
  registered in pre_scan so they resolve as call targets (#1524, #1582)
- C# fields and locals parsed, restoring receiver-type inference for
  `var x = new T(); x.M();` (#1525, #1584)
- JavaScript destructured, array and rest parameters extracted, recording
  the binding names rather than a placeholder (#1527, #1591)

Queries and analysis
- Five defects that returned wrong answers without erroring: inflated
  repository stats, misattributed callers, discarded graph_name,
  count(*) after OPTIONAL MATCH, an ignored tool argument (#1577)
- Dead-code detection made correct and self-consistent, including the
  JS module-level false positive (#600, #1559, #1578)

Indexing
- add_package_to_graph on a flat module no longer indexes the whole
  virtualenv (#1528, #1586)
- SCIP job progress no longer exceeds 100% (#1535, #1583)

Docs and tests
- Database Options table columns realigned (#1590)
- MCP tool definition contract validation (#1580)

Co-authored-by: Claude Fable 5 <[email protected]>

This branch was successfully deployed

1 active deployment
Preview — 9ff5db2f Deployed Aug 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

bug(indexer): C# variables is hardcoded to [] — no fields or locals are parsed, breaking receiver-type inference for method calls

1 participant