"""PHP `Class::method()` static calls must resolve to the actual method with EXTRACTED confidence, not to a bare-name match on the class itself (#3872). `scoped_call_expression` used the scope text (`Helper` in `Helper::format()`) as the callee name instead of the method name, so the shared cross-file bare-name pass bound every static call to whichever node happened to share the class's label - almost always the class definition - and did so gated on import evidence (INFERRED 0.85) even though the receiver class is named explicitly in source. Same-namespace PHP classes never need a `use` import for each other, so every same-namespace static call was stuck at INFERRED. """ from __future__ import annotations import tempfile from pathlib import Path from graphify.extract import extract def _extract(tmp_path, files: dict[str, str]): for name, body in files.items(): p = tmp_path / name p.parent.mkdir(parents=True, exist_ok=True) p.write_text(body, encoding="utf-8") r = extract([tmp_path / n for n in files], cache_root=Path(tempfile.mkdtemp()), root=tmp_path, parallel=False) labels = {n["id"]: n["label"] for n in r["nodes"]} call_edges = [e for e in r["edges"] if e["relation"] == "calls"] calls = {(labels[e["source"]], labels[e["target"]]): e for e in call_edges} return calls, r def test_same_namespace_static_call_is_extracted_not_inferred(tmp_path): """The exact shape from #3872: a same-namespace static call has no `use` import (none needed), so it must not be penalized as INFERRED.""" calls, _ = _extract(tmp_path, { "Helper.php": ( "method()` was never resolved before this fix (no receiver-typed PHP resolver existed) and must remain so - this fix only targets scoped (`::`) calls, not instance (`->`) calls.""" calls, _ = _extract(tmp_path, { "Helper.php": ( "sanitize($x); }\n}\n"), }) assert not any(s == ".run()" for s, _t in calls)