clangd_parser/
lib.rs

1//! clangd-parser
2//! Parse the clangd output to leverage in other tools, such as test generation.
3
4pub mod clangd;
5pub mod symbols;
6pub mod rela;
7pub mod refs;
8pub mod srcs;
9pub mod cmdl;
10
11use async_std::task;
12
13use std::fs;
14use std::path::PathBuf;
15use std::collections::BTreeMap;
16use crate::symbols::SymbolKind;
17
18/// Given a root directory containing .cache/index, parse the IDX files
19pub fn run(p: &PathBuf) -> clangd::ClangdDatabase {
20    let mut db = task::block_on(_run(p));
21    #[cfg(feature="post-process")]
22    post_process(&mut db);
23    db
24}
25
26#[cfg(feature="post-process")]
27fn post_process(db: &mut clangd::ClangdDatabase) {
28    // for each name
29    for entry in db.name.iter() {
30        let sym = entry.1;
31
32        match sym.syminfo.kind {
33            // For variables, check if declared in an H file.
34            // If so, map id in corresponding file entry
35            SymbolKind::Variable => {
36                let decl_file = sym.canonical_declaration.file_uri.rsplit_once("/");
37                if decl_file.is_none() {
38                    debug_assert!(false);
39                }
40                let decl_file = decl_file.unwrap().1;
41                if decl_file.ends_with(".h") {
42                    let hfile = db.file.get_mut(&decl_file.to_string());
43                    if hfile.is_none() {
44                        debug_assert!(false);
45                    }
46                    let hfile = hfile.unwrap();
47                    hfile.variable_declarations.push(sym.id.clone());
48                }
49            },
50            _ => ()
51        }
52    }
53}
54
55async fn _run(p: &PathBuf) -> clangd::ClangdDatabase {
56    let mut to_file: clangd::ClangdFileMap = BTreeMap::new();
57    let mut to_id: clangd::ClangdIdMap = BTreeMap::new();
58    let mut to_name: clangd::ClangdNameMap = BTreeMap::new();
59    let mut path = p.join(".cache");
60    if !path.exists() {
61        panic!("Unable to find .cache!");
62    }
63    path = path.join("clangd").join("index");
64    if !path.exists() {
65        panic!("Has clangd been run?");
66    }
67
68    let rd = fs::read_dir(path.as_path()).unwrap();
69    for entry in rd {
70        let e = entry.unwrap();
71        if e.file_type().unwrap().is_file() {
72            let _ret = clangd::ClangdFile::parse(e.path()).await;
73            if _ret.is_ok() {
74                let fname = e.file_name().to_str().unwrap().to_string();
75                let parts: Vec<&str> = fname.split(".").collect();
76                let fname = format!("{}.{}", parts[0], parts[1]);
77                let db = _ret.unwrap();
78                if !to_file.contains_key(&fname) {
79                    let _ = to_file.insert(fname, db.clone());
80                }
81                for sym in db.symbols.data.iter() {
82                    if !to_id.contains_key(&sym.id) {
83                        let _ = to_id.insert(sym.id.clone(), sym.clone());
84                    }
85                    if !to_name.contains_key(&sym.name) {
86                        let _ = to_name.insert(sym.name.clone(), sym.clone());
87                    }
88                }
89            }
90        }
91    }
92
93    clangd::ClangdDatabase{ file: to_file, id: to_id, name: to_name }
94}