summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs
blob: ae539a5d397f788a6a0a3f1bbbaeb7f94a78f039 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use std::sync::Arc;

use ide_db::{
    base_db::{salsa::Durability, CrateGraph, SourceDatabase},
    FxHashMap, RootDatabase,
};

// Feature: Shuffle Crate Graph
//
// Randomizes all crate IDs in the crate graph, for debugging.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **rust-analyzer: Shuffle Crate Graph**
// |===
pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
    let crate_graph = db.crate_graph();

    let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>();
    shuffle(&mut shuffled_ids);

    let mut new_graph = CrateGraph::default();

    let mut map = FxHashMap::default();
    for old_id in shuffled_ids.iter().copied() {
        let data = &crate_graph[old_id];
        let new_id = new_graph.add_crate_root(
            data.root_file_id,
            data.edition,
            data.display_name.clone(),
            data.version.clone(),
            data.cfg_options.clone(),
            data.potential_cfg_options.clone(),
            data.env.clone(),
            data.proc_macro.clone(),
            data.is_proc_macro,
            data.origin.clone(),
            data.target_layout.clone(),
        );
        map.insert(old_id, new_id);
    }

    for old_id in shuffled_ids.iter().copied() {
        let data = &crate_graph[old_id];
        for dep in &data.dependencies {
            let mut new_dep = dep.clone();
            new_dep.crate_id = map[&dep.crate_id];
            new_graph.add_dep(map[&old_id], new_dep).unwrap();
        }
    }

    db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH);
}

fn shuffle<T>(slice: &mut [T]) {
    let mut rng = oorandom::Rand32::new(seed());

    let mut remaining = slice.len() - 1;
    while remaining > 0 {
        let index = rng.rand_range(0..remaining as u32);
        slice.swap(remaining, index as usize);
        remaining -= 1;
    }
}

fn seed() -> u64 {
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hasher};

    RandomState::new().build_hasher().finish()
}