#[derive(Debug, Default)]
pub(super) struct CompileCommands {
pub include_dirs: Vec<String>,
pub entry_count: usize,
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub(super) fn load_compile_commands(project_root: &std::path::Path) -> CompileCommands {
let candidates = [
project_root.join("compile_commands.json"),
project_root.join("build/compile_commands.json"),
project_root.join("cmake-build-debug/compile_commands.json"),
project_root.join("cmake-build-release/compile_commands.json"),
];
for path in &candidates {
if let Ok(content) = std::fs::read_to_string(path) {
if let Some(cmds) = parse_compile_commands(&content) {
eprintln!(
" compile_commands.json: {} entries, {} include dirs (from {})",
cmds.entry_count,
cmds.include_dirs.len(),
path.display()
);
return cmds;
}
}
}
CompileCommands::default()
}
fn parse_compile_commands(content: &str) -> Option<CompileCommands> {
let entries: Vec<serde_json::Value> = serde_json::from_str(content).ok()?;
let mut include_dirs = std::collections::HashSet::new();
let entry_count = entries.len();
for entry in &entries {
if let Some(command) = entry.get("command").and_then(|c| c.as_str()) {
extract_include_dirs(command, &mut include_dirs);
}
if let Some(args) = entry.get("arguments").and_then(|a| a.as_array()) {
let command = args
.iter()
.filter_map(|a| a.as_str())
.collect::<Vec<_>>()
.join(" ");
extract_include_dirs(&command, &mut include_dirs);
}
}
let mut dirs: Vec<String> = include_dirs.into_iter().collect();
dirs.sort();
Some(CompileCommands {
include_dirs: dirs,
entry_count,
})
}
fn extract_include_dirs(command: &str, dirs: &mut std::collections::HashSet<String>) {
let parts: Vec<&str> = command.split_whitespace().collect();
let mut iter = parts.iter().peekable();
while let Some(&part) = iter.next() {
if part == "-I" || part == "-isystem" {
if let Some(&&next) = iter.peek() {
dirs.insert(next.to_string());
iter.next();
}
continue;
}
for prefix in &["-I", "-isystem"] {
if let Some(path) = part.strip_prefix(prefix) {
if !path.is_empty() {
dirs.insert(path.to_string());
}
}
}
}
}