struct graph

This commit is contained in:
2026-09-07 15:52:46 -04:00
parent 30ed3351b5
commit 93521c53fb
15 changed files with 1061 additions and 30 deletions

View File

@@ -903,3 +903,221 @@ fn function_graph_depth_namespaces_and_cycles() {
);
server.stop();
}
#[test]
#[ignore = "requires clangd"]
fn type_graph_constraints_and_members() {
let temp = tempdir().unwrap();
let root = temp.path();
let build = root.join("build");
fs::create_dir_all(build.join("meson-info")).unwrap();
fs::write(build.join("meson-info/intro-projectinfo.json"), "{}").unwrap();
fs::write(
root.join("types.hpp"),
include_str!("../../../../examples/types/types.hpp"),
)
.unwrap();
fs::write(
root.join("main.cpp"),
include_str!("../../../../examples/types/main.cpp"),
)
.unwrap();
fs::write(build.join("compile_commands.json"),serde_json::to_vec(&json!([{"directory":root,"file":root.join("main.cpp"),"arguments":["clang++","-std=c++23","-c",root.join("main.cpp")]}])).unwrap()).unwrap();
let server = Clangd::start(crate::open(root, Some(&build), false).unwrap()).unwrap();
let source = include_str!("../../../../examples/types/types.hpp");
let position = |needle: &str| {
let (line, text) = source
.lines()
.enumerate()
.find(|(_, l)| l.contains(needle))
.unwrap();
Position {
line: line as u32,
character: (text.find(needle).unwrap() + 1) as u32,
}
};
let pos = position("Box :");
let graph = server
.graph(
"types.hpp",
pos,
&GraphOptions {
depth: 1,
excluded_namespaces: vec![],
},
)
.unwrap();
for label in [
"demo::Base",
"demo::Helper",
"demo::Box::value",
"demo::Box::helper",
"demo::Box::set",
"demo::Box::run",
"demo::Addable",
"demo::Sized",
"std::copyable",
"std::constructible_from",
"std::integral",
"std::convertible_to",
] {
assert!(
graph.nodes.iter().any(|n| n.label == label),
"Missing {label}: {graph:?}"
);
}
assert!(
graph
.nodes
.iter()
.any(|n| n.kind == "requires" && n.detail.contains("u.size()"))
);
assert!(
graph
.nodes
.iter()
.any(|n| n.kind == "parameter" && n.label == "argument x")
);
assert!(
graph
.nodes
.iter()
.any(|n| n.kind == "template-parameter" && n.label == "template T")
);
let default_graph = server
.graph("types.hpp", pos, &GraphOptions::default())
.unwrap();
assert!(
!default_graph
.nodes
.iter()
.any(|n| n.label.starts_with("std::"))
);
let node = |label: &str| graph.nodes.iter().find(|n| n.label == label).unwrap();
let edge = |from: &str, to: &str, label: &str| {
graph
.edges
.iter()
.any(|e| e.from == from && e.to == to && e.label == label)
};
assert!(edge(&node("demo::Base").id, "selected", "base of"));
assert!(edge(
&node("demo::Helper").id,
&node("demo::Box::helper").id,
"type of"
));
assert!(edge(
&node("template T").id,
&node("demo::Box::value").id,
"type of"
));
assert!(edge(
&node("std::integral").id,
&node("argument n").id,
"constrains"
));
let u = graph
.nodes
.iter()
.find(|n| {
n.label == "template U" && edge(&n.id, &node("demo::Box::set").id, "template parameter")
})
.unwrap();
let argument = graph
.nodes
.iter()
.find(|n| n.label == "argument u" && edge(&n.id, &node("demo::Box::set").id, "argument"))
.unwrap();
assert!(edge(&node("demo::Sized").id, &u.id, "constrains"));
assert!(edge(&u.id, &argument.id, "type of"));
let calls = server
.graph(
"types.hpp",
pos,
&GraphOptions {
depth: 2,
..Default::default()
},
)
.unwrap();
let work = calls
.nodes
.iter()
.find(|n| n.label == "demo::Helper::work")
.unwrap();
let set = calls
.nodes
.iter()
.find(|n| n.label == "demo::Box::set")
.unwrap();
assert!(
calls
.edges
.iter()
.any(|e| e.from == work.id && e.to == set.id && e.label == "called by")
);
assert!(
graph
.nodes
.iter()
.any(|n| n.kind == "operator" && n.label == "||")
);
assert!(
graph
.nodes
.iter()
.any(|n| n.kind == "type" && n.label.starts_with("std::vector")),
"{graph:?}"
);
let method = server
.graph(
"types.hpp",
position("set("),
&GraphOptions {
depth: 1,
excluded_namespaces: vec![],
},
)
.unwrap();
assert!(method.title.ends_with("::set"), "{method:?}");
assert!(
method.nodes.iter().any(|n| n.label == "demo::Sized"),
"{method:?}"
);
let constructor = server
.graph(
"types.hpp",
position("Box(Addable"),
&GraphOptions {
depth: 1,
excluded_namespaces: vec![],
},
)
.unwrap();
assert!(
constructor
.nodes
.iter()
.any(|n| n.label == "std::constructible_from"),
"{constructor:?}"
);
let alias = server
.graph("types.hpp", position("IntBox ="), &GraphOptions::default())
.unwrap();
assert!(
alias.title == "demo::Box"
|| alias
.nodes
.iter()
.any(|n| n.kind == "type" && n.label == "demo::Box"),
"{alias:?}"
);
let enumeration = server
.graph("types.hpp", position("State {"), &GraphOptions::default())
.unwrap();
assert!(
enumeration.nodes.iter().any(|n| n.label == "idle"),
"{enumeration:?}"
);
server.stop();
}