mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Auto merge of #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.
This commit is contained in:
commit
a6ddf5fb80
3 changed files with 32 additions and 37 deletions
|
@ -49,8 +49,7 @@
|
|||
//! user explores them belongs to that extension (it's totally valid to change
|
||||
//! rust-project.json over time via configuration request!)
|
||||
|
||||
use base_db::{CrateDisplayName, CrateId, CrateName, Dependency};
|
||||
use la_arena::RawIdx;
|
||||
use base_db::{CrateDisplayName, CrateName};
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{de, Deserialize};
|
||||
|
@ -74,10 +73,10 @@ pub struct ProjectJson {
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Crate {
|
||||
pub(crate) display_name: Option<CrateDisplayName>,
|
||||
pub(crate) root_module: AbsPathBuf,
|
||||
pub root_module: AbsPathBuf,
|
||||
pub(crate) edition: Edition,
|
||||
pub(crate) version: Option<String>,
|
||||
pub(crate) deps: Vec<Dependency>,
|
||||
pub(crate) deps: Vec<Dep>,
|
||||
pub(crate) cfg: Vec<CfgFlag>,
|
||||
pub(crate) target: Option<String>,
|
||||
pub(crate) env: FxHashMap<String, String>,
|
||||
|
@ -128,16 +127,7 @@ impl ProjectJson {
|
|||
root_module,
|
||||
edition: crate_data.edition.into(),
|
||||
version: crate_data.version.as_ref().map(ToString::to_string),
|
||||
deps: crate_data
|
||||
.deps
|
||||
.into_iter()
|
||||
.map(|dep_data| {
|
||||
Dependency::new(
|
||||
dep_data.name,
|
||||
CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
deps: crate_data.deps,
|
||||
cfg: crate_data.cfg,
|
||||
target: crate_data.target,
|
||||
env: crate_data.env,
|
||||
|
@ -161,11 +151,8 @@ impl ProjectJson {
|
|||
}
|
||||
|
||||
/// Returns an iterator over the crates in the project.
|
||||
pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
|
||||
self.crates
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, krate)| (CrateId::from_raw(RawIdx::from(idx as u32)), krate))
|
||||
pub fn crates(&self) -> impl Iterator<Item = (CrateArrayIdx, &Crate)> {
|
||||
self.crates.iter().enumerate().map(|(idx, krate)| (CrateArrayIdx(idx), krate))
|
||||
}
|
||||
|
||||
/// Returns the path to the project's root folder.
|
||||
|
@ -188,7 +175,7 @@ struct CrateData {
|
|||
edition: EditionData,
|
||||
#[serde(default)]
|
||||
version: Option<semver::Version>,
|
||||
deps: Vec<DepData>,
|
||||
deps: Vec<Dep>,
|
||||
#[serde(default)]
|
||||
cfg: Vec<CfgFlag>,
|
||||
target: Option<String>,
|
||||
|
@ -227,13 +214,21 @@ impl From<EditionData> for Edition {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
struct DepData {
|
||||
/// Identifies a crate by position in the crates array.
|
||||
///
|
||||
/// This will differ from `CrateId` when multiple `ProjectJson`
|
||||
/// workspaces are loaded.
|
||||
#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
#[serde(transparent)]
|
||||
pub struct CrateArrayIdx(pub usize);
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) struct Dep {
|
||||
/// Identifies a crate by position in the crates array.
|
||||
#[serde(rename = "crate")]
|
||||
krate: usize,
|
||||
pub(crate) krate: CrateArrayIdx,
|
||||
#[serde(deserialize_with = "deserialize_crate_name")]
|
||||
name: CrateName,
|
||||
pub(crate) name: CrateName,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
build_scripts::BuildScriptOutput,
|
||||
cargo_workspace::{DepKind, PackageData, RustLibSource},
|
||||
cfg_flag::CfgFlag,
|
||||
project_json::Crate,
|
||||
project_json::{Crate, CrateArrayIdx},
|
||||
rustc_cfg::{self, RustcCfgConfig},
|
||||
sysroot::{SysrootCrate, SysrootMode},
|
||||
target_data_layout::{self, RustcDataLayoutConfig},
|
||||
|
@ -878,12 +878,13 @@ fn project_json_to_crate_graph(
|
|||
|
||||
let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
|
||||
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
|
||||
let crates: FxHashMap<CrateId, CrateId> = project
|
||||
|
||||
let idx_to_crate_id: FxHashMap<CrateArrayIdx, CrateId> = project
|
||||
.crates()
|
||||
.filter_map(|(crate_id, krate)| Some((crate_id, krate, load(&krate.root_module)?)))
|
||||
.filter_map(|(idx, krate)| Some((idx, krate, load(&krate.root_module)?)))
|
||||
.map(
|
||||
|(
|
||||
crate_id,
|
||||
idx,
|
||||
Crate {
|
||||
display_name,
|
||||
edition,
|
||||
|
@ -939,13 +940,13 @@ fn project_json_to_crate_graph(
|
|||
proc_macros.insert(crate_graph_crate_id, node);
|
||||
}
|
||||
}
|
||||
(crate_id, crate_graph_crate_id)
|
||||
(idx, crate_graph_crate_id)
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
||||
for (from, krate) in project.crates() {
|
||||
if let Some(&from) = crates.get(&from) {
|
||||
for (from_idx, krate) in project.crates() {
|
||||
if let Some(&from) = idx_to_crate_id.get(&from_idx) {
|
||||
if let Some((public_deps, libproc_macro)) = &sysroot_deps {
|
||||
public_deps.add_to_crate_graph(crate_graph, from);
|
||||
if let Some(proc_macro) = libproc_macro {
|
||||
|
@ -954,8 +955,8 @@ fn project_json_to_crate_graph(
|
|||
}
|
||||
|
||||
for dep in &krate.deps {
|
||||
if let Some(&to) = crates.get(&dep.crate_id) {
|
||||
add_dep(crate_graph, from, dep.name.clone(), to)
|
||||
if let Some(&to) = idx_to_crate_id.get(&dep.krate) {
|
||||
add_dep(crate_graph, from, dep.name.clone(), to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,10 +296,9 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
|
|||
})
|
||||
}
|
||||
project_model::ProjectWorkspace::Json { project, .. } => {
|
||||
if !project
|
||||
.crates()
|
||||
.any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c))
|
||||
{
|
||||
if !project.crates().any(|(_, krate)| {
|
||||
crate_root_paths.contains(&krate.root_module.as_path())
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
None
|
||||
|
|
Loading…
Reference in a new issue