about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/project-model/src/build_scripts.rs19
-rw-r--r--crates/project-model/src/workspace.rs13
-rw-r--r--crates/rust-analyzer/src/reload.rs9
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs47
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs16
-rw-r--r--crates/rust-analyzer/tests/slow-tests/testdir.rs37
6 files changed, 114 insertions, 27 deletions
diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs
index 68cd40c040b..c1670c20049 100644
--- a/crates/project-model/src/build_scripts.rs
+++ b/crates/project-model/src/build_scripts.rs
@@ -60,6 +60,7 @@ impl WorkspaceBuildScripts {
     fn build_command(
         config: &CargoConfig,
         allowed_features: &FxHashSet<String>,
+        workspace_root: &AbsPathBuf,
     ) -> io::Result<Command> {
         let mut cmd = match config.run_build_script_command.as_deref() {
             Some([program, args @ ..]) => {
@@ -73,6 +74,9 @@ impl WorkspaceBuildScripts {
                 cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
                 cmd.args(&config.extra_args);
 
+                cmd.arg("--manifest-path");
+                cmd.arg(workspace_root.join("Cargo.toml").as_os_str());
+
                 if let Some(target_dir) = &config.target_dir {
                     cmd.arg("--target-dir").arg(target_dir);
                 }
@@ -143,7 +147,11 @@ impl WorkspaceBuildScripts {
         let allowed_features = workspace.workspace_features();
 
         match Self::run_per_ws(
-            Self::build_command(config, &allowed_features)?,
+            Self::build_command(
+                config,
+                &allowed_features,
+                &workspace.workspace_root().to_path_buf(),
+            )?,
             workspace,
             current_dir,
             progress,
@@ -153,7 +161,11 @@ impl WorkspaceBuildScripts {
             {
                 // 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)?;
+                let mut cmd = Self::build_command(
+                    config,
+                    &allowed_features,
+                    &workspace.workspace_root().to_path_buf(),
+                )?;
                 cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
                 let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
                 res.error = Some(error);
@@ -169,6 +181,7 @@ impl WorkspaceBuildScripts {
         config: &CargoConfig,
         workspaces: &[&CargoWorkspace],
         progress: &dyn Fn(String),
+        workspace_root: &AbsPathBuf,
     ) -> io::Result<Vec<WorkspaceBuildScripts>> {
         assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
 
@@ -181,7 +194,7 @@ impl WorkspaceBuildScripts {
                 ))
             }
         };
-        let cmd = Self::build_command(config, &Default::default())?;
+        let cmd = Self::build_command(config, &Default::default(), workspace_root)?;
         // 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/workspace.rs b/crates/project-model/src/workspace.rs
index c04eddc56fb..e14090a9728 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -407,6 +407,7 @@ impl ProjectWorkspace {
         workspaces: &[ProjectWorkspace],
         config: &CargoConfig,
         progress: &dyn Fn(String),
+        workspace_root: &AbsPathBuf,
     ) -> Vec<anyhow::Result<WorkspaceBuildScripts>> {
         if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace)
             || config.run_build_script_command.is_none()
@@ -421,11 +422,13 @@ impl ProjectWorkspace {
                 _ => None,
             })
             .collect();
-        let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
-            Ok(it) => Ok(it.into_iter()),
-            // io::Error is not Clone?
-            Err(e) => Err(sync::Arc::new(e)),
-        };
+        let outputs =
+            &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress, workspace_root)
+            {
+                Ok(it) => Ok(it.into_iter()),
+                // io::Error is not Clone?
+                Err(e) => Err(sync::Arc::new(e)),
+            };
 
         workspaces
             .iter()
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 8e3fa7fa4da..d90933b004d 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -275,6 +275,8 @@ impl GlobalState {
         tracing::info!(%cause, "will fetch build data");
         let workspaces = Arc::clone(&self.workspaces);
         let config = self.config.cargo();
+        let root_path = self.config.root_path().clone();
+
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
             sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
 
@@ -284,7 +286,12 @@ impl GlobalState {
                     sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
                 }
             };
-            let res = ProjectWorkspace::run_all_build_scripts(&workspaces, &config, &progress);
+            let res = ProjectWorkspace::run_all_build_scripts(
+                &workspaces,
+                &config,
+                &progress,
+                &root_path,
+            );
 
             sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
         });
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 78411e2d58d..58a99cc4471 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -682,13 +682,12 @@ version = \"0.0.0\"
     );
 }
 
-#[test]
-fn out_dirs_check() {
+fn out_dirs_check_impl(root_contains_symlink: bool) {
     if skip_slow_tests() {
         return;
     }
 
-    let server = Project::with_fixture(
+    let mut server = Project::with_fixture(
         r###"
 //- /Cargo.toml
 [package]
@@ -745,20 +744,26 @@ fn main() {
     let another_str = include_str!("main.rs");
 }
 "###,
-    )
-    .with_config(serde_json::json!({
-        "cargo": {
-            "buildScripts": {
-                "enable": true
-            },
-            "sysroot": null,
-            "extraEnv": {
-                "RUSTC_BOOTSTRAP": "1"
+    );
+
+    if root_contains_symlink {
+        server = server.with_root_dir_contains_symlink();
+    }
+
+    let server = server
+        .with_config(serde_json::json!({
+            "cargo": {
+                "buildScripts": {
+                    "enable": true
+                },
+                "sysroot": null,
+                "extraEnv": {
+                    "RUSTC_BOOTSTRAP": "1"
+                }
             }
-        }
-    }))
-    .server()
-    .wait_until_workspace_is_loaded();
+        }))
+        .server()
+        .wait_until_workspace_is_loaded();
 
     let res = server.send_request::<HoverRequest>(HoverParams {
         text_document_position_params: TextDocumentPositionParams::new(
@@ -832,6 +837,16 @@ fn main() {
 }
 
 #[test]
+fn out_dirs_check() {
+    out_dirs_check_impl(false);
+}
+
+#[test]
+fn root_contains_symlink_out_dirs_check() {
+    out_dirs_check_impl(true);
+}
+
+#[test]
 #[cfg(any(feature = "sysroot-abi", rust_analyzer))]
 fn resolve_proc_macro() {
     use expect_test::expect;
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index 106b99cb935..e16990eabd0 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -23,6 +23,7 @@ pub(crate) struct Project<'a> {
     tmp_dir: Option<TestDir>,
     roots: Vec<PathBuf>,
     config: serde_json::Value,
+    root_dir_contains_symlink: bool,
 }
 
 impl Project<'_> {
@@ -45,6 +46,7 @@ impl Project<'_> {
                     "enable": false,
                 }
             }),
+            root_dir_contains_symlink: false,
         }
     }
 
@@ -58,6 +60,11 @@ impl Project<'_> {
         self
     }
 
+    pub(crate) fn with_root_dir_contains_symlink(mut self) -> Self {
+        self.root_dir_contains_symlink = true;
+        self
+    }
+
     pub(crate) fn with_config(mut self, config: serde_json::Value) -> Self {
         fn merge(dst: &mut serde_json::Value, src: serde_json::Value) {
             match (dst, src) {
@@ -74,7 +81,14 @@ impl Project<'_> {
     }
 
     pub(crate) fn server(self) -> Server {
-        let tmp_dir = self.tmp_dir.unwrap_or_else(TestDir::new);
+        let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
+            if self.root_dir_contains_symlink {
+                TestDir::new_symlink()
+            } else {
+                TestDir::new()
+            }
+        });
+
         static INIT: Once = Once::new();
         INIT.call_once(|| {
             let filter: tracing_subscriber::filter::Targets =
diff --git a/crates/rust-analyzer/tests/slow-tests/testdir.rs b/crates/rust-analyzer/tests/slow-tests/testdir.rs
index f7fceb58886..45241ad63e5 100644
--- a/crates/rust-analyzer/tests/slow-tests/testdir.rs
+++ b/crates/rust-analyzer/tests/slow-tests/testdir.rs
@@ -11,6 +11,14 @@ pub(crate) struct TestDir {
 
 impl TestDir {
     pub(crate) fn new() -> TestDir {
+        return TestDir::new_dir(false);
+    }
+
+    pub(crate) fn new_symlink() -> TestDir {
+        return TestDir::new_dir(true);
+    }
+
+    fn new_dir(symlink: bool) -> TestDir {
         let temp_dir = std::env::temp_dir();
         // On MacOS builders on GitHub actions, the temp dir is a symlink, and
         // that causes problems down the line. Specifically:
@@ -33,10 +41,24 @@ impl TestDir {
                 continue;
             }
             fs::create_dir_all(&path).unwrap();
+
+            #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
+            if symlink {
+                let symlink_path = base.join(format!("{pid}_{cnt}_symlink"));
+                #[cfg(any(target_os = "macos", target_os = "linux"))]
+                std::os::unix::fs::symlink(path, &symlink_path).unwrap();
+
+                #[cfg(target_os = "windows")]
+                std::os::windows::fs::symlink_dir(path, &symlink_path).unwrap();
+
+                return TestDir { path: symlink_path, keep: false };
+            }
+
             return TestDir { path, keep: false };
         }
         panic!("Failed to create a temporary directory")
     }
+
     #[allow(unused)]
     pub(crate) fn keep(mut self) -> TestDir {
         self.keep = true;
@@ -52,9 +74,22 @@ impl Drop for TestDir {
         if self.keep {
             return;
         }
+
+        let filetype = fs::symlink_metadata(&self.path).unwrap().file_type();
+        let actual_path = filetype.is_symlink().then(|| fs::read_link(&self.path).unwrap());
+
+        if let Some(actual_path) = actual_path {
+            remove_dir_all(&actual_path).unwrap_or_else(|err| {
+                panic!(
+                    "failed to remove temporary link to directory {}: {err}",
+                    actual_path.display()
+                )
+            })
+        }
+
         remove_dir_all(&self.path).unwrap_or_else(|err| {
             panic!("failed to remove temporary directory {}: {err}", self.path.display())
-        })
+        });
     }
 }