Unnamed repository; edit this file 'description' to name the repository.
21 files changed, 201 insertions, 178 deletions
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 2b64a07a5a..82aff6e3b8 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -51,6 +51,7 @@ pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc<str>; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>; + /// Crates whose root's source root is the same as the source root of `file_id` fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>; } @@ -104,6 +105,7 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; + /// Crates whose root fool is in `id`. fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 434e4b5a0c..007709a836 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -121,7 +121,7 @@ impl SourceToDefCtx<'_, '_> { let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def").entered(); let mut mods = SmallVec::new(); for &crate_id in self.db.relevant_crates(file).iter() { - // FIXME: inner items + // Note: `mod` declarations in block modules cannot be supported here let crate_def_map = self.db.crate_def_map(crate_id); mods.extend( crate_def_map @@ -129,6 +129,9 @@ impl SourceToDefCtx<'_, '_> { .map(|local_id| crate_def_map.module_id(local_id)), ) } + if mods.is_empty() { + // FIXME: detached file + } mods } diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs index 024e8f6ae3..0db87c6bc4 100644 --- a/crates/ide-db/src/prime_caches.rs +++ b/crates/ide-db/src/prime_caches.rs @@ -1,6 +1,6 @@ //! rust-analyzer is lazy and doesn't compute anything unless asked. This //! sometimes is counter productive when, for example, the first goto definition -//! request takes longer to compute. This modules implemented prepopulation of +//! request takes longer to compute. This module implements prepopulation of //! various caches, it's not really advanced at the moment. mod topologic_sort; diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index fbd423c9ea..3fdd59967b 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -24,7 +24,7 @@ use toolchain::Tool; use crate::{ cfg::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation, - InvocationStrategy, Package, Sysroot, TargetKind, + InvocationStrategy, ManifestPath, Package, Sysroot, TargetKind, }; /// Output of the build script and proc-macro building steps for a workspace. @@ -63,7 +63,7 @@ impl WorkspaceBuildScripts { fn build_command( config: &CargoConfig, allowed_features: &FxHashSet<String>, - workspace_root: &AbsPathBuf, + manifest_path: &ManifestPath, sysroot: Option<&Sysroot>, ) -> io::Result<Command> { let mut cmd = match config.run_build_script_command.as_deref() { @@ -79,7 +79,7 @@ impl WorkspaceBuildScripts { cmd.args(&config.extra_args); cmd.arg("--manifest-path"); - cmd.arg(workspace_root.join("Cargo.toml")); + cmd.arg(manifest_path.as_ref()); if let Some(target_dir) = &config.target_dir { cmd.arg("--target-dir").arg(target_dir); @@ -116,6 +116,10 @@ impl WorkspaceBuildScripts { } } + if manifest_path.extension().map_or(false, |ext| ext == "rs") { + cmd.arg("-Zscript"); + } + cmd } }; @@ -152,37 +156,12 @@ impl WorkspaceBuildScripts { .as_ref(); let allowed_features = workspace.workspace_features(); - - match Self::run_per_ws( - Self::build_command( - config, - &allowed_features, - &workspace.workspace_root().to_path_buf(), - sysroot, - )?, - workspace, - current_dir, - progress, - ) { - Ok(WorkspaceBuildScripts { error: Some(error), .. }) - if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) => - { - // building build scripts failed, attempt to build with --keep-going so - // that we potentially get more build data - let mut cmd = Self::build_command( - config, - &allowed_features, - &workspace.workspace_root().to_path_buf(), - sysroot, - )?; - - cmd.args(["--keep-going"]); - let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; - res.error = Some(error); - Ok(res) - } - res => res, + let mut cmd = + Self::build_command(config, &allowed_features, workspace.manifest_path(), sysroot)?; + if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) { + cmd.args(["--keep-going"]); } + Self::run_per_ws(cmd, workspace, current_dir, progress) } /// Runs the build scripts by invoking the configured command *once*. @@ -204,7 +183,13 @@ impl WorkspaceBuildScripts { )) } }; - let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?; + let cmd = Self::build_command( + config, + &Default::default(), + // This is not gonna be used anyways, so just construct a dummy here + &ManifestPath::try_from(workspace_root.clone()).unwrap(), + None, + )?; // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are // exactly those from `config`. diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index ff7cf144aa..88ba5a0da9 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -32,6 +32,7 @@ pub struct CargoWorkspace { targets: Arena<TargetData>, workspace_root: AbsPathBuf, target_directory: AbsPathBuf, + manifest_path: ManifestPath, } impl ops::Index<Package> for CargoWorkspace { @@ -334,7 +335,7 @@ impl CargoWorkspace { .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) } - pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace { + pub fn new(mut meta: cargo_metadata::Metadata, manifest_path: ManifestPath) -> CargoWorkspace { let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); let mut targets = Arena::default(); @@ -448,7 +449,7 @@ impl CargoWorkspace { let target_directory = AbsPathBuf::assert(meta.target_directory); - CargoWorkspace { packages, targets, workspace_root, target_directory } + CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path } } pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ { @@ -466,6 +467,10 @@ impl CargoWorkspace { &self.workspace_root } + pub fn manifest_path(&self) -> &ManifestPath { + &self.manifest_path + } + pub fn target_directory(&self) -> &AbsPath { &self.target_directory } diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index 7f3e35ca5d..5428f061b7 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -54,11 +54,13 @@ pub use crate::{ sysroot::Sysroot, workspace::{FileLoader, PackageRoot, ProjectWorkspace}, }; +pub use cargo_metadata::Metadata; #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectManifest { ProjectJson(ManifestPath), CargoToml(ManifestPath), + CargoScript(ManifestPath), } impl ProjectManifest { @@ -71,7 +73,10 @@ impl ProjectManifest { if path.file_name().unwrap_or_default() == "Cargo.toml" { return Ok(ProjectManifest::CargoToml(path)); } - bail!("project root must point to Cargo.toml or rust-project.json: {path}"); + if path.extension().unwrap_or_default() == "rs" { + return Ok(ProjectManifest::CargoScript(path)); + } + bail!("project root must point to a Cargo.toml, rust-project.json or <script>.rs file: {path}"); } pub fn discover_single(path: &AbsPath) -> anyhow::Result<ProjectManifest> { @@ -146,15 +151,19 @@ impl ProjectManifest { res.sort(); res } + + pub fn manifest_path(&self) -> &ManifestPath { + match self { + ProjectManifest::ProjectJson(it) + | ProjectManifest::CargoToml(it) + | ProjectManifest::CargoScript(it) => it, + } + } } impl fmt::Display for ProjectManifest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ProjectManifest::ProjectJson(it) | ProjectManifest::CargoToml(it) => { - fmt::Display::fmt(&it, f) - } - } + fmt::Display::fmt(self.manifest_path(), f) } } diff --git a/crates/project-model/src/manifest_path.rs b/crates/project-model/src/manifest_path.rs index d86e81e7e1..6929a75895 100644 --- a/crates/project-model/src/manifest_path.rs +++ b/crates/project-model/src/manifest_path.rs @@ -1,5 +1,5 @@ //! See [`ManifestPath`]. -use std::{fmt, ops, path::Path}; +use std::{borrow::Borrow, fmt, ops}; use paths::{AbsPath, AbsPathBuf}; @@ -54,8 +54,14 @@ impl ops::Deref for ManifestPath { } } -impl AsRef<Path> for ManifestPath { - fn as_ref(&self) -> &Path { +impl AsRef<AbsPath> for ManifestPath { + fn as_ref(&self) -> &AbsPath { self.file.as_ref() } } + +impl Borrow<AbsPath> for ManifestPath { + fn borrow(&self) -> &AbsPath { + self.file.borrow() + } +} diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 1142d6243d..00dd18b5b1 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -349,7 +349,7 @@ impl Sysroot { .filter(|&package| RELEVANT_SYSROOT_CRATES.contains(&&*package.name)) .map(|package| package.id.clone()) .collect(); - let cargo_workspace = CargoWorkspace::new(res); + let cargo_workspace = CargoWorkspace::new(res, sysroot_cargo_toml); Some(Sysroot { root: sysroot_dir.clone(), src_root: Some(Ok(sysroot_src_dir.clone())), @@ -368,7 +368,7 @@ impl Sysroot { .into_iter() .map(|it| sysroot_src_dir.join(it)) .filter_map(|it| ManifestPath::try_from(it).ok()) - .find(|it| fs::metadata(it).is_ok()); + .find(|it| fs::metadata(it.as_ref()).is_ok()); if let Some(root) = root { stitched.crates.alloc(SysrootCrateData { @@ -468,7 +468,7 @@ fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> { let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml"); let rustc_src = ManifestPath::try_from(rustc_src).ok()?; tracing::debug!("checking for rustc source code: {rustc_src}"); - if fs::metadata(&rustc_src).is_ok() { + if fs::metadata(rustc_src.as_ref()).is_ok() { Some(rustc_src) } else { None diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index fd09dff503..41351d5dc0 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -1,6 +1,7 @@ use std::ops::Deref; use base_db::{CrateGraph, FileId, ProcMacroPaths}; +use cargo_metadata::Metadata; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect_file, ExpectFile}; use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; @@ -9,8 +10,8 @@ use serde::de::DeserializeOwned; use triomphe::Arc; use crate::{ - CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, - WorkspaceBuildScripts, + CargoWorkspace, CfgOverrides, ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, + Sysroot, WorkspaceBuildScripts, }; fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { @@ -21,8 +22,10 @@ fn load_cargo_with_overrides( file: &str, cfg_overrides: CfgOverrides, ) -> (CrateGraph, ProcMacroPaths) { - let meta = get_test_json_file(file); - let cargo_workspace = CargoWorkspace::new(meta); + let meta: Metadata = get_test_json_file(file); + let manifest_path = + ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); + let cargo_workspace = CargoWorkspace::new(meta, manifest_path); let project_workspace = ProjectWorkspace::Cargo { cargo: cargo_workspace, build_scripts: WorkspaceBuildScripts::default(), @@ -41,8 +44,10 @@ fn load_cargo_with_fake_sysroot( file_map: &mut FxHashMap<AbsPathBuf, FileId>, file: &str, ) -> (CrateGraph, ProcMacroPaths) { - let meta = get_test_json_file(file); - let cargo_workspace = CargoWorkspace::new(meta); + let meta: Metadata = get_test_json_file(file); + let manifest_path = + ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); + let cargo_workspace = CargoWorkspace::new(meta, manifest_path); let project_workspace = ProjectWorkspace::Cargo { cargo: cargo_workspace, build_scripts: WorkspaceBuildScripts::default(), @@ -268,9 +273,10 @@ fn smoke_test_real_sysroot_cargo() { return; } let file_map = &mut FxHashMap::<AbsPathBuf, FileId>::default(); - let meta = get_test_json_file("hello-world-metadata.json"); - - let cargo_workspace = CargoWorkspace::new(meta); + let meta: Metadata = get_test_json_file("hello-world-metadata.json"); + let manifest_path = + ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); + let cargo_workspace = CargoWorkspace::new(meta, manifest_path); let sysroot = Ok(Sysroot::discover( AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), &Default::default(), 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), diff --git a/crates/rust-analyzer/src/cli/progress_report.rs b/crates/rust-analyzer/src/cli/progress_report.rs index 6964977840..8b143daf2a 100644 --- a/crates/rust-analyzer/src/cli/progress_report.rs +++ b/crates/rust-analyzer/src/cli/progress_report.rs @@ -96,7 +96,7 @@ impl<'a> ProgressReport<'a> { } fn set_value(&mut self, value: f32) { - self.curr = f32::max(0.0, f32::min(1.0, value)); + self.curr = value.clamp(0.0, 1.0); } fn clear(&mut self) { diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs index 2f9394d0ee..cd15d86aa6 100644 --- a/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -10,7 +10,9 @@ use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; use itertools::Either; use profile::StopWatch; use project_model::target_data_layout::RustcDataLayoutConfig; -use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot}; +use project_model::{ + target_data_layout, CargoConfig, ManifestPath, ProjectWorkspace, RustLibSource, Sysroot, +}; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use rustc_hash::FxHashMap; @@ -76,7 +78,7 @@ impl Tester { ); let workspace = ProjectWorkspace::DetachedFile { - file: tmp_file, + file: ManifestPath::try_from(tmp_file).unwrap(), sysroot, rustc_cfg: vec![], toolchain: None, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index e956791d9d..5842c1d2ec 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -356,7 +356,8 @@ config_data! { /// of projects. /// /// Elements must be paths pointing to `Cargo.toml`, - /// `rust-project.json`, or JSON objects in `rust-project.json` format. + /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON + /// objects in `rust-project.json` format. linkedProjects: Vec<ManifestOrProjectJson> = vec![], /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. @@ -1301,12 +1302,9 @@ impl Config { self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect(); self.discovered_projects .iter() - .filter( - |(ProjectManifest::ProjectJson(path) - | ProjectManifest::CargoToml(path))| { - !exclude_dirs.iter().any(|p| path.starts_with(p)) - }, - ) + .filter(|project| { + !exclude_dirs.iter().any(|p| project.manifest_path().starts_with(p)) + }) .cloned() .map(LinkedProject::from) .collect() diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index e9bca19af6..eaf3f511c4 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -18,7 +18,9 @@ use parking_lot::{ RwLockWriteGuard, }; use proc_macro_api::ProcMacroServer; -use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; +use project_model::{ + CargoWorkspace, ManifestPath, ProjectWorkspace, Target, WorkspaceBuildScripts, +}; use rustc_hash::{FxHashMap, FxHashSet}; use triomphe::Arc; use vfs::{AnchoredPathBuf, ChangedFile, Vfs}; @@ -125,7 +127,7 @@ pub(crate) struct GlobalState { /// to invalidate any salsa caches. pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, pub(crate) crate_graph_file_dependencies: FxHashSet<vfs::VfsPath>, - pub(crate) detached_files: FxHashSet<vfs::AbsPathBuf>, + pub(crate) detached_files: FxHashSet<ManifestPath>, // op queues pub(crate) fetch_workspaces_queue: diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index cf97d7d9d2..39cdef08f8 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1759,11 +1759,12 @@ pub(crate) fn handle_open_docs( let position = from_proto::file_position(&snap, params)?; let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws { - ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())), - ProjectWorkspace::Json { .. } => None, - ProjectWorkspace::DetachedFile { cargo_script, sysroot, .. } => { - cargo_script.as_ref().zip(Some(sysroot.as_ref().ok())) + ProjectWorkspace::Cargo { cargo, sysroot, .. } + | ProjectWorkspace::DetachedFile { cargo_script: Some((cargo, _)), sysroot, .. } => { + Some((cargo, sysroot.as_ref().ok())) } + ProjectWorkspace::Json { .. } => None, + ProjectWorkspace::DetachedFile { .. } => None, }); let (cargo, sysroot) = match ws_and_sysroot { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 5d8a66cabc..4cc174731c 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -25,7 +25,7 @@ use ide_db::{ use itertools::Itertools; use load_cargo::{load_proc_macro, ProjectFolders}; use proc_macro_api::ProcMacroServer; -use project_model::{ProjectWorkspace, WorkspaceBuildScripts}; +use project_model::{ManifestPath, ProjectWorkspace, WorkspaceBuildScripts}; use stdx::{format_to, thread::ThreadIntent}; use triomphe::Arc; use vfs::{AbsPath, AbsPathBuf, ChangeKind}; @@ -204,7 +204,14 @@ impl GlobalState { self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let linked_projects = self.config.linked_or_discovered_projects(); - let detached_files = self.config.detached_files().to_vec(); + let detached_files: Vec<_> = self + .config + .detached_files() + .iter() + .cloned() + .map(ManifestPath::try_from) + .filter_map(Result::ok) + .collect(); let cargo_config = self.config.cargo(); move |sender| { diff --git a/crates/rust-analyzer/tests/crate_graph.rs b/crates/rust-analyzer/tests/crate_graph.rs index cf38032b94..e833ea5e11 100644 --- a/crates/rust-analyzer/tests/crate_graph.rs +++ b/crates/rust-analyzer/tests/crate_graph.rs @@ -1,14 +1,18 @@ use std::path::PathBuf; -use project_model::{CargoWorkspace, ProjectWorkspace, Sysroot, WorkspaceBuildScripts}; +use project_model::{ + CargoWorkspace, ManifestPath, Metadata, ProjectWorkspace, Sysroot, WorkspaceBuildScripts, +}; use rust_analyzer::ws_to_crate_graph; use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; use vfs::{AbsPathBuf, FileId}; fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace { - let meta = get_test_json_file(file); - let cargo_workspace = CargoWorkspace::new(meta); + let meta: Metadata = get_test_json_file(file); + let manifest_path = + ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap(); + let cargo_workspace = CargoWorkspace::new(meta, manifest_path); ProjectWorkspace::Cargo { cargo: cargo_workspace, build_scripts: WorkspaceBuildScripts::default(), diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index b87f02947b..2ca86bc50a 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -150,6 +150,7 @@ use dependency2::Spam; ) .with_config(serde_json::json!({ "cargo": { "sysroot": null }, + "detachedFiles": ["/src/lib.rs"], })) .server() .wait_until_workspace_is_loaded(); diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index f04962a7a2..cf27cc7eef 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs @@ -185,11 +185,7 @@ impl Project<'_> { roots, None, ); - // TODO: don't hardcode src/lib.rs as detached file - let mut c = self.config; - let p = tmp_dir_path.join("src/lib.rs").to_string(); - c["detachedFiles"] = serde_json::json!([p]); - config.update(c).expect("invalid config"); + config.update(self.config).expect("invalid config"); config.rediscover_workspaces(); Server::new(tmp_dir.keep(), config) diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index a03ab0031d..6e4820c5de 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -778,7 +778,8 @@ Disable project auto-discovery in favor of explicitly specified set of projects. Elements must be paths pointing to `Cargo.toml`, -`rust-project.json`, or JSON objects in `rust-project.json` format. +`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON +objects in `rust-project.json` format. -- [[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 389e1b8742..352eb24229 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1495,7 +1495,7 @@ "type": "boolean" }, "rust-analyzer.linkedProjects": { - "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.", + "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.", "default": [], "type": "array", "items": { |