You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
C#: calls through interfaces / virtual members are not attributed to implementers (0 inbound callers); overloads bound by name only #2893
Context. We index a large legacy .NET codebase (≈45k C# files, 64 solutions, mixed .NET Framework / ASP.NET Web Forms / EF6 / EF Core, ~1.9M nodes) with codebase-memory-mcp 0.11.0 (production) and 0.12.1 (trial). To know how far to trust the graph we built a Roslyn 5.9 reference (MSBuildWorkspace per solution, SemanticModel.GetSymbolInfo on every invocation / object creation) and compared edge by edge (key = caller file, call line ±1, target name; the engine's properties.line/strategy/confidence were used). Numbers below are from one sub-repo (8,458 files, 904,672 call sites, 310,119 with the target defined in the repo); the two larger sub-repos (≈1.4M and ≈2.6M call sites) show the same picture within a few points. Related: #2874 (INHERITS loss with constructors) and #2876 (maintainer C# gap list).
1. Interface / virtual dispatch is invisible. Calls through an interface receiver (DI-injected IFooService.GetByKey(...)) produce an edge to the interface method; implementers show 0 inbound callers, so "who calls FooService.GetByKey" is answered "nobody" although the class is called through its interface from many places. The data to derive this exists: Roslyn finds implementers for 100 % of the 106 source interfaces in this sub-repo and the engine's own IMPLEMENTS recall is 98.2 % in 0.12.1 (88.8 % in 0.11.0). Example shape: IUnitBusiness.GetByReferenceKey → 2 implementing classes in different projects, 4 Roslyn call sites through the interface, 0 graph callers on either implementation.
2. Overload resolution by name only. 16,927 call sites (5.5 % of the resolved ones) have several same-name overloads in the target type; the engine picks one by name, Roslyn by arity/argument types, so inbound lists mix overloads and sometimes point to the wrong one.
Suggestions. (a) A query-time option (trace_path … expand_dispatch=true, same for inbound callers) or a derived CALLS_VIA_INTERFACE edge from the interface/virtual member to each implementer/override, so inbound traces on an implementation include calls made through its interfaces and base virtuals (IMPLEMENTS/OVERRIDES edges already carry what is needed); (b) at least arity-aware overload binding — the argument count is available syntactically — with confidence lowered when several overloads still match.
Reproduction / offer. Our comparison script (reads the engine's SQLite graph and a Roslyn-produced SQLite call map, reports recall/precision per strategy with the error classes above) and the Roslyn extractor are generic (.NET 8, Microsoft.CodeAnalysis 5.9). We can share both, and can run any candidate build against the same corpus and report the same tables.
Activity