mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-18 18:09:28 +00:00
resolve_interface_dispatch (shared by the C# and Swift gates) bailed out
entirely whenever an interface/protocol had more than one implementer,
on the reasoning that guessing which one a runtime call reaches would be
wrong. For a static structural graph the question isn't which one is
reached at runtime, it's which ones *can* be reached, and the answer with
N implementers is all N, not none -- so every chain through an injected
dependency with more than one implementation was left permanently cut at
the interface.
Each implementer is still subject to the existing single-owner guard
independently: an implementer that itself declares more than one method
of the same name is skipped on its own, without suppressing its siblings.
Confidence drops as the candidate set grows, using the extraction
rubric's own discrete INFERRED tiers (0.85 / 0.75 / 0.65 floor) instead of
inventing continuous precision.
Fixes #3800 for the dispatches_to half (interface->implementation calls).
The property-access half of that issue (a method edge for `c.Count`
through an interface-typed receiver) is a separate mechanism and is not
addressed here, to keep this PR to one concern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit f340494e07)
40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""Member-level interface dispatch for C# (#3003).
|
|
|
|
A C# call through a constructor-injected dependency lands on the interface's
|
|
method node, because that is what the call site names: `_report.Build()` where
|
|
`_report` is an `IReport` resolves to `IReport.Build()`. The implementing
|
|
`Report.Build()` is a separate node, and nothing joins the two, so a directed
|
|
walk stops at the interface and every chain through an injected dependency is
|
|
cut at that point. On a Scrutor-scanned .NET service where every dependency is
|
|
an interface, that is most chains.
|
|
|
|
The mechanism — single-owner, per-method `dispatches_to` edges at INFERRED,
|
|
fanning out to every implementer — lives in `graphify.interface_dispatch` so
|
|
that another language can add a gate rather than a copy; this module fixes
|
|
the C# gate.
|
|
Both ends of a pair must be declared in a `.cs` file: `implements` is
|
|
resolved by name, so in a mixed corpus a Java class declaring
|
|
`implements IReport` binds to a C# `IReport` when that is the only node with
|
|
the name, and linking a C# interface member to a Java method would be a wrong
|
|
edge rather than a missing one. A non-C# implementation of a C# interface,
|
|
from VB or a Razor component, is a real thing, but claiming it needs its own
|
|
extractor evidence.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from graphify.interface_dispatch import ( # noqa: F401 (re-exported for callers)
|
|
DISPATCH_RELATION,
|
|
method_label as _method_label,
|
|
resolve_interface_dispatch,
|
|
)
|
|
|
|
_CSHARP_SUFFIXES = (".cs",)
|
|
|
|
def resolve_csharp_interface_dispatch(
|
|
per_file: list[dict],
|
|
all_nodes: list[dict],
|
|
all_edges: list[dict],
|
|
) -> None:
|
|
"""Link each C# interface method to every implementation that owns it unambiguously."""
|
|
resolve_interface_dispatch(per_file, all_nodes, all_edges, suffixes=_CSHARP_SUFFIXES)
|