mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-18 18:09:28 +00:00
fix(csharp): resolve calls through casts and interface-typed properties (#3797)
((IStore)_obj).Save() and (_obj as IStore).Save() produced no calls edge:
the receiver capture didn't handle a parenthesized cast, so the call never
reached the receiver-typed resolver. Use the cast's type as the receiver so
it resolves like IStore.Save().
IStore Store => ...; Store.Save() bound to the concrete Store.Save() because
a capitalised receiver was looked up as a type name first. A field, property
or local of that name shadows the type, so try the recorded receiver_type
first and fall back to the type name.
Co-Authored-By: Grok Bot <noreply@x.ai>
(cherry picked from commit 2d26dad2ab)
This commit is contained in:
1 parent
f50b79ffc5
commit
ac467b0c00
3 files changed
+67
-6
No files matched your search
@@ -353,6 +353,53 @@ def test_null_conditional_cross_file_receiver_resolves(tmp_path):
|
||||
assert not any("commit" in s and "cache_save" in t for s, t in calls)
|
||||
|
||||
|
||||
_STORE = (
|
||||
"public interface IStore { void Save(); }\n"
|
||||
"public class Store : IStore { public void Save() { } }\n"
|
||||
)
|
||||
|
||||
|
||||
def _store_call(tmp_path, editor_body: str):
|
||||
"""Call `IStore.Save()` from another file; return (calls, caller, IStore.Save, Store.Save)."""
|
||||
calls, r = _calls(tmp_path, {
|
||||
"Store.cs": _STORE,
|
||||
"Editor.cs": (
|
||||
"public class Editor {\n"
|
||||
" object _obj;\n"
|
||||
" IStore Store => (IStore)_obj;\n"
|
||||
f" public void Run() {{ {editor_body} }}\n"
|
||||
"}\n"
|
||||
),
|
||||
})
|
||||
run = _find(r, ".Run()", "editor")
|
||||
istore_save = _find(r, ".Save()", "istore")
|
||||
store_save = next(n["id"] for n in r["nodes"]
|
||||
if n["label"] == ".Save()" and n["id"] != istore_save)
|
||||
return calls, run, istore_save, store_save
|
||||
|
||||
|
||||
def test_cast_receiver_resolves_to_cast_type(tmp_path):
|
||||
"""`((IStore)_obj).Save()`: the cast names the receiver type (#3797)."""
|
||||
calls, run, istore_save, store_save = _store_call(tmp_path, "((IStore)_obj).Save();")
|
||||
assert (run, istore_save) in calls
|
||||
assert (run, store_save) not in calls
|
||||
|
||||
|
||||
def test_as_cast_receiver_resolves_to_cast_type(tmp_path):
|
||||
"""`(_obj as IStore).Save()` types the receiver the same way (#3797)."""
|
||||
calls, run, istore_save, store_save = _store_call(tmp_path, "(_obj as IStore).Save();")
|
||||
assert (run, istore_save) in calls
|
||||
assert (run, store_save) not in calls
|
||||
|
||||
|
||||
def test_property_receiver_shadows_same_named_type(tmp_path):
|
||||
"""`IStore Store => ...; Store.Save()`: inside Editor `Store` is the
|
||||
property, so the call is IStore.Save, not the class Store's (#3797)."""
|
||||
calls, run, istore_save, store_save = _store_call(tmp_path, "Store.Save();")
|
||||
assert (run, istore_save) in calls
|
||||
assert (run, store_save) not in calls
|
||||
|
||||
|
||||
def test_base_receiver_resolves_to_base_class_method(tmp_path):
|
||||
calls, r = _calls(tmp_path, {
|
||||
"Base.cs": "public class BaseSvc { public bool Ping() => true; }\n",
|
||||
|
||||
Reference in new issue
Block a user