Version / platform
Source build on Windows x64, MCP server version dev. Upstream base: 96c3f41cf334d87670cb085f1fcf16f637293222; tested with the narrow direct-include fix in #2541, head 7d3e09baf8b132a140ded36443382a8b54530986. This uses the upstream executable, not a reduced fork. Tested binary SHA-256: f932d8fdb7deb0c19f58bb94b1c6cf914ca1c43a565e705e5b7176ed1f410cd5.
Problem
A valid C++ caller obtains ProbeDevice through an indirect include and then includes a header with a forward declaration of that same class. The graph connects RunProbe to methods from two unrelated same-named classes that are not included in this translation unit. Adding a compilation database with the intended header search path does not prevent these wrong edges in this fixture.
This reports a concrete wrong-target result. It does not assume compiler-equivalent analysis is a promised feature, or establish header-search-path handling as the root cause.
Self-contained synthetic reproduction
Save this as make_repro.py and run python make_repro.py. All identifiers and files below are independently constructed synthetic examples.
from pathlib import Path
import json
base = Path("cpp-indirect-repro")
for case in ("quoted_indirect_forward", "search_path_indirect_forward", "direct_control"):
repo = base / case
repo.mkdir(parents=True, exist_ok=True)
for folder, methods in (("alpha", ("Open", "Close")),
("beta", ("Read", "Write")),
("gamma", ("Open", "Close", "Read", "Write"))):
(repo / folder).mkdir(exist_ok=True)
code = "#pragma once\nclass ProbeDevice { public: "
code += " ".join("int " + m + "() { return 0; }" for m in methods)
(repo / folder / "probe_device.h").write_text(code + " };\n", encoding="utf-8")
(repo / "decls.h").write_text("class ProbeDevice;\n", encoding="utf-8")
bridge = ('#include <probe_device.h>\n' if case.startswith("search")
else '#include "gamma/probe_device.h"\n')
(repo / "bridge.h").write_text(bridge, encoding="utf-8")
includes = ('#include "gamma/probe_device.h"\n' if case == "direct_control"
else '#include "bridge.h"\n#include "decls.h"\n')
calls = "void RunProbe(ProbeDevice& dev) { dev.Open(); dev.Close(); dev.Read(); dev.Write(); }\n"
(repo / "caller.cpp").write_text(includes + calls, encoding="utf-8")
if case.startswith("search"):
command = {"directory": str(repo.resolve()),
"file": str((repo / "caller.cpp").resolve()),
"arguments": ["clang++", "-std=c++17", "-Igamma", "-fsyntax-only", "caller.cpp"]}
(repo / "compile_commands.json").write_text(json.dumps([command]), encoding="utf-8")
The three directories are separate test repositories. Only the gamma class is visible to the caller; the alpha and beta headers represent unrelated alternatives in the indexed repository.
Inside each generated directory, this compiler check passed:
clang++ -std=c++17 -Igamma -fsyntax-only caller.cpp
For each directory, index its absolute path with index_repository, using a fresh graph cache (or an explicit full reindex). Use the returned project identifier with query_graph:
MATCH (f:Function)-[r:CALLS]->(c)
WHERE f.name = 'RunProbe'
RETURN c.name, c.file_path, r.strategy, r.confidence
LIMIT 20
Expected
All four calls in RunProbe target the methods in gamma/probe_device.h.
If this receiver cannot be resolved within the supported analysis model, an unresolved/ambiguous result would be preferable to attributing the calls to unrelated alternatives. This does not ask for a particular implementation.
Actual
Both quoted_indirect_forward and search_path_indirect_forward produce:
| Method |
Target file |
Strategy |
Confidence |
| Open |
alpha/probe_device.h |
suffix_match |
0.28 |
| Close |
alpha/probe_device.h |
suffix_match |
0.28 |
| Read |
beta/probe_device.h |
suffix_match |
0.28 |
| Write |
beta/probe_device.h |
suffix_match |
0.28 |
All four targets are wrong for this translation unit. The search_path_indirect_forward case includes a generated compile_commands.json with -Igamma.
The direct_control case targets gamma/probe_device.h for all four methods, with lsp_base_dispatch / 0.95. The control changes both the include form and the extra forward-declaration include, so it does not isolate either as the sole cause.
Partial-parse and unusable-parse counts were both zero in all three cases. These wrong edges are low-confidence heuristic edges; that limitation is visible, but they still identify unrelated methods as callees.
Related
No proprietary source, identifiers, absolute machine paths, project-derived IDs or internal logs are included.
Version / platform
Source build on Windows x64, MCP server version
dev. Upstream base:96c3f41cf334d87670cb085f1fcf16f637293222; tested with the narrow direct-include fix in #2541, head7d3e09baf8b132a140ded36443382a8b54530986. This uses the upstream executable, not a reduced fork. Tested binary SHA-256:f932d8fdb7deb0c19f58bb94b1c6cf914ca1c43a565e705e5b7176ed1f410cd5.Problem
A valid C++ caller obtains
ProbeDevicethrough an indirect include and then includes a header with a forward declaration of that same class. The graph connectsRunProbeto methods from two unrelated same-named classes that are not included in this translation unit. Adding a compilation database with the intended header search path does not prevent these wrong edges in this fixture.This reports a concrete wrong-target result. It does not assume compiler-equivalent analysis is a promised feature, or establish header-search-path handling as the root cause.
Self-contained synthetic reproduction
Save this as
make_repro.pyand runpython make_repro.py. All identifiers and files below are independently constructed synthetic examples.The three directories are separate test repositories. Only the
gammaclass is visible to the caller; thealphaandbetaheaders represent unrelated alternatives in the indexed repository.Inside each generated directory, this compiler check passed:
For each directory, index its absolute path with
index_repository, using a fresh graph cache (or an explicit full reindex). Use the returned project identifier withquery_graph:Expected
All four calls in
RunProbetarget the methods ingamma/probe_device.h.If this receiver cannot be resolved within the supported analysis model, an unresolved/ambiguous result would be preferable to attributing the calls to unrelated alternatives. This does not ask for a particular implementation.
Actual
Both
quoted_indirect_forwardandsearch_path_indirect_forwardproduce:All four targets are wrong for this translation unit. The
search_path_indirect_forwardcase includes a generatedcompile_commands.jsonwith-Igamma.The
direct_controlcase targetsgamma/probe_device.hfor all four methods, withlsp_base_dispatch/0.95. The control changes both the include form and the extra forward-declaration include, so it does not isolate either as the sole cause.Partial-parse and unusable-parse counts were both zero in all three cases. These wrong edges are low-confidence heuristic edges; that limitation is visible, but they still identify unrelated methods as callees.
Related
No proprietary source, identifiers, absolute machine paths, project-derived IDs or internal logs are included.