Found by a spike, not by a test
Src/Newtonsoft.Json/JsonReader.Async.cs:
public abstract partial class JsonReader
#if HAVE_ASYNC_DISPOSABLE
: IAsyncDisposable
#endif
{
…
The declaration's name is JsonReader. The extractor emits Newtonsoft.HAVE_ASYNC_DISPOSABLE — the preprocessor symbol — and hangs 48 members off it:
class Newtonsoft.HAVE_ASYNC_DISPOSABLE JsonReader.Async.cs L36-L261
method Newtonsoft.HAVE_ASYNC_DISPOSABLE.DisposeAsync L42-L53
method Newtonsoft.HAVE_ASYNC_DISPOSABLE.MoveToContentAsync L230-L240
declName scans forward from the declaration node for name-typed children, and the #if identifier sits between the class name and the {, so it wins.
Why this matters more than 48 nodes
Those 48 are JsonReader's async surface, attributed to a class that does not exist. So:
card JsonReader under-reports its members.
affected/change-plan on JsonReader misses everything in the .Async.cs partial.
- Any query about
DisposeAsync / MoveToContentAsync cites a fictional owner.
- It creates a fake resolution candidate: a spike measuring receiver-type inference kept hitting
candidates owned by ['Newtonsoft.HAVE_ASYNC_DISPOSABLE', 'Newtonsoft.JsonTextReader'] — the phantom class competing with the real one, which is exactly the kind of thing that turns a resolvable call into an AMBIGUOUS shortlist.
This corpus is newtonsoft, one of the two pinned judged corpora, and JsonReader's async members being unreachable is a plausible contributor to the low judged score tracked in #11.
Scope, measured
57 of 10,120 nodes on this corpus are named or owned by a SCREAMING_CASE symbol; 48 are this one bug (the rest are legitimate — README, LICENSE, IEEE754, doc sections).
Not measured: how often this shape occurs outside Newtonsoft. C# partial class X #if … : IFoo #endif { is a common conditional-compilation idiom, and the same trap exists anywhere a directive can sit between a declaration's name and its body. Worth checking C/C++ too, where #if between a struct name and brace is legal and common.
Likely fix
declName should take the first name-typed child at the shallowest depth (the declaration's own identifier) rather than scanning past it, or explicitly skip preproc_* node types. tree-sitter's C# grammar exposes preproc_if / preproc_directive as distinct node kinds, so this can be a structural exclusion rather than a heuristic — no guessing about what a name "looks like".
Needs a fixture in internal/golden/testdata/repos/ reproducing the shape, and it will move the newtonsoft corpus node/edge counts (currently pinned at 10120/24130) — a reviewed diff.
Found by a spike, not by a test
Src/Newtonsoft.Json/JsonReader.Async.cs:The declaration's name is
JsonReader. The extractor emitsNewtonsoft.HAVE_ASYNC_DISPOSABLE— the preprocessor symbol — and hangs 48 members off it:declNamescans forward from the declaration node for name-typed children, and the#ifidentifier sits between the class name and the{, so it wins.Why this matters more than 48 nodes
Those 48 are
JsonReader's async surface, attributed to a class that does not exist. So:card JsonReaderunder-reports its members.affected/change-planonJsonReadermisses everything in the.Async.cspartial.DisposeAsync/MoveToContentAsynccites a fictional owner.candidates owned by ['Newtonsoft.HAVE_ASYNC_DISPOSABLE', 'Newtonsoft.JsonTextReader']— the phantom class competing with the real one, which is exactly the kind of thing that turns a resolvable call into an AMBIGUOUS shortlist.This corpus is
newtonsoft, one of the two pinned judged corpora, andJsonReader's async members being unreachable is a plausible contributor to the low judged score tracked in #11.Scope, measured
57 of 10,120 nodes on this corpus are named or owned by a SCREAMING_CASE symbol; 48 are this one bug (the rest are legitimate —
README,LICENSE,IEEE754, doc sections).Not measured: how often this shape occurs outside Newtonsoft. C#
partial class X #if … : IFoo #endif {is a common conditional-compilation idiom, and the same trap exists anywhere a directive can sit between a declaration's name and its body. Worth checking C/C++ too, where#ifbetween a struct name and brace is legal and common.Likely fix
declNameshould take the first name-typed child at the shallowest depth (the declaration's own identifier) rather than scanning past it, or explicitly skippreproc_*node types. tree-sitter's C# grammar exposespreproc_if/preproc_directiveas distinct node kinds, so this can be a structural exclusion rather than a heuristic — no guessing about what a name "looks like".Needs a fixture in
internal/golden/testdata/repos/reproducing the shape, and it will move thenewtonsoftcorpus node/edge counts (currently pinned at 10120/24130) — a reviewed diff.