mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 15:40:05 +00:00
fix(go): preserve interface method signature references
(cherry picked from commit 00fb309983)
This commit is contained in:
1 parent
6fdc26db03
commit
bda82f9ded
2 files changed
+60
No files matched your search
@@ -390,6 +390,7 @@ def extract_go(path: Path) -> dict:
|
||||
m_nid = symbol_nid(_make_id(type_nid, m_name), m_name)
|
||||
add_node(m_nid, f".{m_name}()", m_line)
|
||||
add_edge(type_nid, m_nid, "method", m_line)
|
||||
emit_go_method_refs(elem, m_nid, m_line)
|
||||
continue
|
||||
if elem.type != "type_elem":
|
||||
continue
|
||||
|
||||
@@ -8,6 +8,8 @@ an empty node with no members - the method requirements were dropped entirely.
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from graphify.extract import extract
|
||||
|
||||
|
||||
@@ -106,3 +108,60 @@ def test_interface_method_is_distinct_from_a_concrete_method(tmp_path: Path) ->
|
||||
}
|
||||
assert shape_area and rect_area
|
||||
assert shape_area.isdisjoint(rect_area), "interface and struct methods collapsed"
|
||||
|
||||
|
||||
def _signature_refs(result: dict, owner_label: str) -> tuple[str, list[dict]]:
|
||||
by_id = {node["id"]: node for node in result["nodes"]}
|
||||
method_ids = {
|
||||
edge["target"]
|
||||
for edge in result["edges"]
|
||||
if edge.get("relation") == "method"
|
||||
and by_id[edge["source"]].get("label") == owner_label
|
||||
}
|
||||
assert len(method_ids) == 1
|
||||
method_id = method_ids.pop()
|
||||
return method_id, [
|
||||
{**edge, "target_label": by_id[edge["target"]]["label"]}
|
||||
for edge in result["edges"]
|
||||
if edge.get("relation") == "references" and edge["source"] == method_id
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("signature", "body"),
|
||||
[
|
||||
("Handle(Request) Response", "return Response{}"),
|
||||
("Handle(req *Request) (res *Response, err error)", "return nil, nil"),
|
||||
],
|
||||
)
|
||||
def test_interface_method_signature_keeps_type_references(tmp_path: Path, signature, body):
|
||||
path = tmp_path / "contract.go"
|
||||
path.write_text(
|
||||
"package contracts\n\n"
|
||||
"type Request struct{}\n"
|
||||
"type Response struct{}\n"
|
||||
"type Service interface {\n"
|
||||
f" {signature}\n"
|
||||
"}\n\n"
|
||||
"type Impl struct{}\n"
|
||||
f"func (Impl) {signature} {{ {body} }}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = _extract(tmp_path)
|
||||
interface_id, interface_refs = _signature_refs(result, "Service")
|
||||
concrete_id, concrete_refs = _signature_refs(result, "Impl")
|
||||
expected = {("Request", "parameter_type"), ("Response", "return_type")}
|
||||
assert {(edge["target_label"], edge["context"]) for edge in concrete_refs} == expected
|
||||
assert {(edge["target_label"], edge["context"]) for edge in interface_refs} == expected
|
||||
assert len(interface_refs) == 2
|
||||
assert interface_id != concrete_id
|
||||
assert not any(node["label"] == "error" for node in result["nodes"])
|
||||
for edge in interface_refs:
|
||||
assert edge["source_file"] == "contract.go"
|
||||
assert edge["source_location"] == "L6"
|
||||
assert edge["confidence"] == "EXTRACTED"
|
||||
|
||||
# A warm extraction replays the same source-owned signature edges.
|
||||
warm = _extract(tmp_path)
|
||||
assert _signature_refs(warm, "Service") == (interface_id, interface_refs)
|
||||
assert _signature_refs(warm, "Impl") == (concrete_id, concrete_refs)
|
||||
Reference in new issue
Block a user