]> git.lizzy.rs Git - rust.git/blobdiff - crates/project_model/src/workspace.rs
Don't load auxiliary crates outside the workspace
[rust.git] / crates / project_model / src / workspace.rs
index cb79ce08bad63e7cd4619c27b7583255db8318eb..96522bf070a4ccc1dddef77d689bb985d5d0b423 100644 (file)
@@ -2,11 +2,12 @@
 //! metadata` or `rust-project.json`) into representation stored in the salsa
 //! database -- `CrateGraph`.
 
-use std::{collections::VecDeque, convert::TryFrom, fmt, fs, process::Command};
+use std::{collections::VecDeque, fmt, fs, process::Command};
 
 use anyhow::{format_err, Context, Result};
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacro,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
+    FileId, ProcMacro,
 };
 use cfg::{CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
@@ -160,14 +161,19 @@ pub fn load(
                     cmd
                 })?;
 
-                let meta = CargoWorkspace::fetch_metadata(&cargo_toml, config, progress)
-                    .with_context(|| {
-                        format!(
-                            "Failed to read Cargo metadata from Cargo.toml file {}, {}",
-                            cargo_toml.display(),
-                            cargo_version
-                        )
-                    })?;
+                let meta = CargoWorkspace::fetch_metadata(
+                    &cargo_toml,
+                    cargo_toml.parent(),
+                    config,
+                    progress,
+                )
+                .with_context(|| {
+                    format!(
+                        "Failed to read Cargo metadata from Cargo.toml file {}, {}",
+                        cargo_toml.display(),
+                        cargo_version
+                    )
+                })?;
                 let cargo = CargoWorkspace::new(meta);
 
                 let sysroot = if config.no_sysroot {
@@ -189,10 +195,15 @@ pub fn load(
 
                 let rustc = match rustc_dir {
                     Some(rustc_dir) => Some({
-                        let meta = CargoWorkspace::fetch_metadata(&rustc_dir, config, progress)
-                            .with_context(|| {
-                                "Failed to read Cargo metadata for Rust sources".to_string()
-                            })?;
+                        let meta = CargoWorkspace::fetch_metadata(
+                            &rustc_dir,
+                            cargo_toml.parent(),
+                            config,
+                            progress,
+                        )
+                        .with_context(|| {
+                            "Failed to read Cargo metadata for Rust sources".to_string()
+                        })?;
                         CargoWorkspace::new(meta)
                     }),
                     None => None,
@@ -376,10 +387,14 @@ pub fn n_packages(&self) -> usize {
 
     pub fn to_crate_graph(
         &self,
-        load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+        dummy_replace: &FxHashMap<Box<str>, Box<[Box<str>]>>,
+        load_proc_macro: &mut dyn FnMut(&AbsPath, &[Box<str>]) -> Vec<ProcMacro>,
         load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     ) -> CrateGraph {
         let _p = profile::span("ProjectWorkspace::to_crate_graph");
+        let load_proc_macro = &mut |crate_name: &_, path: &_| {
+            load_proc_macro(path, dummy_replace.get(crate_name).map(|it| &**it).unwrap_or_default())
+        };
 
         let mut crate_graph = match self {
             ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
@@ -421,7 +436,7 @@ pub fn to_crate_graph(
 
 fn project_json_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     project: &ProjectJson,
     sysroot: &Option<Sysroot>,
@@ -441,7 +456,12 @@ fn project_json_to_crate_graph(
         })
         .map(|(crate_id, krate, file_id)| {
             let env = krate.env.clone().into_iter().collect();
-            let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| load_proc_macro(&it));
+            let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| {
+                load_proc_macro(
+                    krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""),
+                    &it,
+                )
+            });
 
             let target_cfgs = match krate.target.as_deref() {
                 Some(target) => {
@@ -458,10 +478,16 @@ fn project_json_to_crate_graph(
                     file_id,
                     krate.edition,
                     krate.display_name.clone(),
+                    krate.version.clone(),
                     cfg_options.clone(),
                     cfg_options,
                     env,
                     proc_macro.unwrap_or_default(),
+                    if krate.display_name.is_some() {
+                        CrateOrigin::CratesIo { repo: krate.repository.clone() }
+                    } else {
+                        CrateOrigin::Unknown
+                    },
                 ),
             )
         })
@@ -496,7 +522,7 @@ fn project_json_to_crate_graph(
 fn cargo_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     override_cfg: &CfgOverrides,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     cargo: &CargoWorkspace,
     build_scripts: &WorkspaceBuildScripts,
@@ -548,13 +574,22 @@ fn cargo_to_crate_graph(
         has_private |= cargo[pkg].metadata.rustc_private;
         let mut lib_tgt = None;
         for &tgt in cargo[pkg].targets.iter() {
+            if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member {
+                // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't
+                // add any targets except the library target, since those will not work correctly if
+                // they use dev-dependencies.
+                // In fact, they can break quite badly if multiple client workspaces get merged:
+                // https://github.com/rust-analyzer/rust-analyzer/issues/11300
+                continue;
+            }
+
             if let Some(file_id) = load(&cargo[tgt].root) {
                 let crate_id = add_target_crate_root(
                     &mut crate_graph,
                     &cargo[pkg],
                     build_scripts.outputs.get(pkg),
                     cfg_options,
-                    load_proc_macro,
+                    &mut |path| load_proc_macro(&cargo[tgt].name, path),
                     file_id,
                     &cargo[tgt].name,
                 );
@@ -578,6 +613,9 @@ fn cargo_to_crate_graph(
 
         // Set deps to the core, std and to the lib target of the current package
         for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
+            // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
+            public_deps.add(*from, &mut crate_graph);
+
             if let Some((to, name)) = lib_tgt.clone() {
                 if to != *from && *kind != TargetKind::BuildScript {
                     // (build script can not depend on its library target)
@@ -589,7 +627,6 @@ fn cargo_to_crate_graph(
                     add_dep(&mut crate_graph, *from, name, to);
                 }
             }
-            public_deps.add(*from, &mut crate_graph);
         }
     }
 
@@ -665,10 +702,12 @@ fn detached_files_to_crate_graph(
             file_id,
             Edition::CURRENT,
             display_name,
+            None,
             cfg_options.clone(),
             cfg_options.clone(),
             Env::default(),
             Vec::new(),
+            CrateOrigin::Unknown,
         );
 
         public_deps.add(detached_file_crate, &mut crate_graph);
@@ -681,7 +720,7 @@ fn handle_rustc_crates(
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     crate_graph: &mut CrateGraph,
     cfg_options: &CfgOptions,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
     public_deps: &SysrootPublicDeps,
     cargo: &CargoWorkspace,
@@ -717,7 +756,7 @@ fn handle_rustc_crates(
                         &rustc_workspace[pkg],
                         None,
                         cfg_options,
-                        load_proc_macro,
+                        &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
                         file_id,
                         &rustc_workspace[tgt].name,
                     );
@@ -809,15 +848,16 @@ fn add_target_crate_root(
             .iter()
             .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
     );
-
     crate_graph.add_crate_root(
         file_id,
         edition,
         Some(display_name),
+        Some(pkg.version.to_string()),
         cfg_options,
         potential_cfg_options,
         env,
         proc_macro,
+        CrateOrigin::CratesIo { repo: pkg.repository.clone() },
     )
 }
 
@@ -856,10 +896,12 @@ fn sysroot_to_crate_graph(
                 file_id,
                 Edition::CURRENT,
                 Some(display_name),
+                None,
                 cfg_options.clone(),
                 cfg_options.clone(),
                 env,
                 proc_macro,
+                CrateOrigin::Lang,
             );
             Some((krate, crate_id))
         })