aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-04-12 09:04:36 +0100
committerAleksey Kladov <[email protected]>2021-04-12 13:29:31 +0100
commit186c5c47cbfde4ae9d81dc67450c958cb6aece2c (patch)
tree05141f6e9aa7d20c4ce2a8b59324a3d82d43f895
parent7be06139b632ee615fc18af04dd67947e2c794b2 (diff)
feat: avoid checking the whole project during initial loading
-rw-r--r--crates/project_model/src/build_data.rs236
-rw-r--r--crates/rust-analyzer/src/benchmarks.rs7
-rw-r--r--crates/rust-analyzer/src/bin/main.rs15
-rw-r--r--crates/rust-analyzer/src/bin/rustc_wrapper.rs46
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs3
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs10
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs9
-rw-r--r--crates/rust-analyzer/src/config.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop.rs3
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/main.rs2
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs20
-rw-r--r--docs/user/generated_config.adoc6
-rw-r--r--editors/code/package.json5
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
59impl Eq for BuildDataConfig {} 59impl Eq for BuildDataConfig {}
60 60
61#[derive(Debug, Default)] 61#[derive(Debug)]
62pub struct BuildDataCollector { 62pub struct BuildDataCollector {
63 wrap_rustc: bool,
63 configs: FxHashMap<AbsPathBuf, BuildDataConfig>, 64 configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
64} 65}
65 66
66impl BuildDataCollector { 67impl 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
123fn collect_from_workspace( 127impl 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
4mod flags; 4mod flags;
5mod logger; 5mod logger;
6mod rustc_wrapper;
6 7
7use std::{convert::TryFrom, env, fs, path::Path, process}; 8use std::{convert::TryFrom, env, fs, path::Path, process};
8 9
@@ -26,6 +27,20 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
26static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 27static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
27 28
28fn main() { 29fn 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
7use std::{
8 ffi::OsString,
9 io,
10 process::{Command, Stdio},
11};
12
13/// ExitCode/ExitStatus are impossible to create :(.
14pub(crate) struct ExitCode(pub(crate) Option<i32>);
15
16pub(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
38fn 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
16pub struct LoadCargoConfig { 16pub 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};
9pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { 9pub 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]
528fn out_dirs_check() { 528fn 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--
40Run build scripts (`build.rs`) for more precise code analysis. 40Run build scripts (`build.rs`) for more precise code analysis.
41-- 41--
42[[rust-analyzer.cargo.useRustcWrapperForBuildScripts]]rust-analyzer.cargo.useRustcWrapperForBuildScripts (default: `true`)::
43+
44--
45Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
46avoid 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,