Skip to content

Commit 5b2d0e3

Browse files
committed
Rust: extract crate graph
1 parent 03afc92 commit 5b2d0e3

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

rust/extractor/src/main.rs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ use crate::rust_analyzer::path_to_file_id;
33
use crate::trap::TrapId;
44
use anyhow::Context;
55
use archive::Archiver;
6+
use itertools::Itertools;
67
use log::{info, warn};
8+
use ra_ap_base_db::{CrateId, SourceDatabase};
9+
use ra_ap_cfg::CfgAtom;
710
use ra_ap_hir::Semantics;
811
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
912
use ra_ap_ide_db::RootDatabase;
1013
use ra_ap_project_model::{CargoConfig, ProjectManifest};
11-
use ra_ap_vfs::Vfs;
14+
use ra_ap_vfs::{Vfs, VfsPath};
1215
use rust_analyzer::{ParseResult, RustAnalyzer};
16+
use std::cmp::Ordering;
17+
use std::hash::{Hash, Hasher};
1318
use std::time::Instant;
1419
use std::{
1520
collections::HashMap,
@@ -159,6 +164,83 @@ impl<'a> Extractor<'a> {
159164
trap.commit()?;
160165
Ok(())
161166
}
167+
168+
fn extract_crate_graph(&self, db: &RootDatabase, vfs: &Vfs) {
169+
let crate_graph = db.crate_graph();
170+
171+
// According to the documentation of `CrateGraph`:
172+
// Each crate is defined by the `FileId` of its root module, the set of enabled
173+
// `cfg` flags and the set of dependencies.
174+
let mut crate_id_map = HashMap::<CrateId, (&VfsPath, u64)>::new();
175+
for krate_id in crate_graph.crates_in_topological_order() {
176+
let krate = &crate_graph[krate_id];
177+
let root_module_file = vfs.file_path(krate.root_file_id);
178+
let mut hasher = std::hash::DefaultHasher::new();
179+
krate
180+
.cfg_options
181+
.as_ref()
182+
.into_iter()
183+
.sorted_by(cmp_flag)
184+
.for_each(|x| format!("{x}").hash(&mut hasher));
185+
186+
krate
187+
.dependencies
188+
.iter()
189+
.flat_map(|d| crate_id_map.get(&d.crate_id))
190+
.sorted()
191+
.for_each(|x| x.hash(&mut hasher));
192+
let hash = hasher.finish();
193+
crate_id_map.insert(krate_id, (root_module_file, hash));
194+
}
195+
for krate_id in crate_graph.iter() {
196+
let (root_module_file, hash) = crate_id_map.get(&krate_id).unwrap();
197+
let path: &Path = root_module_file.as_path().unwrap().as_ref();
198+
let path = path.join(format!("{hash:0>16x}"));
199+
let mut trap = self.traps.create("crates", path.as_path());
200+
if trap.path.exists() {
201+
continue;
202+
}
203+
let krate = &crate_graph[krate_id];
204+
let element = generated::Crate {
205+
id: trap::TrapId::Key(format!("crate:{root_module_file}:{hash}")),
206+
name: krate
207+
.display_name
208+
.as_ref()
209+
.map(|x| x.canonical_name().to_string()),
210+
version: krate.version.to_owned(),
211+
cfg_options: krate
212+
.cfg_options
213+
.as_ref()
214+
.into_iter()
215+
.map(|x| format!("{x}"))
216+
.collect(),
217+
dependencies: krate
218+
.dependencies
219+
.iter()
220+
.flat_map(|x| crate_id_map.get(&x.crate_id))
221+
.map(|(module, hash)| trap.label(format!("crate:{module}:{hash}").into()))
222+
.collect(),
223+
};
224+
trap.emit(element);
225+
trap.commit();
226+
}
227+
}
228+
}
229+
230+
fn cmp_flag(a: &&CfgAtom, b: &&CfgAtom) -> Ordering {
231+
match (a, b) {
232+
(CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
233+
(CfgAtom::Flag(a), CfgAtom::KeyValue { key: b, value: _ }) => {
234+
a.as_str().cmp(b.as_str()).then(Ordering::Less)
235+
}
236+
(CfgAtom::KeyValue { key: a, value: _ }, CfgAtom::Flag(b)) => {
237+
a.as_str().cmp(b.as_str()).then(Ordering::Greater)
238+
}
239+
(CfgAtom::KeyValue { key: a, value: av }, CfgAtom::KeyValue { key: b, value: bv }) => a
240+
.as_str()
241+
.cmp(b.as_str())
242+
.then(av.as_str().cmp(bv.as_str())),
243+
}
162244
}
163245

164246
fn main() -> anyhow::Result<()> {
@@ -204,6 +286,7 @@ fn main() -> anyhow::Result<()> {
204286
let cargo_config = cfg.to_cargo_config();
205287
for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) {
206288
if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) {
289+
extractor.extract_crate_graph(db, vfs);
207290
let semantics = Semantics::new(db);
208291
for file in files {
209292
match extractor.load_source(file, &semantics, vfs) {

rust/extractor/src/trap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ macro_rules! trap_key {
7474
$(
7575
key.push_str(&$x.as_key_part());
7676
)*
77-
$crate::TrapId::Key(key)
77+
trap::TrapId::Key(key)
7878
}};
7979
}
8080

@@ -123,7 +123,7 @@ impl<T: TrapClass> From<Label<T>> for trap::Arg {
123123
}
124124

125125
pub struct TrapFile {
126-
path: PathBuf,
126+
pub path: PathBuf,
127127
pub writer: Writer,
128128
compression: Compression,
129129
}

0 commit comments

Comments
 (0)