Skip to content

fix(trace-path): store C# call targets with the receiver's declared type - #126

Merged
spelech merged 1 commit into
mainfrom
fix/csharp-typed-call-targets
Nov 12, 2026
Merged

spelech merged 1 commit into
mainfrom
fix/csharp-typed-call-targets

Conversation

@spelech

@spelech spelech commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Problem

#123 did not fix trace_path on a real repository. Calls are stored with the bare method name (_toolService.PublishInstance() → PublishInstance), and this layout injects concrete classes into fields:

public class ToolsController
{
    private readonly ToolService _toolService;
    ...
    return Ok(await _toolService.PublishInstance(id));

The callers of AssistantService.PublishInstance still included ToolsController.PublishInstance and ToolService.PublishInstance. The DI check from #123 compares constructor signatures, but the stored signature is only the first line (public ToolsController(), and there are no interfaces to match.

Fix

  • New app/services/chunking/csharp_receiver_types.py. For receiver.Method(...) with a simple receiver (x or this.x), it finds the declared type in the nearest scope: method parameters, locals (var x = new T() included), foreach variables, then fields, properties, and primary-constructor parameters of the enclosing type. Generic arguments, namespaces, and ? are removed. Built-in types, var without new, static calls, and unknown names keep the bare name.
  • symbol_extractor.py stores C# CALLS targets as Type.Method when the type is known.
  • graph_traversal.py: the existing caller filter already drops a qualified target of another class. New: a resolved interface method maps to its only implementation (IOrderRepository.SaveAsync → SqlOrderRepository.SaveAsync).
  • topology/graph_builder.py: a typed target matches the full symbol first, then the method name.
  • diagnostics.py (find_references callers): a short name also matches %.Name.

Existing indexes get the typed targets when C# files are indexed again.

Tests

  • tests/test_csharp_typed_call_targets.py: receiver types from fields, this. fields, parameters, new locals, primary-constructor parameters, properties, and foreach; a parameter hides a field; unknown receivers stay bare. End to end through process_file_content: controller → service → repository with concrete injection, each PublishInstance gets only its real caller, and callees follow the field type.
  • The existing C# DI test (test_csharp_primary_ctors_records_mapgroup_routes_and_di_call_tracing) passes locally with the C# grammar.
  • Checked on the real repository: all four PublishInstance call sites resolve to the correct class.

🤖 Generated with Claude Code

C# calls were stored with the bare method name, so `_toolService.PublishInstance()`
matched every class with a PublishInstance method. In a layout that injects
concrete classes (no interfaces), trace_path listed ToolsController and
ToolService as callers of AssistantService.PublishInstance, and the
signature-based DI check could not help: the stored signature is only the
first line of the constructor.

The extractor now resolves a simple receiver (`x` or `this.x`) to its declared
type from the nearest scope: method parameters, locals (`var x = new T()`
included), foreach variables, then fields, properties, and primary-constructor
parameters of the enclosing type. The call is stored as `Type.Method`. Unknown
receivers keep the bare name.

Readers of CALLS targets handle typed targets:
- trace_path maps an interface method to its only implementation.
- The topology graph matches a typed target by full symbol first.
- find_references callers also match `%.Name` for a short name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@spelech
spelech merged commit b2a7e52 into main Nov 12, 2026
15 checks passed
@spelech
spelech deleted the fix/csharp-typed-call-targets branch November 12, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant