Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/workspace.rs')
| -rw-r--r-- | crates/project-model/src/workspace.rs | 177 |
1 files changed, 86 insertions, 91 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 98c5a02dcd..9f6e75171b 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -4,7 +4,7 @@ use std::{collections::VecDeque, fmt, fs, iter, sync}; -use anyhow::{format_err, Context}; +use anyhow::Context; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, @@ -14,7 +14,6 @@ use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use span::Edition; -use stdx::always; use toolchain::Tool; use triomphe::Arc; @@ -101,7 +100,7 @@ pub enum ProjectWorkspace { /// Backed by basic sysroot crates for basic completion and highlighting. DetachedFile { /// The file in question. - file: AbsPathBuf, + file: ManifestPath, /// The sysroot loaded for this workspace. sysroot: Result<Sysroot, Option<String>>, /// Holds cfg flags for the current target. We get those by running @@ -116,7 +115,7 @@ pub enum ProjectWorkspace { /// A set of cfg overrides for the files. cfg_overrides: CfgOverrides, /// Is this file a cargo script file? - cargo_script: Option<CargoWorkspace>, + cargo_script: Option<(CargoWorkspace, WorkspaceBuildScripts)>, }, } @@ -230,7 +229,7 @@ impl ProjectWorkspace { ) -> anyhow::Result<ProjectWorkspace> { let res = match manifest { ProjectManifest::ProjectJson(project_json) => { - let file = fs::read_to_string(project_json) + let file = fs::read_to_string(project_json.as_ref()) .with_context(|| format!("Failed to read json file {project_json}"))?; let data = serde_json::from_str(&file) .with_context(|| format!("Failed to deserialize json file {project_json}"))?; @@ -243,6 +242,9 @@ impl ProjectWorkspace { &config.cfg_overrides, ) } + ProjectManifest::CargoScript(rust_file) => { + ProjectWorkspace::load_detached_file(rust_file, config)? + } ProjectManifest::CargoToml(cargo_toml) => { let sysroot = match (&config.sysroot, &config.sysroot_src) { (Some(RustLibSource::Path(path)), None) => { @@ -299,7 +301,7 @@ impl ProjectWorkspace { progress, ) { Ok(meta) => { - let workspace = CargoWorkspace::new(meta); + let workspace = CargoWorkspace::new(meta, cargo_toml.clone()); let buildscripts = WorkspaceBuildScripts::rustc_crates( &workspace, cargo_toml.parent(), @@ -355,7 +357,7 @@ impl ProjectWorkspace { "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}", ) })?; - let cargo = CargoWorkspace::new(meta); + let cargo = CargoWorkspace::new(meta, cargo_toml.clone()); let cargo_config_extra_env = cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref); @@ -433,82 +435,71 @@ impl ProjectWorkspace { } } - pub fn load_detached_files( - detached_files: Vec<AbsPathBuf>, + pub fn load_detached_file( + detached_file: &ManifestPath, config: &CargoConfig, - ) -> Vec<anyhow::Result<ProjectWorkspace>> { - detached_files - .into_iter() - .map(|detached_file| { - let dir = detached_file - .parent() - .ok_or_else(|| format_err!("detached file has no parent"))?; - let sysroot = match &config.sysroot { - Some(RustLibSource::Path(path)) => { - Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) - .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) - } - Some(RustLibSource::Discover) => { - Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata) - .map_err(|e| { - Some(format!( - "Failed to find sysroot for {dir}. Is rust-src installed? {e}" - )) - }) - } - None => Err(None), - }; + ) -> anyhow::Result<ProjectWorkspace> { + let dir = detached_file.parent(); + let sysroot = match &config.sysroot { + Some(RustLibSource::Path(path)) => { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) + .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) + } + Some(RustLibSource::Discover) => Sysroot::discover( + dir, + &config.extra_env, + config.sysroot_query_metadata, + ) + .map_err(|e| { + Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}")) + }), + None => Err(None), + }; - let sysroot_ref = sysroot.as_ref().ok(); - let toolchain = match get_toolchain_version( - dir, - sysroot_ref, - Tool::Rustc, - &config.extra_env, - "rustc ", - ) { - Ok(it) => it, - Err(e) => { - tracing::error!("{e}"); - None - } - }; + let sysroot_ref = sysroot.as_ref().ok(); + let toolchain = + match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ") + { + Ok(it) => it, + Err(e) => { + tracing::error!("{e}"); + None + } + }; - let rustc_cfg = - rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); - let data_layout = target_data_layout::get( - RustcDataLayoutConfig::Rustc(sysroot_ref), - None, - &config.extra_env, - ); + let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); + let data_layout = target_data_layout::get( + RustcDataLayoutConfig::Rustc(sysroot_ref), + None, + &config.extra_env, + ); - let cargo_script = ManifestPath::try_from(detached_file.clone()) - .ok() - .and_then(|file| { - CargoWorkspace::fetch_metadata( - &file, - file.parent(), - config, - sysroot_ref, - &|_| (), - ) - .ok() - }) - .map(CargoWorkspace::new); + let cargo_script = + CargoWorkspace::fetch_metadata(detached_file, dir, config, sysroot_ref, &|_| ()) + .ok() + .map(|ws| { + ( + CargoWorkspace::new(ws, detached_file.clone()), + WorkspaceBuildScripts::default(), + ) + }); - Ok(ProjectWorkspace::DetachedFile { - file: detached_file, - sysroot, - rustc_cfg, - toolchain, - target_layout: data_layout - .map(Arc::from) - .map_err(|it| Arc::from(it.to_string())), - cfg_overrides: config.cfg_overrides.clone(), - cargo_script, - }) - }) - .collect() + Ok(ProjectWorkspace::DetachedFile { + file: detached_file.to_owned(), + sysroot, + rustc_cfg, + toolchain, + target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + cfg_overrides: config.cfg_overrides.clone(), + cargo_script, + }) + } + + pub fn load_detached_files( + detached_files: Vec<ManifestPath>, + config: &CargoConfig, + ) -> Vec<anyhow::Result<ProjectWorkspace>> { + detached_files.into_iter().map(|file| Self::load_detached_file(&file, config)).collect() } /// Runs the build scripts for this [`ProjectWorkspace`]. @@ -519,7 +510,7 @@ impl ProjectWorkspace { ) -> anyhow::Result<WorkspaceBuildScripts> { match self { ProjectWorkspace::DetachedFile { - cargo_script: Some(cargo), + cargo_script: Some((cargo, _)), toolchain, sysroot, .. @@ -586,10 +577,11 @@ impl ProjectWorkspace { pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) { match self { - ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs, - _ => { - always!(bs == WorkspaceBuildScripts::default()); + ProjectWorkspace::Cargo { build_scripts, .. } + | ProjectWorkspace::DetachedFile { cargo_script: Some((_, build_scripts)), .. } => { + *build_scripts = bs } + _ => assert_eq!(bs, WorkspaceBuildScripts::default()), } } @@ -742,15 +734,18 @@ impl ProjectWorkspace { ProjectWorkspace::DetachedFile { file, cargo_script, sysroot, .. } => { iter::once(PackageRoot { is_local: true, - include: vec![file.clone()], + include: vec![file.as_ref().to_owned()], exclude: Vec::new(), }) - .chain(cargo_script.iter().flat_map(|cargo| { + .chain(cargo_script.iter().flat_map(|(cargo, build_scripts)| { cargo.packages().map(|pkg| { let is_local = cargo[pkg].is_local; let pkg_root = cargo[pkg].manifest.parent().to_path_buf(); let mut include = vec![pkg_root.clone()]; + let out_dir = + build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone()); + include.extend(out_dir); // In case target's path is manually set in Cargo.toml to be // outside the package root, add its parent as an extra include. @@ -801,7 +796,7 @@ impl ProjectWorkspace { ProjectWorkspace::DetachedFile { sysroot, cargo_script, .. } => { let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); sysroot_package_len - + cargo_script.as_ref().map_or(1, |cargo| cargo.packages().len()) + + cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len()) } } } @@ -863,7 +858,7 @@ impl ProjectWorkspace { cfg_overrides, cargo_script, } => ( - if let Some(cargo) = cargo_script { + if let Some((cargo, build_scripts)) = cargo_script { cargo_to_crate_graph( &mut |path| load(path), None, @@ -871,7 +866,7 @@ impl ProjectWorkspace { sysroot.as_ref().ok(), rustc_cfg.clone(), cfg_overrides, - &WorkspaceBuildScripts::default(), + build_scripts, ) } else { detached_file_to_crate_graph( @@ -959,7 +954,7 @@ impl ProjectWorkspace { file, sysroot, rustc_cfg, - cargo_script, + cargo_script: Some((cargo_script, _)), toolchain, target_layout, cfg_overrides, @@ -968,7 +963,7 @@ impl ProjectWorkspace { file: o_file, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg, - cargo_script: o_cargo_script, + cargo_script: Some((o_cargo_script, _)), toolchain: o_toolchain, target_layout: o_target_layout, cfg_overrides: o_cfg_overrides, @@ -1294,11 +1289,11 @@ fn cargo_to_crate_graph( fn detached_file_to_crate_graph( rustc_cfg: Vec<CfgFlag>, load: FileLoader<'_>, - detached_file: &AbsPathBuf, + detached_file: &ManifestPath, sysroot: Option<&Sysroot>, override_cfg: &CfgOverrides, ) -> (CrateGraph, ProcMacroPaths) { - let _p = tracing::span!(tracing::Level::INFO, "detached_files_to_crate_graph").entered(); + let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered(); let mut crate_graph = CrateGraph::default(); let (public_deps, _libproc_macro) = match sysroot { Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load), |