Files
graphify/tests/test_elixir_defdelegate.py
T
safishamsiandClaude Opus 4.8 93de0d4aea fix(elixir): extract defdelegate as a function definition (#4132)
`defdelegate name(args), to: Mod` declares an invocable function with the same
`call` head shape as `def`, but was missing from the def-family recognizer, so no
node was minted and same-module calls to the delegated name dangled. Add
`defdelegate` to the def-family tuple and to the call-pass skip set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-10 21:20:29 +01:00

66 lines
2.2 KiB
Python

"""`defdelegate` defines an invocable function in the module (#4132).
`defdelegate greet(name), to: Greeter` declares a callable `greet` whose body is
delegated to another module. It has the same `call` head shape as `def`, but was
missing from the def-family recognizer, so no node was minted and same-module
calls to the delegated name dangled.
"""
from __future__ import annotations
from pathlib import Path
from graphify.extract import extract
def _graph(tmp_path: Path):
src = tmp_path / "facade.ex"
src.write_text(
"defmodule Facade do\n"
" defdelegate start(x), to: Worker\n"
" defdelegate stop(x), to: Worker, as: :halt\n"
" def run(x) do\n"
" start(x)\n"
" stop(x)\n"
" end\n"
"end\n",
encoding="utf-8",
)
result = extract([src], cache_root=tmp_path / "graphify-out")
label = {n["id"]: n["label"] for n in result["nodes"]}
return result, label
def _edges(result, label, relation):
return {
(label[e["source"]], label[e["target"]])
for e in result["edges"]
if e["relation"] == relation and e["source"] in label and e["target"] in label
}
def test_defdelegate_defines_functions(tmp_path: Path) -> None:
result, label = _graph(tmp_path)
labels = set(label.values())
assert "start()" in labels, "defdelegate function dropped"
assert "stop()" in labels, "defdelegate-with-as function dropped"
methods = _edges(result, label, "method")
assert ("Facade", "start()") in methods
assert ("Facade", "stop()") in methods
def test_defdelegate_same_module_calls_resolve(tmp_path: Path) -> None:
result, label = _graph(tmp_path)
calls = _edges(result, label, "calls")
assert ("run()", "start()") in calls, "call to a delegated function dangled"
assert ("run()", "stop()") in calls
def test_defdelegate_leaves_no_dangling_edges(tmp_path: Path) -> None:
result, _ = _graph(tmp_path)
node_ids = {n["id"] for n in result["nodes"]}
dangling = [
e for e in result["edges"]
if e["source"] not in node_ids or e["target"] not in node_ids
]
assert not dangling, f"defdelegate produced dangling edges: {dangling}"