diff --git a/tests/test_cpp_objc_cross_file_calls.py b/tests/test_cpp_objc_cross_file_calls.py index 22e631fd4..fbcd192c5 100644 --- a/tests/test_cpp_objc_cross_file_calls.py +++ b/tests/test_cpp_objc_cross_file_calls.py @@ -167,6 +167,48 @@ def test_cpp_qualified_call_resolves_to_a_qualified_only_definition(tmp_path: Pa assert ("useIt()", "calls", "AHelper::FindNearest()", "EXTRACTED") in calls +def test_cpp_qualified_only_call_stays_ambiguous_across_two_classes(tmp_path: Path): + """The exactly-one-candidate guard still applies to the qualified-only + fallback: two DIFFERENT classes that both fail header parsing and both + happen to share a class name and a method name must not let a call + resolve to either one.""" + base = tmp_path / "src" + header = ( + "#pragma once\n" + '#include "a.generated.h"\n' + "UCLASS()\n" + "class AFoo : public AActor {\n" + " GENERATED_BODY()\n" + "public:\n" + " UFUNCTION()\n" + " static AFoo* FindNearest(UWorld* W);\n" + "};\n" + ) + body = ( + '#include "a.h"\n' + "AFoo* AFoo::FindNearest(UWorld* W) { return nullptr; }\n" + ) + _write(base / "a.h", header) + _write(base / "a.cpp", body) + _write(base / "sub" / "a.h", header) + _write(base / "sub" / "a.cpp", body) + _write(base / "caller.cpp", ( + '#include "a.h"\n' + "void useIt(UWorld* W) {\n" + " AFoo* h = AFoo::FindNearest(W);\n" + " (void)h;\n" + "}\n" + )) + paths = sorted(base.glob("*")) + sorted((base / "sub").glob("*")) + result = extract(paths, cache_root=tmp_path / "cache") + + calls = _call_edges(result) + assert not any( + rel == "calls" and src == "useIt()" + for src, rel, _, _ in calls + ) + + def test_cpp_this_member_call_resolves_to_enclosing_class(tmp_path: Path): # `this->bar()` inside Foo::baz resolves to Foo::bar (the caller's own class) -> # EXTRACTED. Cross-file: the body lives in Foo.cpp, the decl in Foo.h.