From deb5c1426d1ca8150a9a7e4eddb53a84f51b58b9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 7 Dec 2021 15:38:12 +0100 Subject: [PATCH] internal: add "Shuffle Crate Graph" command --- .gitignore | 1 + crates/ide/src/lib.rs | 5 ++ crates/ide/src/shuffle_crate_graph.rs | 70 +++++++++++++++++++++++++++ crates/rust-analyzer/src/handlers.rs | 5 ++ crates/rust-analyzer/src/lsp_ext.rs | 8 +++ crates/rust-analyzer/src/main_loop.rs | 1 + editors/code/package.json | 5 ++ editors/code/src/commands.ts | 9 ++++ editors/code/src/lsp_ext.ts | 1 + editors/code/src/main.ts | 1 + 10 files changed, 106 insertions(+) create mode 100644 crates/ide/src/shuffle_crate_graph.rs diff --git a/.gitignore b/.gitignore index f3e3cab1d6e..68c87a6b1ed 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ generated_diagnostic.adoc .DS_Store /out/ /dump.lsif +.envrc diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index e7feb042b22..5bd9f054dd3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -56,6 +56,7 @@ mod typing; mod view_crate_graph; mod view_hir; mod view_item_tree; +mod shuffle_crate_graph; use std::sync::Arc; @@ -177,6 +178,10 @@ impl AnalysisHost { pub fn raw_database_mut(&mut self) -> &mut RootDatabase { &mut self.db } + + pub fn shuffle_crate_graph(&mut self) { + shuffle_crate_graph::shuffle_crate_graph(&mut self.db); + } } impl Default for AnalysisHost { diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs new file mode 100644 index 00000000000..9c3cce5dfe4 --- /dev/null +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -0,0 +1,70 @@ +use std::sync::Arc; + +use ide_db::base_db::salsa::Durability; +use ide_db::base_db::{CrateGraph, SourceDatabase}; +use ide_db::RootDatabase; +use rustc_hash::FxHashMap; + +// 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::>(); + 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.origin.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(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() +} diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index bf153012d94..ab3c9e8227d 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -97,6 +97,11 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result Result<()> { + state.analysis_host.shuffle_crate_graph(); + Ok(()) +} + pub(crate) fn handle_syntax_tree( snap: GlobalStateSnapshot, params: lsp_ext::SyntaxTreeParams, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 19137b942eb..0e23094199f 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -31,6 +31,14 @@ impl Request for MemoryUsage { const METHOD: &'static str = "rust-analyzer/memoryUsage"; } +pub enum ShuffleCrateGraph {} + +impl Request for ShuffleCrateGraph { + type Params = (); + type Result = (); + const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph"; +} + pub enum ReloadWorkspace {} impl Request for ReloadWorkspace { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 2d83cbee669..65f9c873673 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -567,6 +567,7 @@ impl GlobalState { Ok(()) })? .on_sync_mut::(handlers::handle_memory_usage)? + .on_sync_mut::(handlers::handle_shuffle_crate_graph)? .on_sync::(handlers::handle_join_lines)? .on_sync::(handlers::handle_on_enter)? .on_sync::(handlers::handle_selection_range)? diff --git a/editors/code/package.json b/editors/code/package.json index da4fa15b02f..4b6e5ef3332 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -171,6 +171,11 @@ "title": "Memory Usage (Clears Database)", "category": "Rust Analyzer" }, + { + "command": "rust-analyzer.shuffleCrateGraph", + "title": "Shuffle Crate Graph", + "category": "Rust Analyzer" + }, { "command": "rust-analyzer.reloadWorkspace", "title": "Reload workspace", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index c9385361f88..fe006a63e27 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -85,6 +85,15 @@ export function memoryUsage(ctx: Ctx): Cmd { }; } +export function shuffleCrateGraph(ctx: Ctx): Cmd { + return async () => { + const client = ctx.client; + if (!client) return; + + await client.sendRequest(ra.shuffleCrateGraph); + }; +} + export function matchingBrace(ctx: Ctx): Cmd { return async () => { const editor = ctx.activeRustEditor; diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 90796e611e6..a21a742a571 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -9,6 +9,7 @@ export interface AnalyzerStatusParams { } export const analyzerStatus = new lc.RequestType("rust-analyzer/analyzerStatus"); export const memoryUsage = new lc.RequestType0("rust-analyzer/memoryUsage"); +export const shuffleCrateGraph = new lc.RequestType0("rust-analyzer/shuffleCrateGraph"); export interface ServerStatusParams { health: "ok" | "warning" | "error"; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 734f2245036..a06fc09fc8e 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -117,6 +117,7 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { ctx.registerCommand('analyzerStatus', commands.analyzerStatus); ctx.registerCommand('memoryUsage', commands.memoryUsage); + ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph); ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace); ctx.registerCommand('matchingBrace', commands.matchingBrace); ctx.registerCommand('joinLines', commands.joinLines);