about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonas Schievink <jonasschievink@gmail.com>2021-05-12 14:16:51 +0200
committerJonas Schievink <jonasschievink@gmail.com>2021-05-12 14:48:26 +0200
commita272cdfecdbbd95725d66b2452da3d379ef35d76 (patch)
tree92c544276f4556e02c434321f2e0407d54d68a02
parent9a431c26f4528e2649de0ca171a38c93e473c94e (diff)
downloadrust-a272cdfecdbbd95725d66b2452da3d379ef35d76.tar.gz
rust-a272cdfecdbbd95725d66b2452da3d379ef35d76.zip
Fix build script dependencies
-rw-r--r--crates/project_model/src/cargo_workspace.rs34
-rw-r--r--crates/project_model/src/workspace.rs34
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs2
3 files changed, 57 insertions, 13 deletions
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index b18699b7711..4a4996cf4df 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -119,6 +119,32 @@ pub struct RustAnalyzerPackageMetaData {
 pub struct PackageDependency {
     pub pkg: Package,
     pub name: String,
+    pub kind: DepKind,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum DepKind {
+    /// Available to the library, binary, and dev targets in the package (but not the build script).
+    Normal,
+    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
+    Dev,
+    /// Available only to the build script target.
+    Build,
+}
+
+impl DepKind {
+    fn new(list: &[cargo_metadata::DepKindInfo]) -> Self {
+        for info in list {
+            match info.kind {
+                cargo_metadata::DependencyKind::Normal => return Self::Normal,
+                cargo_metadata::DependencyKind::Development => return Self::Dev,
+                cargo_metadata::DependencyKind::Build => return Self::Build,
+                cargo_metadata::DependencyKind::Unknown => continue,
+            }
+        }
+
+        Self::Normal
+    }
 }
 
 /// Information associated with a package's target
@@ -144,6 +170,7 @@ pub enum TargetKind {
     Example,
     Test,
     Bench,
+    BuildScript,
     Other,
 }
 
@@ -155,6 +182,7 @@ impl TargetKind {
                 "test" => TargetKind::Test,
                 "bench" => TargetKind::Bench,
                 "example" => TargetKind::Example,
+                "custom-build" => TargetKind::BuildScript,
                 "proc-macro" => TargetKind::Lib,
                 _ if kind.contains("lib") => TargetKind::Lib,
                 _ => continue,
@@ -301,7 +329,11 @@ impl CargoWorkspace {
                         continue;
                     }
                 };
-                let dep = PackageDependency { name: dep_node.name, pkg };
+                let dep = PackageDependency {
+                    name: dep_node.name,
+                    pkg,
+                    kind: DepKind::new(&dep_node.dep_kinds),
+                };
                 packages[source].dependencies.push(dep);
             }
             packages[source].active_features.extend(node.features);
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 761fbb3ab58..607e62ea590 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -6,6 +6,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
 
 use anyhow::{Context, Result};
 use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
+use cargo_workspace::DepKind;
 use cfg::CfgOptions;
 use paths::{AbsPath, AbsPathBuf};
 use proc_macro_api::ProcMacroClient;
@@ -407,23 +408,25 @@ fn cargo_to_crate_graph(
                     }
                 }
 
-                pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
+                pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
             }
         }
 
         // Set deps to the core, std and to the lib target of the current package
-        for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+        for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
             if let Some((to, name)) = lib_tgt.clone() {
-                if to != from {
+                if to != *from && *kind != TargetKind::BuildScript {
+                    // (build script can not depend on its library target)
+
                     // For root projects with dashes in their name,
                     // cargo metadata does not do any normalization,
                     // so we do it ourselves currently
                     let name = CrateName::normalize_dashes(&name);
-                    add_dep(&mut crate_graph, from, name, to);
+                    add_dep(&mut crate_graph, *from, name, to);
                 }
             }
             for (name, krate) in public_deps.iter() {
-                add_dep(&mut crate_graph, from, name.clone(), *krate);
+                add_dep(&mut crate_graph, *from, name.clone(), *krate);
             }
         }
     }
@@ -434,8 +437,17 @@ fn cargo_to_crate_graph(
         for dep in cargo[pkg].dependencies.iter() {
             let name = CrateName::new(&dep.name).unwrap();
             if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
-                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
-                    add_dep(&mut crate_graph, from, name.clone(), to)
+                for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
+                    if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
+                        // Only build scripts may depend on build dependencies.
+                        continue;
+                    }
+                    if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
+                        // Build scripts may only depend on build dependencies.
+                        continue;
+                    }
+
+                    add_dep(&mut crate_graph, *from, name.clone(), to)
                 }
             }
         }
@@ -472,7 +484,7 @@ fn handle_rustc_crates(
     pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
     public_deps: &[(CrateName, CrateId)],
     cargo: &CargoWorkspace,
-    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<CrateId>>,
+    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
 ) {
     let mut rustc_pkg_crates = FxHashMap::default();
     // The root package of the rustc-dev component is rustc_driver, so we match that
@@ -541,13 +553,13 @@ fn handle_rustc_crates(
                 if !package.metadata.rustc_private {
                     continue;
                 }
-                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
                     // Avoid creating duplicate dependencies
                     // This avoids the situation where `from` depends on e.g. `arrayvec`, but
                     // `rust_analyzer` thinks that it should use the one from the `rustcSource`
                     // instead of the one from `crates.io`
-                    if !crate_graph[from].dependencies.iter().any(|d| d.name == name) {
-                        add_dep(crate_graph, from, name.clone(), to);
+                    if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
+                        add_dep(crate_graph, *from, name.clone(), to);
                     }
                 }
             }
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 909c2153225..f4cd43448d0 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -159,7 +159,7 @@ impl CargoTargetSpec {
             TargetKind::Lib => {
                 buf.push("--lib".to_string());
             }
-            TargetKind::Other => (),
+            TargetKind::Other | TargetKind::BuildScript => (),
         }
     }
 }