Skip to content

Commit 9c04788

Browse files
committed
Auto merge of rust-lang#16961 - Wilfred:fix_crate_ids, r=Veykril
Fix crate IDs when multiple workspaces are loaded Previously, we assumed that the crate numbers in a `rust-project.json` always matched the `CrateId` values in the crate graph. This isn't true when there are multiple workspaces, because the crate graphs are merged and the `CrateId` values in the merged graph are different. This broke flycheck (see first commit), because we were unable to find the workspace when a file changed, so we every single flycheck, producing duplicate compilation errors. Instead, use the crate root module path to look up the relevant flycheck. This makes `ProjectWorkspace::Json` consistenet with `ProjectWorkspace::Cargo`. Also, define a separate JSON crate number type, to prevent bugs like this happening again.
2 parents 80131ce + aeb6be6 commit 9c04788

File tree

3 files changed

+32
-37
lines changed

3 files changed

+32
-37
lines changed

src/tools/rust-analyzer/crates/project-model/src/project_json.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@
4949
//! user explores them belongs to that extension (it's totally valid to change
5050
//! rust-project.json over time via configuration request!)
5151
52-
use base_db::{CrateDisplayName, CrateId, CrateName, Dependency};
53-
use la_arena::RawIdx;
52+
use base_db::{CrateDisplayName, CrateName};
5453
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
5554
use rustc_hash::FxHashMap;
5655
use serde::{de, Deserialize};
@@ -74,10 +73,10 @@ pub struct ProjectJson {
7473
#[derive(Clone, Debug, Eq, PartialEq)]
7574
pub struct Crate {
7675
pub(crate) display_name: Option<CrateDisplayName>,
77-
pub(crate) root_module: AbsPathBuf,
76+
pub root_module: AbsPathBuf,
7877
pub(crate) edition: Edition,
7978
pub(crate) version: Option<String>,
80-
pub(crate) deps: Vec<Dependency>,
79+
pub(crate) deps: Vec<Dep>,
8180
pub(crate) cfg: Vec<CfgFlag>,
8281
pub(crate) target: Option<String>,
8382
pub(crate) env: FxHashMap<String, String>,
@@ -128,16 +127,7 @@ impl ProjectJson {
128127
root_module,
129128
edition: crate_data.edition.into(),
130129
version: crate_data.version.as_ref().map(ToString::to_string),
131-
deps: crate_data
132-
.deps
133-
.into_iter()
134-
.map(|dep_data| {
135-
Dependency::new(
136-
dep_data.name,
137-
CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
138-
)
139-
})
140-
.collect::<Vec<_>>(),
130+
deps: crate_data.deps,
141131
cfg: crate_data.cfg,
142132
target: crate_data.target,
143133
env: crate_data.env,
@@ -161,11 +151,8 @@ impl ProjectJson {
161151
}
162152

163153
/// Returns an iterator over the crates in the project.
164-
pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
165-
self.crates
166-
.iter()
167-
.enumerate()
168-
.map(|(idx, krate)| (CrateId::from_raw(RawIdx::from(idx as u32)), krate))
154+
pub fn crates(&self) -> impl Iterator<Item = (CrateArrayIdx, &Crate)> {
155+
self.crates.iter().enumerate().map(|(idx, krate)| (CrateArrayIdx(idx), krate))
169156
}
170157

171158
/// Returns the path to the project's root folder.
@@ -188,7 +175,7 @@ struct CrateData {
188175
edition: EditionData,
189176
#[serde(default)]
190177
version: Option<semver::Version>,
191-
deps: Vec<DepData>,
178+
deps: Vec<Dep>,
192179
#[serde(default)]
193180
cfg: Vec<CfgFlag>,
194181
target: Option<String>,
@@ -227,13 +214,21 @@ impl From<EditionData> for Edition {
227214
}
228215
}
229216

230-
#[derive(Deserialize, Debug, Clone)]
231-
struct DepData {
217+
/// Identifies a crate by position in the crates array.
218+
///
219+
/// This will differ from `CrateId` when multiple `ProjectJson`
220+
/// workspaces are loaded.
221+
#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
222+
#[serde(transparent)]
223+
pub struct CrateArrayIdx(pub usize);
224+
225+
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
226+
pub(crate) struct Dep {
232227
/// Identifies a crate by position in the crates array.
233228
#[serde(rename = "crate")]
234-
krate: usize,
229+
pub(crate) krate: CrateArrayIdx,
235230
#[serde(deserialize_with = "deserialize_crate_name")]
236-
name: CrateName,
231+
pub(crate) name: CrateName,
237232
}
238233

239234
#[derive(Deserialize, Debug, Clone)]

src/tools/rust-analyzer/crates/project-model/src/workspace.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
build_scripts::BuildScriptOutput,
2323
cargo_workspace::{DepKind, PackageData, RustLibSource},
2424
cfg_flag::CfgFlag,
25-
project_json::Crate,
25+
project_json::{Crate, CrateArrayIdx},
2626
rustc_cfg::{self, RustcCfgConfig},
2727
sysroot::{SysrootCrate, SysrootMode},
2828
target_data_layout::{self, RustcDataLayoutConfig},
@@ -878,12 +878,13 @@ fn project_json_to_crate_graph(
878878

879879
let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
880880
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
881-
let crates: FxHashMap<CrateId, CrateId> = project
881+
882+
let idx_to_crate_id: FxHashMap<CrateArrayIdx, CrateId> = project
882883
.crates()
883-
.filter_map(|(crate_id, krate)| Some((crate_id, krate, load(&krate.root_module)?)))
884+
.filter_map(|(idx, krate)| Some((idx, krate, load(&krate.root_module)?)))
884885
.map(
885886
|(
886-
crate_id,
887+
idx,
887888
Crate {
888889
display_name,
889890
edition,
@@ -939,13 +940,13 @@ fn project_json_to_crate_graph(
939940
proc_macros.insert(crate_graph_crate_id, node);
940941
}
941942
}
942-
(crate_id, crate_graph_crate_id)
943+
(idx, crate_graph_crate_id)
943944
},
944945
)
945946
.collect();
946947

947-
for (from, krate) in project.crates() {
948-
if let Some(&from) = crates.get(&from) {
948+
for (from_idx, krate) in project.crates() {
949+
if let Some(&from) = idx_to_crate_id.get(&from_idx) {
949950
if let Some((public_deps, libproc_macro)) = &sysroot_deps {
950951
public_deps.add_to_crate_graph(crate_graph, from);
951952
if let Some(proc_macro) = libproc_macro {
@@ -954,8 +955,8 @@ fn project_json_to_crate_graph(
954955
}
955956

956957
for dep in &krate.deps {
957-
if let Some(&to) = crates.get(&dep.crate_id) {
958-
add_dep(crate_graph, from, dep.name.clone(), to)
958+
if let Some(&to) = idx_to_crate_id.get(&dep.krate) {
959+
add_dep(crate_graph, from, dep.name.clone(), to);
959960
}
960961
}
961962
}

src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,9 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
296296
})
297297
}
298298
project_model::ProjectWorkspace::Json { project, .. } => {
299-
if !project
300-
.crates()
301-
.any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c))
302-
{
299+
if !project.crates().any(|(_, krate)| {
300+
crate_root_paths.contains(&krate.root_module.as_path())
301+
}) {
303302
return None;
304303
}
305304
None

0 commit comments

Comments
 (0)