Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions graphify/extractors/commonlisp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import warnings
from pathlib import Path

from graphify.extractors.base import _make_id
from graphify.extractors.base import _file_stem, _make_id


# Standard CL definer forms that introduce data/type/variable bindings
Expand Down Expand Up @@ -84,7 +84,11 @@ def extract_commonlisp(path: Path) -> dict:
except Exception as e:
return {"nodes": [], "edges": [], "error": str(e)}

stem = path.stem
# Path-qualified, not the bare `path.stem`: same-named .lisp files in
# different directories must not collide (#1504). Pre-collapsed through
# `_make_id` because `_cl_id` would otherwise map the `/` separators to
# `_slash` via _CL_CHAR_MAP.
stem = _make_id(_file_stem(path))
str_path = str(path)
nodes: list[dict] = []
edges: list[dict] = []
Expand Down
22 changes: 22 additions & 0 deletions tests/test_languages.py
Original file line number Diff line number Diff line change
Expand Up @@ -3974,3 +3974,25 @@ def test_zig_enum_and_union_methods_are_extracted(tmp_path):
for e in r["edges"] if e["relation"] == "calls"
}
assert (".area()", "helper()") in calls, "call from union method body dropped"


@_needs_commonlisp
def test_cl_ids_are_path_qualified_across_directories(tmp_path):
"""Two same-named .lisp files in DIFFERENT directories must mint distinct
ids (#1504). The prefix was derived from the bare `path.stem`, so both
`a/sample.lisp` and `b/sample.lisp` minted `sample` / `sample_init`; when
they land in separate extract batches (what `graphify update` does) build()
merges them and one file's nodes are dropped."""
a = tmp_path / "a" / "sample.lisp"
b = tmp_path / "b" / "sample.lisp"
for p in (a, b):
p.parent.mkdir(parents=True)
p.write_text("(defun init (x) (+ x 1))\n")

ids_a = {n["id"] for n in extract_commonlisp(a)["nodes"]}
ids_b = {n["id"] for n in extract_commonlisp(b)["nodes"]}

assert not (ids_a & ids_b), (
f"same-named .lisp files in different dirs must not share ids, "
f"got overlap {sorted(ids_a & ids_b)}"
)