about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/shuffle_crate_graph.rs70
-rw-r--r--crates/rust-analyzer/src/handlers.rs5
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs8
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--docs/dev/lsp-extensions.md10
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/commands.ts9
-rw-r--r--editors/code/src/lsp_ext.ts1
-rw-r--r--editors/code/src/main.ts1
11 files changed, 115 insertions, 1 deletions
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::<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.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<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()
+}
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<Stri
     Ok(out)
 }
 
+pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> 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::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)?
+            .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)?
             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
             .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index b925f146a72..c92395553c0 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: c6568e4035333f3a
+lsp_ext.rs hash: 49ffd619919ed74
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -526,6 +526,14 @@ Renders rust-analyzer's crate graph as an SVG image.
 
 If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
 
+## Shuffle Crate Graph
+
+**Method:** `rust-analyzer/shuffleCrateGraph`
+
+**Request:** `null`
+
+Shuffles the crate IDs in the crate graph, for debugging purposes.
+
 ## Expand Macro
 
 **Method:** `rust-analyzer/expandMacro`
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
@@ -172,6 +172,11 @@
                 "category": "Rust Analyzer"
             },
             {
+                "command": "rust-analyzer.shuffleCrateGraph",
+                "title": "Shuffle Crate Graph",
+                "category": "Rust Analyzer"
+            },
+            {
                 "command": "rust-analyzer.reloadWorkspace",
                 "title": "Reload workspace",
                 "category": "Rust Analyzer"
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<AnalyzerStatusParams, string, void>("rust-analyzer/analyzerStatus");
 export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
+export const shuffleCrateGraph = new lc.RequestType0<null, void>("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);