diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-04-12 13:32:55 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-04-12 13:32:55 +0100 |
commit | a526d0a4b78b29fec4c2e8d5608ceaeec128f794 (patch) | |
tree | 05141f6e9aa7d20c4ce2a8b59324a3d82d43f895 | |
parent | 7be06139b632ee615fc18af04dd67947e2c794b2 (diff) | |
parent | 186c5c47cbfde4ae9d81dc67450c958cb6aece2c (diff) |
Merge #8476
8476: feat: avoid checking the whole project during initial loading r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/project_model/src/build_data.rs | 236 | ||||
-rw-r--r-- | crates/rust-analyzer/src/benchmarks.rs | 7 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 15 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/rustc_wrapper.rs | 46 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/diagnostics.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/ssr.rs | 9 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/main.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/support.rs | 20 | ||||
-rw-r--r-- | docs/user/generated_config.adoc | 6 | ||||
-rw-r--r-- | editors/code/package.json | 5 |
14 files changed, 248 insertions, 121 deletions
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index 0d4d39fef..ab5cc8c49 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -58,12 +58,17 @@ impl PartialEq for BuildDataConfig { | |||
58 | 58 | ||
59 | impl Eq for BuildDataConfig {} | 59 | impl Eq for BuildDataConfig {} |
60 | 60 | ||
61 | #[derive(Debug, Default)] | 61 | #[derive(Debug)] |
62 | pub struct BuildDataCollector { | 62 | pub struct BuildDataCollector { |
63 | wrap_rustc: bool, | ||
63 | configs: FxHashMap<AbsPathBuf, BuildDataConfig>, | 64 | configs: FxHashMap<AbsPathBuf, BuildDataConfig>, |
64 | } | 65 | } |
65 | 66 | ||
66 | impl BuildDataCollector { | 67 | impl BuildDataCollector { |
68 | pub fn new(wrap_rustc: bool) -> Self { | ||
69 | Self { wrap_rustc, configs: FxHashMap::default() } | ||
70 | } | ||
71 | |||
67 | pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) { | 72 | pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) { |
68 | self.configs.insert(workspace_root.to_path_buf(), config); | 73 | self.configs.insert(workspace_root.to_path_buf(), config); |
69 | } | 74 | } |
@@ -71,15 +76,14 @@ impl BuildDataCollector { | |||
71 | pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> { | 76 | pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> { |
72 | let mut res = BuildDataResult::default(); | 77 | let mut res = BuildDataResult::default(); |
73 | for (path, config) in self.configs.iter() { | 78 | for (path, config) in self.configs.iter() { |
74 | res.per_workspace.insert( | 79 | let workspace_build_data = WorkspaceBuildData::collect( |
75 | path.clone(), | 80 | &config.cargo_toml, |
76 | collect_from_workspace( | 81 | &config.cargo_features, |
77 | &config.cargo_toml, | 82 | &config.packages, |
78 | &config.cargo_features, | 83 | self.wrap_rustc, |
79 | &config.packages, | 84 | progress, |
80 | progress, | 85 | )?; |
81 | )?, | 86 | res.per_workspace.insert(path.clone(), workspace_build_data); |
82 | ); | ||
83 | } | 87 | } |
84 | Ok(res) | 88 | Ok(res) |
85 | } | 89 | } |
@@ -120,119 +124,137 @@ impl BuildDataConfig { | |||
120 | } | 124 | } |
121 | } | 125 | } |
122 | 126 | ||
123 | fn collect_from_workspace( | 127 | impl WorkspaceBuildData { |
124 | cargo_toml: &AbsPath, | 128 | fn collect( |
125 | cargo_features: &CargoConfig, | 129 | cargo_toml: &AbsPath, |
126 | packages: &Vec<cargo_metadata::Package>, | 130 | cargo_features: &CargoConfig, |
127 | progress: &dyn Fn(String), | 131 | packages: &Vec<cargo_metadata::Package>, |
128 | ) -> Result<WorkspaceBuildData> { | 132 | wrap_rustc: bool, |
129 | let mut cmd = Command::new(toolchain::cargo()); | 133 | progress: &dyn Fn(String), |
130 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) | 134 | ) -> Result<WorkspaceBuildData> { |
131 | .arg(cargo_toml.as_ref()); | 135 | let mut cmd = Command::new(toolchain::cargo()); |
132 | 136 | ||
133 | // --all-targets includes tests, benches and examples in addition to the | 137 | if wrap_rustc { |
134 | // default lib and bins. This is an independent concept from the --targets | 138 | // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use |
135 | // flag below. | 139 | // that to compile only proc macros and build scripts during the initial |
136 | cmd.arg("--all-targets"); | 140 | // `cargo check`. |
137 | 141 | let myself = std::env::current_exe()?; | |
138 | if let Some(target) = &cargo_features.target { | 142 | cmd.env("RUSTC_WRAPPER", myself); |
139 | cmd.args(&["--target", target]); | 143 | cmd.env("RA_RUSTC_WRAPPER", "1"); |
140 | } | 144 | } |
145 | |||
146 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) | ||
147 | .arg(cargo_toml.as_ref()); | ||
141 | 148 | ||
142 | if cargo_features.all_features { | 149 | // --all-targets includes tests, benches and examples in addition to the |
143 | cmd.arg("--all-features"); | 150 | // default lib and bins. This is an independent concept from the --targets |
144 | } else { | 151 | // flag below. |
145 | if cargo_features.no_default_features { | 152 | cmd.arg("--all-targets"); |
146 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | 153 | |
147 | // https://github.com/oli-obk/cargo_metadata/issues/79 | 154 | if let Some(target) = &cargo_features.target { |
148 | cmd.arg("--no-default-features"); | 155 | cmd.args(&["--target", target]); |
149 | } | 156 | } |
150 | if !cargo_features.features.is_empty() { | 157 | |
151 | cmd.arg("--features"); | 158 | if cargo_features.all_features { |
152 | cmd.arg(cargo_features.features.join(" ")); | 159 | cmd.arg("--all-features"); |
160 | } else { | ||
161 | if cargo_features.no_default_features { | ||
162 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
163 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
164 | cmd.arg("--no-default-features"); | ||
165 | } | ||
166 | if !cargo_features.features.is_empty() { | ||
167 | cmd.arg("--features"); | ||
168 | cmd.arg(cargo_features.features.join(" ")); | ||
169 | } | ||
153 | } | 170 | } |
154 | } | ||
155 | 171 | ||
156 | cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); | 172 | cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); |
157 | 173 | ||
158 | let mut child = cmd.spawn().map(JodChild)?; | 174 | let mut child = cmd.spawn().map(JodChild)?; |
159 | let child_stdout = child.stdout.take().unwrap(); | 175 | let child_stdout = child.stdout.take().unwrap(); |
160 | let stdout = BufReader::new(child_stdout); | 176 | let stdout = BufReader::new(child_stdout); |
161 | 177 | ||
162 | let mut res = WorkspaceBuildData::default(); | 178 | let mut res = WorkspaceBuildData::default(); |
163 | for message in cargo_metadata::Message::parse_stream(stdout).flatten() { | 179 | for message in cargo_metadata::Message::parse_stream(stdout).flatten() { |
164 | match message { | 180 | match message { |
165 | Message::BuildScriptExecuted(BuildScript { | 181 | Message::BuildScriptExecuted(BuildScript { |
166 | package_id, out_dir, cfgs, env, .. | 182 | package_id, |
167 | }) => { | 183 | out_dir, |
168 | let cfgs = { | 184 | cfgs, |
169 | let mut acc = Vec::new(); | 185 | env, |
170 | for cfg in cfgs { | 186 | .. |
171 | match cfg.parse::<CfgFlag>() { | 187 | }) => { |
172 | Ok(it) => acc.push(it), | 188 | let cfgs = { |
173 | Err(err) => { | 189 | let mut acc = Vec::new(); |
174 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | 190 | for cfg in cfgs { |
175 | } | 191 | match cfg.parse::<CfgFlag>() { |
176 | }; | 192 | Ok(it) => acc.push(it), |
193 | Err(err) => { | ||
194 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
195 | } | ||
196 | }; | ||
197 | } | ||
198 | acc | ||
199 | }; | ||
200 | let package_build_data = | ||
201 | res.per_package.entry(package_id.repr.clone()).or_default(); | ||
202 | // cargo_metadata crate returns default (empty) path for | ||
203 | // older cargos, which is not absolute, so work around that. | ||
204 | if !out_dir.as_str().is_empty() { | ||
205 | let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
206 | package_build_data.out_dir = Some(out_dir); | ||
207 | package_build_data.cfgs = cfgs; | ||
177 | } | 208 | } |
178 | acc | ||
179 | }; | ||
180 | let package_build_data = | ||
181 | res.per_package.entry(package_id.repr.clone()).or_default(); | ||
182 | // cargo_metadata crate returns default (empty) path for | ||
183 | // older cargos, which is not absolute, so work around that. | ||
184 | if !out_dir.as_str().is_empty() { | ||
185 | let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
186 | package_build_data.out_dir = Some(out_dir); | ||
187 | package_build_data.cfgs = cfgs; | ||
188 | } | ||
189 | 209 | ||
190 | package_build_data.envs = env; | 210 | package_build_data.envs = env; |
191 | } | 211 | } |
192 | Message::CompilerArtifact(message) => { | 212 | Message::CompilerArtifact(message) => { |
193 | progress(format!("metadata {}", message.target.name)); | 213 | progress(format!("metadata {}", message.target.name)); |
194 | 214 | ||
195 | if message.target.kind.contains(&"proc-macro".to_string()) { | 215 | if message.target.kind.contains(&"proc-macro".to_string()) { |
196 | let package_id = message.package_id; | 216 | let package_id = message.package_id; |
197 | // Skip rmeta file | 217 | // Skip rmeta file |
198 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) { | 218 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) |
199 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); | 219 | { |
200 | let package_build_data = | 220 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); |
201 | res.per_package.entry(package_id.repr.clone()).or_default(); | 221 | let package_build_data = |
202 | package_build_data.proc_macro_dylib_path = Some(filename); | 222 | res.per_package.entry(package_id.repr.clone()).or_default(); |
223 | package_build_data.proc_macro_dylib_path = Some(filename); | ||
224 | } | ||
203 | } | 225 | } |
204 | } | 226 | } |
227 | Message::CompilerMessage(message) => { | ||
228 | progress(message.target.name.clone()); | ||
229 | } | ||
230 | Message::BuildFinished(_) => {} | ||
231 | Message::TextLine(_) => {} | ||
232 | _ => {} | ||
205 | } | 233 | } |
206 | Message::CompilerMessage(message) => { | ||
207 | progress(message.target.name.clone()); | ||
208 | } | ||
209 | Message::BuildFinished(_) => {} | ||
210 | Message::TextLine(_) => {} | ||
211 | _ => {} | ||
212 | } | 234 | } |
213 | } | ||
214 | 235 | ||
215 | for package in packages { | 236 | for package in packages { |
216 | let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default(); | 237 | let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default(); |
217 | inject_cargo_env(package, package_build_data); | 238 | inject_cargo_env(package, package_build_data); |
218 | if let Some(out_dir) = &package_build_data.out_dir { | 239 | if let Some(out_dir) = &package_build_data.out_dir { |
219 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | 240 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() |
220 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | 241 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { |
221 | package_build_data.envs.push(("OUT_DIR".to_string(), out_dir)); | 242 | package_build_data.envs.push(("OUT_DIR".to_string(), out_dir)); |
243 | } | ||
222 | } | 244 | } |
223 | } | 245 | } |
224 | } | ||
225 | 246 | ||
226 | let output = child.into_inner().wait_with_output()?; | 247 | let output = child.into_inner().wait_with_output()?; |
227 | if !output.status.success() { | 248 | if !output.status.success() { |
228 | let mut stderr = String::from_utf8(output.stderr).unwrap_or_default(); | 249 | let mut stderr = String::from_utf8(output.stderr).unwrap_or_default(); |
229 | if stderr.is_empty() { | 250 | if stderr.is_empty() { |
230 | stderr = "cargo check failed".to_string(); | 251 | stderr = "cargo check failed".to_string(); |
252 | } | ||
253 | res.error = Some(stderr) | ||
231 | } | 254 | } |
232 | res.error = Some(stderr) | ||
233 | } | ||
234 | 255 | ||
235 | Ok(res) | 256 | Ok(res) |
257 | } | ||
236 | } | 258 | } |
237 | 259 | ||
238 | // FIXME: File a better way to know if it is a dylib | 260 | // FIXME: File a better way to know if it is a dylib |
diff --git a/crates/rust-analyzer/src/benchmarks.rs b/crates/rust-analyzer/src/benchmarks.rs index bf569b40b..bdd94b1c4 100644 --- a/crates/rust-analyzer/src/benchmarks.rs +++ b/crates/rust-analyzer/src/benchmarks.rs | |||
@@ -30,8 +30,11 @@ fn benchmark_integrated_highlighting() { | |||
30 | let file = "./crates/ide_db/src/apply_change.rs"; | 30 | let file = "./crates/ide_db/src/apply_change.rs"; |
31 | 31 | ||
32 | let cargo_config = Default::default(); | 32 | let cargo_config = Default::default(); |
33 | let load_cargo_config = | 33 | let load_cargo_config = LoadCargoConfig { |
34 | LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: false }; | 34 | load_out_dirs_from_check: true, |
35 | wrap_rustc: false, | ||
36 | with_proc_macro: false, | ||
37 | }; | ||
35 | 38 | ||
36 | let (mut host, vfs, _proc_macro) = { | 39 | let (mut host, vfs, _proc_macro) = { |
37 | let _it = stdx::timeit("workspace loading"); | 40 | let _it = stdx::timeit("workspace loading"); |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 873e82c7b..f0abb5b15 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | //! Based on cli flags, either spawns an LSP server, or runs a batch analysis | 3 | //! Based on cli flags, either spawns an LSP server, or runs a batch analysis |
4 | mod flags; | 4 | mod flags; |
5 | mod logger; | 5 | mod logger; |
6 | mod rustc_wrapper; | ||
6 | 7 | ||
7 | use std::{convert::TryFrom, env, fs, path::Path, process}; | 8 | use std::{convert::TryFrom, env, fs, path::Path, process}; |
8 | 9 | ||
@@ -26,6 +27,20 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; | |||
26 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; | 27 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; |
27 | 28 | ||
28 | fn main() { | 29 | fn main() { |
30 | if std::env::var("RA_RUSTC_WRAPPER").is_ok() { | ||
31 | let mut args = std::env::args_os(); | ||
32 | let _me = args.next().unwrap(); | ||
33 | let rustc = args.next().unwrap(); | ||
34 | let code = match rustc_wrapper::run_rustc_skipping_cargo_checking(rustc, args.collect()) { | ||
35 | Ok(rustc_wrapper::ExitCode(code)) => code.unwrap_or(102), | ||
36 | Err(err) => { | ||
37 | eprintln!("{}", err); | ||
38 | 101 | ||
39 | } | ||
40 | }; | ||
41 | process::exit(code); | ||
42 | } | ||
43 | |||
29 | if let Err(err) = try_main() { | 44 | if let Err(err) = try_main() { |
30 | log::error!("Unexpected error: {}", err); | 45 | log::error!("Unexpected error: {}", err); |
31 | eprintln!("{}", err); | 46 | eprintln!("{}", err); |
diff --git a/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/crates/rust-analyzer/src/bin/rustc_wrapper.rs new file mode 100644 index 000000000..2f6d4706d --- /dev/null +++ b/crates/rust-analyzer/src/bin/rustc_wrapper.rs | |||
@@ -0,0 +1,46 @@ | |||
1 | //! We setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself during the | ||
2 | //! initial `cargo check`. That way, we avoid checking the actual project, and | ||
3 | //! only build proc macros and build.rs. | ||
4 | //! | ||
5 | //! Code taken from IntelliJ :0) | ||
6 | //! https://github.com/intellij-rust/intellij-rust/blob/master/native-helper/src/main.rs | ||
7 | use std::{ | ||
8 | ffi::OsString, | ||
9 | io, | ||
10 | process::{Command, Stdio}, | ||
11 | }; | ||
12 | |||
13 | /// ExitCode/ExitStatus are impossible to create :(. | ||
14 | pub(crate) struct ExitCode(pub(crate) Option<i32>); | ||
15 | |||
16 | pub(crate) fn run_rustc_skipping_cargo_checking( | ||
17 | rustc_executable: OsString, | ||
18 | args: Vec<OsString>, | ||
19 | ) -> io::Result<ExitCode> { | ||
20 | let is_cargo_check = args.iter().any(|arg| { | ||
21 | let arg = arg.to_string_lossy(); | ||
22 | // `cargo check` invokes `rustc` with `--emit=metadata` argument. | ||
23 | // | ||
24 | // https://doc.rust-lang.org/rustc/command-line-arguments.html#--emit-specifies-the-types-of-output-files-to-generate | ||
25 | // link — Generates the crates specified by --crate-type. The default | ||
26 | // output filenames depend on the crate type and platform. This | ||
27 | // is the default if --emit is not specified. | ||
28 | // metadata — Generates a file containing metadata about the crate. | ||
29 | // The default output filename is CRATE_NAME.rmeta. | ||
30 | arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link") | ||
31 | }); | ||
32 | if is_cargo_check { | ||
33 | return Ok(ExitCode(Some(0))); | ||
34 | } | ||
35 | run_rustc(rustc_executable, args) | ||
36 | } | ||
37 | |||
38 | fn run_rustc(rustc_executable: OsString, args: Vec<OsString>) -> io::Result<ExitCode> { | ||
39 | let mut child = Command::new(rustc_executable) | ||
40 | .args(args) | ||
41 | .stdin(Stdio::inherit()) | ||
42 | .stdout(Stdio::inherit()) | ||
43 | .stderr(Stdio::inherit()) | ||
44 | .spawn()?; | ||
45 | Ok(ExitCode(child.wait()?.code())) | ||
46 | } | ||
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index fe9f273b0..3f3134562 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -68,6 +68,7 @@ impl AnalysisStatsCmd { | |||
68 | cargo_config.no_sysroot = self.no_sysroot; | 68 | cargo_config.no_sysroot = self.no_sysroot; |
69 | let load_cargo_config = LoadCargoConfig { | 69 | let load_cargo_config = LoadCargoConfig { |
70 | load_out_dirs_from_check: self.load_output_dirs, | 70 | load_out_dirs_from_check: self.load_output_dirs, |
71 | wrap_rustc: false, | ||
71 | with_proc_macro: self.with_proc_macro, | 72 | with_proc_macro: self.with_proc_macro, |
72 | }; | 73 | }; |
73 | let (host, vfs, _proc_macro) = | 74 | let (host, vfs, _proc_macro) = |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 8b985716b..0085d0e4d 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -34,7 +34,8 @@ pub fn diagnostics( | |||
34 | with_proc_macro: bool, | 34 | with_proc_macro: bool, |
35 | ) -> Result<()> { | 35 | ) -> Result<()> { |
36 | let cargo_config = Default::default(); | 36 | let cargo_config = Default::default(); |
37 | let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check, with_proc_macro }; | 37 | let load_cargo_config = |
38 | LoadCargoConfig { load_out_dirs_from_check, with_proc_macro, wrap_rustc: false }; | ||
38 | let (host, _vfs, _proc_macro) = | 39 | let (host, _vfs, _proc_macro) = |
39 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; | 40 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; |
40 | let db = host.raw_database(); | 41 | let db = host.raw_database(); |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 310c36904..75bad1112 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -15,6 +15,7 @@ use crate::reload::{ProjectFolders, SourceRootConfig}; | |||
15 | 15 | ||
16 | pub struct LoadCargoConfig { | 16 | pub struct LoadCargoConfig { |
17 | pub load_out_dirs_from_check: bool, | 17 | pub load_out_dirs_from_check: bool, |
18 | pub wrap_rustc: bool, | ||
18 | pub with_proc_macro: bool, | 19 | pub with_proc_macro: bool, |
19 | } | 20 | } |
20 | 21 | ||
@@ -52,7 +53,7 @@ pub fn load_workspace( | |||
52 | }; | 53 | }; |
53 | 54 | ||
54 | let build_data = if config.load_out_dirs_from_check { | 55 | let build_data = if config.load_out_dirs_from_check { |
55 | let mut collector = BuildDataCollector::default(); | 56 | let mut collector = BuildDataCollector::new(config.wrap_rustc); |
56 | ws.collect_build_data_configs(&mut collector); | 57 | ws.collect_build_data_configs(&mut collector); |
57 | Some(collector.collect(progress)?) | 58 | Some(collector.collect(progress)?) |
58 | } else { | 59 | } else { |
@@ -136,8 +137,11 @@ mod tests { | |||
136 | fn test_loading_rust_analyzer() -> Result<()> { | 137 | fn test_loading_rust_analyzer() -> Result<()> { |
137 | let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); | 138 | let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); |
138 | let cargo_config = Default::default(); | 139 | let cargo_config = Default::default(); |
139 | let load_cargo_config = | 140 | let load_cargo_config = LoadCargoConfig { |
140 | LoadCargoConfig { load_out_dirs_from_check: false, with_proc_macro: false }; | 141 | load_out_dirs_from_check: false, |
142 | wrap_rustc: false, | ||
143 | with_proc_macro: false, | ||
144 | }; | ||
141 | let (host, _vfs, _proc_macro) = | 145 | let (host, _vfs, _proc_macro) = |
142 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; | 146 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; |
143 | 147 | ||
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs index 79f426fff..1fd9b5a9b 100644 --- a/crates/rust-analyzer/src/cli/ssr.rs +++ b/crates/rust-analyzer/src/cli/ssr.rs | |||
@@ -9,8 +9,11 @@ use ide_ssr::{MatchFinder, SsrPattern, SsrRule}; | |||
9 | pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { | 9 | pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { |
10 | use ide_db::base_db::SourceDatabaseExt; | 10 | use ide_db::base_db::SourceDatabaseExt; |
11 | let cargo_config = Default::default(); | 11 | let cargo_config = Default::default(); |
12 | let load_cargo_config = | 12 | let load_cargo_config = LoadCargoConfig { |
13 | LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: true }; | 13 | load_out_dirs_from_check: true, |
14 | wrap_rustc: false, | ||
15 | with_proc_macro: true, | ||
16 | }; | ||
14 | let (host, vfs, _proc_macro) = | 17 | let (host, vfs, _proc_macro) = |
15 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; | 18 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; |
16 | let db = host.raw_database(); | 19 | let db = host.raw_database(); |
@@ -37,7 +40,7 @@ pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<Stri | |||
37 | use ide_db::symbol_index::SymbolsDatabase; | 40 | use ide_db::symbol_index::SymbolsDatabase; |
38 | let cargo_config = Default::default(); | 41 | let cargo_config = Default::default(); |
39 | let load_cargo_config = | 42 | let load_cargo_config = |
40 | LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: true }; | 43 | LoadCargoConfig { load_out_dirs_from_check: true, wrap_rustc: true, with_proc_macro: true }; |
41 | let (host, _vfs, _proc_macro) = | 44 | let (host, _vfs, _proc_macro) = |
42 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; | 45 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; |
43 | let db = host.raw_database(); | 46 | let db = host.raw_database(); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index f809667e9..1edaa394a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -48,6 +48,9 @@ config_data! { | |||
48 | /// Run build scripts (`build.rs`) for more precise code analysis. | 48 | /// Run build scripts (`build.rs`) for more precise code analysis. |
49 | cargo_runBuildScripts | | 49 | cargo_runBuildScripts | |
50 | cargo_loadOutDirsFromCheck: bool = "true", | 50 | cargo_loadOutDirsFromCheck: bool = "true", |
51 | /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to | ||
52 | /// avoid compiling unnecessary things. | ||
53 | cargo_useRustcWrapperForBuildScripts: bool = "true", | ||
51 | /// Do not activate the `default` feature. | 54 | /// Do not activate the `default` feature. |
52 | cargo_noDefaultFeatures: bool = "false", | 55 | cargo_noDefaultFeatures: bool = "false", |
53 | /// Compilation target (target triple). | 56 | /// Compilation target (target triple). |
@@ -493,6 +496,9 @@ impl Config { | |||
493 | pub fn run_build_scripts(&self) -> bool { | 496 | pub fn run_build_scripts(&self) -> bool { |
494 | self.data.cargo_runBuildScripts || self.data.procMacro_enable | 497 | self.data.cargo_runBuildScripts || self.data.procMacro_enable |
495 | } | 498 | } |
499 | pub fn wrap_rustc(&self) -> bool { | ||
500 | self.data.cargo_useRustcWrapperForBuildScripts | ||
501 | } | ||
496 | pub fn cargo(&self) -> CargoConfig { | 502 | pub fn cargo(&self) -> CargoConfig { |
497 | let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { | 503 | let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { |
498 | if rustc_src == "discover" { | 504 | if rustc_src == "discover" { |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 47c6c6d77..b3d4c6ec5 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -236,7 +236,8 @@ impl GlobalState { | |||
236 | let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); | 236 | let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); |
237 | 237 | ||
238 | if self.config.run_build_scripts() && workspaces_updated { | 238 | if self.config.run_build_scripts() && workspaces_updated { |
239 | let mut collector = BuildDataCollector::default(); | 239 | let mut collector = |
240 | BuildDataCollector::new(self.config.wrap_rustc()); | ||
240 | for ws in self.workspaces.iter() { | 241 | for ws in self.workspaces.iter() { |
241 | ws.collect_build_data_configs(&mut collector); | 242 | ws.collect_build_data_configs(&mut collector); |
242 | } | 243 | } |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index 4442cbff6..1e4c04bbf 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs | |||
@@ -527,7 +527,7 @@ version = \"0.0.0\" | |||
527 | #[test] | 527 | #[test] |
528 | fn out_dirs_check() { | 528 | fn out_dirs_check() { |
529 | if skip_slow_tests() { | 529 | if skip_slow_tests() { |
530 | return; | 530 | // return; |
531 | } | 531 | } |
532 | 532 | ||
533 | let server = Project::with_fixture( | 533 | let server = Project::with_fixture( |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index 8d68f1b7d..5e388c0f0 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -32,8 +32,12 @@ impl<'a> Project<'a> { | |||
32 | tmp_dir: None, | 32 | tmp_dir: None, |
33 | roots: vec![], | 33 | roots: vec![], |
34 | config: serde_json::json!({ | 34 | config: serde_json::json!({ |
35 | // Loading standard library is costly, let's ignore it by default | 35 | "cargo": { |
36 | "cargo": { "noSysroot": true } | 36 | // Loading standard library is costly, let's ignore it by default |
37 | "noSysroot": true, | ||
38 | // Can't use test binary as rustc wrapper. | ||
39 | "useRustcWrapperForBuildScripts": false, | ||
40 | } | ||
37 | }), | 41 | }), |
38 | } | 42 | } |
39 | } | 43 | } |
@@ -49,7 +53,17 @@ impl<'a> Project<'a> { | |||
49 | } | 53 | } |
50 | 54 | ||
51 | pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { | 55 | pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { |
52 | self.config = config; | 56 | fn merge(dst: &mut serde_json::Value, src: serde_json::Value) { |
57 | match (dst, src) { | ||
58 | (Value::Object(dst), Value::Object(src)) => { | ||
59 | for (k, v) in src { | ||
60 | merge(dst.entry(k).or_insert(v.clone()), v) | ||
61 | } | ||
62 | } | ||
63 | (dst, src) => *dst = src, | ||
64 | } | ||
65 | } | ||
66 | merge(&mut self.config, config); | ||
53 | self | 67 | self |
54 | } | 68 | } |
55 | 69 | ||
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 871c65add..e0ee35b4e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -39,6 +39,12 @@ List of features to activate. | |||
39 | -- | 39 | -- |
40 | Run build scripts (`build.rs`) for more precise code analysis. | 40 | Run build scripts (`build.rs`) for more precise code analysis. |
41 | -- | 41 | -- |
42 | [[rust-analyzer.cargo.useRustcWrapperForBuildScripts]]rust-analyzer.cargo.useRustcWrapperForBuildScripts (default: `true`):: | ||
43 | + | ||
44 | -- | ||
45 | Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to | ||
46 | avoid compiling unnecessary things. | ||
47 | -- | ||
42 | [[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: | 48 | [[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: |
43 | + | 49 | + |
44 | -- | 50 | -- |
diff --git a/editors/code/package.json b/editors/code/package.json index d263610f5..06ed62d8d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -434,6 +434,11 @@ | |||
434 | "default": true, | 434 | "default": true, |
435 | "type": "boolean" | 435 | "type": "boolean" |
436 | }, | 436 | }, |
437 | "rust-analyzer.cargo.useRustcWrapperForBuildScripts": { | ||
438 | "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid compiling unnecessary things.", | ||
439 | "default": true, | ||
440 | "type": "boolean" | ||
441 | }, | ||
437 | "rust-analyzer.cargo.noDefaultFeatures": { | 442 | "rust-analyzer.cargo.noDefaultFeatures": { |
438 | "markdownDescription": "Do not activate the `default` feature.", | 443 | "markdownDescription": "Do not activate the `default` feature.", |
439 | "default": false, | 444 | "default": false, |