about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs72
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs34
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs14
9 files changed, 81 insertions, 66 deletions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 42953d3b833..21b481c1fa2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -227,7 +227,7 @@ fn run_server() -> anyhow::Result<()> {
         .filter(|workspaces| !workspaces.is_empty())
         .unwrap_or_else(|| vec![root_path.clone()]);
     let mut config =
-        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version, None);
+        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version);
     if let Some(json) = initialization_options {
         let mut change = ConfigChange::default();
         change.change_client_config(json);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 34b20851dd6..a8a02712fe2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -37,7 +37,6 @@ impl flags::Scip {
             lsp_types::ClientCapabilities::default(),
             vec![],
             None,
-            None,
         );
 
         if let Some(p) = self.config_path {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index d7f24e6ce1a..02a513f44b2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -3,10 +3,13 @@
 //! Of particular interest is the `feature_flags` hash map: while other fields
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
-use std::{fmt, iter, ops::Not, sync::OnceLock};
+use std::{
+    env, fmt, iter,
+    ops::Not,
+    sync::{LazyLock, OnceLock},
+};
 
 use cfg::{CfgAtom, CfgDiff};
-use dirs::config_dir;
 use hir::Symbol;
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
@@ -735,7 +738,6 @@ pub enum RatomlFileKind {
 }
 
 #[derive(Debug, Clone)]
-// FIXME @alibektas : Seems like a clippy warning of this sort should tell that combining different ConfigInputs into one enum was not a good idea.
 #[allow(clippy::large_enum_variant)]
 enum RatomlFile {
     Workspace(GlobalLocalConfigInput),
@@ -757,16 +759,6 @@ pub struct Config {
     /// by receiving a `lsp_types::notification::DidChangeConfiguration`.
     client_config: (FullConfigInput, ConfigErrors),
 
-    /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
-    /// If not specified by init of a `Config` object this value defaults to :
-    ///
-    /// |Platform | Value                                 | Example                                  |
-    /// | ------- | ------------------------------------- | ---------------------------------------- |
-    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
-    /// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support |
-    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
-    user_config_path: VfsPath,
-
     /// Config node whose values apply to **every** Rust project.
     user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>,
 
@@ -794,8 +786,27 @@ impl std::ops::Deref for Config {
 }
 
 impl Config {
-    pub fn user_config_path(&self) -> &VfsPath {
-        &self.user_config_path
+    /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
+    /// This path is equal to:
+    ///
+    /// |Platform | Value                                 | Example                                  |
+    /// | ------- | ------------------------------------- | ---------------------------------------- |
+    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
+    /// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support |
+    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
+    pub fn user_config_path() -> &'static AbsPath {
+        static USER_CONFIG_PATH: LazyLock<AbsPathBuf> = LazyLock::new(|| {
+            let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
+                std::path::PathBuf::from(path)
+            } else {
+                dirs::config_dir()
+                    .expect("A config dir is expected to existed on all platforms ra supports.")
+                    .join("rust-analyzer")
+            }
+            .join("rust-analyzer.toml");
+            AbsPathBuf::assert_utf8(user_config_path)
+        });
+        &USER_CONFIG_PATH
     }
 
     pub fn same_source_root_parent_map(
@@ -1315,24 +1326,8 @@ impl Config {
         caps: lsp_types::ClientCapabilities,
         workspace_roots: Vec<AbsPathBuf>,
         visual_studio_code_version: Option<Version>,
-        user_config_path: Option<Utf8PathBuf>,
     ) -> Self {
         static DEFAULT_CONFIG_DATA: OnceLock<&'static DefaultConfigData> = OnceLock::new();
-        let user_config_path = if let Some(user_config_path) = user_config_path {
-            user_config_path.join("rust-analyzer").join("rust-analyzer.toml")
-        } else {
-            let p = config_dir()
-                .expect("A config dir is expected to existed on all platforms ra supports.")
-                .join("rust-analyzer")
-                .join("rust-analyzer.toml");
-            Utf8PathBuf::from_path_buf(p).expect("Config dir expected to be abs.")
-        };
-
-        // A user config cannot be a virtual path as rust-analyzer cannot support watching changes in virtual paths.
-        // See `GlobalState::process_changes` to get more info.
-        // FIXME @alibektas : Temporary solution. I don't think this is right as at some point we may allow users to specify
-        // custom USER_CONFIG_PATHs which may also be relative.
-        let user_config_path = VfsPath::from(AbsPathBuf::assert(user_config_path));
 
         Config {
             caps: ClientCapabilities::new(caps),
@@ -1345,7 +1340,6 @@ impl Config {
             default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())),
             source_root_parent_map: Arc::new(FxHashMap::default()),
             user_config: None,
-            user_config_path,
             detached_files: Default::default(),
             validation_errors: Default::default(),
             ratoml_file: Default::default(),
@@ -3417,7 +3411,7 @@ mod tests {
     #[test]
     fn proc_macro_srv_null() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
         change.change_client_config(serde_json::json!({
@@ -3432,7 +3426,7 @@ mod tests {
     #[test]
     fn proc_macro_srv_abs() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
         let mut change = ConfigChange::default();
         change.change_client_config(serde_json::json!({
         "procMacro" : {
@@ -3446,7 +3440,7 @@ mod tests {
     #[test]
     fn proc_macro_srv_rel() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
 
@@ -3466,7 +3460,7 @@ mod tests {
     #[test]
     fn cargo_target_dir_unset() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
 
@@ -3484,7 +3478,7 @@ mod tests {
     #[test]
     fn cargo_target_dir_subdir() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
         change.change_client_config(serde_json::json!({
@@ -3502,7 +3496,7 @@ mod tests {
     #[test]
     fn cargo_target_dir_relative_dir() {
         let mut config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
         change.change_client_config(serde_json::json!({
@@ -3523,7 +3517,7 @@ mod tests {
     #[test]
     fn toml_unknown_key() {
         let config =
-            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None, None);
+            Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
 
         let mut change = ConfigChange::default();
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index e330cfc3cfd..c3ab7f3ae71 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -548,7 +548,6 @@ mod tests {
                 ClientCapabilities::default(),
                 Vec::new(),
                 None,
-                None,
             ),
         );
         let snap = state.snapshot();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 7a7ec1d77e0..1e21249c125 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -380,7 +380,7 @@ impl GlobalState {
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
         {
             let config_change = {
-                let user_config_path = self.config.user_config_path();
+                let user_config_path = Config::user_config_path();
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 510dc22603c..5b58b332df2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -550,9 +550,12 @@ impl GlobalState {
                 };
 
             watchers.extend(
-                iter::once(self.config.user_config_path().as_path())
-                    .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
-                    .flatten()
+                iter::once(Config::user_config_path())
+                    .chain(
+                        self.workspaces
+                            .iter()
+                            .filter_map(|ws| ws.manifest().map(ManifestPath::as_ref)),
+                    )
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
                         glob_pattern: lsp_types::GlobPattern::String(glob_pattern.to_string()),
                         kind: None,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index c06ba9eee14..478840f104e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -8,6 +8,7 @@ use lsp_types::{
 };
 use paths::Utf8PathBuf;
 
+use rust_analyzer::config::Config;
 use rust_analyzer::lsp::ext::{InternalTestingFetchConfig, InternalTestingFetchConfigParams};
 use serde_json::json;
 use test_utils::skip_slow_tests;
@@ -24,7 +25,6 @@ struct RatomlTest {
     urls: Vec<Url>,
     server: Server,
     tmp_path: Utf8PathBuf,
-    user_config_dir: Utf8PathBuf,
 }
 
 impl RatomlTest {
@@ -41,11 +41,7 @@ impl RatomlTest {
 
         let full_fixture = fixtures.join("\n");
 
-        let user_cnf_dir = TestDir::new();
-        let user_config_dir = user_cnf_dir.path().to_owned();
-
-        let mut project =
-            Project::with_fixture(&full_fixture).tmp_dir(tmp_dir).user_config_dir(user_cnf_dir);
+        let mut project = Project::with_fixture(&full_fixture).tmp_dir(tmp_dir);
 
         for root in roots {
             project = project.root(root);
@@ -57,7 +53,7 @@ impl RatomlTest {
 
         let server = project.server().wait_until_workspace_is_loaded();
 
-        let mut case = Self { urls: vec![], server, tmp_path, user_config_dir };
+        let mut case = Self { urls: vec![], server, tmp_path };
         let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>();
         case.urls = urls;
         case
@@ -81,7 +77,7 @@ impl RatomlTest {
         let mut spl = spl.into_iter();
         if let Some(first) = spl.next() {
             if first == "$$CONFIG_DIR$$" {
-                path = self.user_config_dir.clone();
+                path = Config::user_config_path().to_path_buf().into();
             } else {
                 path = path.join(first);
             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 081ee5fa3e4..5bd27133c2c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -8,6 +8,7 @@ use std::{
 use crossbeam_channel::{after, select, Receiver};
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
+use parking_lot::{Mutex, MutexGuard};
 use paths::{Utf8Path, Utf8PathBuf};
 use rust_analyzer::{
     config::{Config, ConfigChange, ConfigErrors},
@@ -27,7 +28,6 @@ pub(crate) struct Project<'a> {
     roots: Vec<Utf8PathBuf>,
     config: serde_json::Value,
     root_dir_contains_symlink: bool,
-    user_config_path: Option<Utf8PathBuf>,
 }
 
 impl Project<'_> {
@@ -51,15 +51,9 @@ impl Project<'_> {
                 }
             }),
             root_dir_contains_symlink: false,
-            user_config_path: None,
         }
     }
 
-    pub(crate) fn user_config_dir(mut self, config_path_dir: TestDir) -> Self {
-        self.user_config_path = Some(config_path_dir.path().to_owned());
-        self
-    }
-
     pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Self {
         self.tmp_dir = Some(tmp_dir);
         self
@@ -91,6 +85,7 @@ impl Project<'_> {
     }
 
     pub(crate) fn server(self) -> Server {
+        static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
         let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
             if self.root_dir_contains_symlink {
                 TestDir::new_symlink()
@@ -122,9 +117,13 @@ impl Project<'_> {
         assert!(mini_core.is_none());
         assert!(toolchain.is_none());
 
+        let mut config_dir_guard = None;
         for entry in fixture {
             if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
-                let path = self.user_config_path.clone().unwrap().join(&pth['/'.len_utf8()..]);
+                if config_dir_guard.is_none() {
+                    config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
+                }
+                let path = Config::user_config_path().join(&pth['/'.len_utf8()..]);
                 fs::create_dir_all(path.parent().unwrap()).unwrap();
                 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
             } else {
@@ -201,7 +200,6 @@ impl Project<'_> {
             },
             roots,
             None,
-            self.user_config_path,
         );
         let mut change = ConfigChange::default();
 
@@ -213,7 +211,7 @@ impl Project<'_> {
 
         config.rediscover_workspaces();
 
-        Server::new(tmp_dir.keep(), config)
+        Server::new(config_dir_guard, tmp_dir.keep(), config)
     }
 }
 
@@ -228,10 +226,15 @@ pub(crate) struct Server {
     client: Connection,
     /// XXX: remove the tempdir last
     dir: TestDir,
+    _config_dir_guard: Option<MutexGuard<'static, ()>>,
 }
 
 impl Server {
-    fn new(dir: TestDir, config: Config) -> Server {
+    fn new(
+        config_dir_guard: Option<MutexGuard<'static, ()>>,
+        dir: TestDir,
+        config: Config,
+    ) -> Server {
         let (connection, client) = Connection::memory();
 
         let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
@@ -239,7 +242,14 @@ impl Server {
             .spawn(move || main_loop(config, connection).unwrap())
             .expect("failed to spawn a thread");
 
-        Server { req_id: Cell::new(1), dir, messages: Default::default(), client, _thread }
+        Server {
+            req_id: Cell::new(1),
+            dir,
+            messages: Default::default(),
+            client,
+            _thread,
+            _config_dir_guard: config_dir_guard,
+        }
     }
 
     pub(crate) fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
index 92a49e07936..3c8e37413f6 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
@@ -313,6 +313,20 @@ impl fmt::Debug for VfsPathRepr {
     }
 }
 
+impl PartialEq<AbsPath> for VfsPath {
+    fn eq(&self, other: &AbsPath) -> bool {
+        match &self.0 {
+            VfsPathRepr::PathBuf(lhs) => lhs == other,
+            VfsPathRepr::VirtualPath(_) => false,
+        }
+    }
+}
+impl PartialEq<VfsPath> for AbsPath {
+    fn eq(&self, other: &VfsPath) -> bool {
+        other == self
+    }
+}
+
 /// `/`-separated virtual path.
 ///
 /// This is used to describe files that do not reside on the file system.