From 186c5c47cbfde4ae9d81dc67450c958cb6aece2c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 12 Apr 2021 11:04:36 +0300 Subject: feat: avoid checking the whole project during initial loading --- crates/rust-analyzer/src/benchmarks.rs | 7 +++- crates/rust-analyzer/src/bin/main.rs | 15 +++++++ crates/rust-analyzer/src/bin/rustc_wrapper.rs | 46 ++++++++++++++++++++++ crates/rust-analyzer/src/cli/analysis_stats.rs | 1 + crates/rust-analyzer/src/cli/diagnostics.rs | 3 +- crates/rust-analyzer/src/cli/load_cargo.rs | 10 +++-- crates/rust-analyzer/src/cli/ssr.rs | 9 +++-- crates/rust-analyzer/src/config.rs | 6 +++ crates/rust-analyzer/src/main_loop.rs | 3 +- crates/rust-analyzer/tests/rust-analyzer/main.rs | 2 +- .../rust-analyzer/tests/rust-analyzer/support.rs | 20 ++++++++-- 11 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 crates/rust-analyzer/src/bin/rustc_wrapper.rs (limited to 'crates/rust-analyzer') 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() { let file = "./crates/ide_db/src/apply_change.rs"; let cargo_config = Default::default(); - let load_cargo_config = - LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: false }; + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + wrap_rustc: false, + with_proc_macro: false, + }; let (mut host, vfs, _proc_macro) = { 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 @@ //! Based on cli flags, either spawns an LSP server, or runs a batch analysis mod flags; mod logger; +mod rustc_wrapper; use std::{convert::TryFrom, env, fs, path::Path, process}; @@ -26,6 +27,20 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; fn main() { + if std::env::var("RA_RUSTC_WRAPPER").is_ok() { + let mut args = std::env::args_os(); + let _me = args.next().unwrap(); + let rustc = args.next().unwrap(); + let code = match rustc_wrapper::run_rustc_skipping_cargo_checking(rustc, args.collect()) { + Ok(rustc_wrapper::ExitCode(code)) => code.unwrap_or(102), + Err(err) => { + eprintln!("{}", err); + 101 + } + }; + process::exit(code); + } + if let Err(err) = try_main() { log::error!("Unexpected error: {}", err); 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 @@ +//! We setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself during the +//! initial `cargo check`. That way, we avoid checking the actual project, and +//! only build proc macros and build.rs. +//! +//! Code taken from IntelliJ :0) +//! https://github.com/intellij-rust/intellij-rust/blob/master/native-helper/src/main.rs +use std::{ + ffi::OsString, + io, + process::{Command, Stdio}, +}; + +/// ExitCode/ExitStatus are impossible to create :(. +pub(crate) struct ExitCode(pub(crate) Option); + +pub(crate) fn run_rustc_skipping_cargo_checking( + rustc_executable: OsString, + args: Vec, +) -> io::Result { + let is_cargo_check = args.iter().any(|arg| { + let arg = arg.to_string_lossy(); + // `cargo check` invokes `rustc` with `--emit=metadata` argument. + // + // https://doc.rust-lang.org/rustc/command-line-arguments.html#--emit-specifies-the-types-of-output-files-to-generate + // link — Generates the crates specified by --crate-type. The default + // output filenames depend on the crate type and platform. This + // is the default if --emit is not specified. + // metadata — Generates a file containing metadata about the crate. + // The default output filename is CRATE_NAME.rmeta. + arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link") + }); + if is_cargo_check { + return Ok(ExitCode(Some(0))); + } + run_rustc(rustc_executable, args) +} + +fn run_rustc(rustc_executable: OsString, args: Vec) -> io::Result { + let mut child = Command::new(rustc_executable) + .args(args) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn()?; + Ok(ExitCode(child.wait()?.code())) +} 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 { cargo_config.no_sysroot = self.no_sysroot; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: self.load_output_dirs, + wrap_rustc: false, with_proc_macro: self.with_proc_macro, }; 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( with_proc_macro: bool, ) -> Result<()> { let cargo_config = Default::default(); - let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check, with_proc_macro }; + let load_cargo_config = + LoadCargoConfig { load_out_dirs_from_check, with_proc_macro, wrap_rustc: false }; let (host, _vfs, _proc_macro) = load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; 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}; pub struct LoadCargoConfig { pub load_out_dirs_from_check: bool, + pub wrap_rustc: bool, pub with_proc_macro: bool, } @@ -52,7 +53,7 @@ pub fn load_workspace( }; let build_data = if config.load_out_dirs_from_check { - let mut collector = BuildDataCollector::default(); + let mut collector = BuildDataCollector::new(config.wrap_rustc); ws.collect_build_data_configs(&mut collector); Some(collector.collect(progress)?) } else { @@ -136,8 +137,11 @@ mod tests { fn test_loading_rust_analyzer() -> Result<()> { let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); let cargo_config = Default::default(); - let load_cargo_config = - LoadCargoConfig { load_out_dirs_from_check: false, with_proc_macro: false }; + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: false, + wrap_rustc: false, + with_proc_macro: false, + }; let (host, _vfs, _proc_macro) = load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; 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}; pub fn apply_ssr_rules(rules: Vec) -> Result<()> { use ide_db::base_db::SourceDatabaseExt; let cargo_config = Default::default(); - let load_cargo_config = - LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: true }; + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + wrap_rustc: false, + with_proc_macro: true, + }; let (host, vfs, _proc_macro) = load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; let db = host.raw_database(); @@ -37,7 +40,7 @@ pub fn search_for_patterns(patterns: Vec, debug_snippet: Option bool { self.data.cargo_runBuildScripts || self.data.procMacro_enable } + pub fn wrap_rustc(&self) -> bool { + self.data.cargo_useRustcWrapperForBuildScripts + } pub fn cargo(&self) -> CargoConfig { let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { 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 { let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); if self.config.run_build_scripts() && workspaces_updated { - let mut collector = BuildDataCollector::default(); + let mut collector = + BuildDataCollector::new(self.config.wrap_rustc()); for ws in self.workspaces.iter() { ws.collect_build_data_configs(&mut collector); } 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\" #[test] fn out_dirs_check() { if skip_slow_tests() { - return; + // return; } 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> { tmp_dir: None, roots: vec![], config: serde_json::json!({ - // Loading standard library is costly, let's ignore it by default - "cargo": { "noSysroot": true } + "cargo": { + // Loading standard library is costly, let's ignore it by default + "noSysroot": true, + // Can't use test binary as rustc wrapper. + "useRustcWrapperForBuildScripts": false, + } }), } } @@ -49,7 +53,17 @@ impl<'a> Project<'a> { } pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { - self.config = config; + fn merge(dst: &mut serde_json::Value, src: serde_json::Value) { + match (dst, src) { + (Value::Object(dst), Value::Object(src)) => { + for (k, v) in src { + merge(dst.entry(k).or_insert(v.clone()), v) + } + } + (dst, src) => *dst = src, + } + } + merge(&mut self.config, config); self } -- cgit v1.2.3