Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 750be58

Browse files
authored
Merge pull request #1119 from Xanewok/crate-input-files
Collect input files for crates
2 parents 051b96b + e2c8c28 commit 750be58

File tree

9 files changed

+238
-39
lines changed

9 files changed

+238
-39
lines changed

src/actions/mod.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::lsp_data::*;
3232
use crate::project_model::{ProjectModel, RacerFallbackModel, RacerProjectModel};
3333
use crate::server::Output;
3434

35-
use std::collections::HashMap;
35+
use std::collections::{HashMap, HashSet};
3636
use std::io;
3737
use std::path::{Path, PathBuf};
3838
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@@ -143,6 +143,7 @@ pub struct InitActionContext {
143143

144144
previous_build_results: Arc<Mutex<BuildResults>>,
145145
build_queue: BuildQueue,
146+
file_to_crates: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
146147
// Keep a record of builds/post-build tasks currently in flight so that
147148
// mutating actions can block until the data is ready.
148149
active_build_count: Arc<AtomicUsize>,
@@ -212,6 +213,7 @@ impl InitActionContext {
212213
project_model: Arc::default(),
213214
previous_build_results: Arc::default(),
214215
build_queue,
216+
file_to_crates: Arc::default(),
215217
active_build_count: Arc::new(AtomicUsize::new(0)),
216218
shown_cargo_error: Arc::new(AtomicBool::new(false)),
217219
quiescent: Arc::new(AtomicBool::new(false)),
@@ -288,6 +290,22 @@ impl InitActionContext {
288290
FmtConfig::from(&self.current_project)
289291
}
290292

293+
fn file_edition(&self, file: PathBuf) -> Option<Edition> {
294+
let files_to_crates = self.file_to_crates.lock().unwrap();
295+
296+
let editions: HashSet<_> = files_to_crates
297+
.get(&file)?
298+
.iter()
299+
.map(|c| c.edition)
300+
.collect();
301+
302+
let mut iter = editions.into_iter();
303+
match (iter.next(), iter.next()) {
304+
(ret @ Some(_), None) => ret,
305+
_ => None,
306+
}
307+
}
308+
291309
fn init<O: Output>(&self, init_options: &InitializationOptions, out: &O) {
292310
let current_project = self.current_project.clone();
293311
let config = self.config.clone();
@@ -318,6 +336,7 @@ impl InitActionContext {
318336
analysis: self.analysis.clone(),
319337
analysis_queue: self.analysis_queue.clone(),
320338
previous_build_results: self.previous_build_results.clone(),
339+
file_to_crates: self.file_to_crates.clone(),
321340
project_path: project_path.to_owned(),
322341
show_warnings: config.show_warnings,
323342
related_information_support: self.client_capabilities.related_information_support,

src/actions/post_build.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@
1313
#![allow(missing_docs)]
1414

1515
use std::collections::hash_map::DefaultHasher;
16-
use std::collections::HashMap;
16+
use std::collections::{HashMap, HashSet};
1717
use std::hash::{Hash, Hasher};
1818
use std::panic::RefUnwindSafe;
1919
use std::path::{Path, PathBuf};
2020
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
2121
use std::sync::{Arc, Mutex};
2222
use std::thread::{self, Thread};
23+
use std::ops::Deref;
2324

2425
use crate::actions::diagnostics::{parse_diagnostics, Diagnostic, ParsedDiagnostics, Suggestion};
2526
use crate::actions::progress::DiagnosticsNotifier;
26-
use crate::build::BuildResult;
27+
use crate::build::{BuildResult, Crate};
2728
use crate::concurrency::JobToken;
2829
use crate::lsp_data::{Range, PublishDiagnosticsParams};
2930

@@ -41,6 +42,7 @@ pub struct PostBuildHandler {
4142
pub analysis: Arc<AnalysisHost>,
4243
pub analysis_queue: Arc<AnalysisQueue>,
4344
pub previous_build_results: Arc<Mutex<BuildResults>>,
45+
pub file_to_crates: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
4446
pub project_path: PathBuf,
4547
pub show_warnings: bool,
4648
pub use_black_list: bool,
@@ -55,14 +57,20 @@ pub struct PostBuildHandler {
5557
impl PostBuildHandler {
5658
pub fn handle(self, result: BuildResult) {
5759
match result {
58-
BuildResult::Success(cwd, messages, new_analysis, _) => {
60+
BuildResult::Success(cwd, messages, new_analysis, input_files, _) => {
5961
trace!("build - Success");
6062
self.notifier.notify_begin_diagnostics();
6163

6264
// Emit appropriate diagnostics using the ones from build.
6365
self.handle_messages(&cwd, &messages);
6466
let analysis_queue = self.analysis_queue.clone();
6567

68+
{
69+
let mut files_to_crates = self.file_to_crates.lock().unwrap();
70+
*files_to_crates = input_files;
71+
trace!("Files to crates: {:#?}", files_to_crates.deref());
72+
}
73+
6674
let job = Job::new(self, new_analysis, cwd);
6775
analysis_queue.enqueue(job);
6876
}

src/actions/requests.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
1313
use crate::actions::InitActionContext;
1414
use itertools::Itertools;
15-
use log::{debug, trace};
15+
use log::{debug, trace, warn};
1616
use racer;
1717
use rls_data as data;
1818
use rls_span as span;
1919
use rls_vfs::FileContents;
20-
use rustfmt_nightly::{FileLines, FileName, Range as RustfmtRange};
20+
use rustfmt_nightly::{Edition as RustfmtEdition, FileLines, FileName, Range as RustfmtRange};
2121
use serde_derive::{Deserialize, Serialize};
2222
use serde_json;
2323
use url::Url;
@@ -26,6 +26,7 @@ use crate::actions::hover;
2626
use crate::actions::run::collect_run_actions;
2727
use crate::actions::work_pool;
2828
use crate::actions::work_pool::WorkDescription;
29+
use crate::build::Edition;
2930
use crate::lsp_data;
3031
use crate::lsp_data::*;
3132
use crate::server;
@@ -754,6 +755,26 @@ fn reformat(
754755
if !config.was_set().tab_spaces() {
755756
config.set().tab_spaces(opts.tab_size as usize);
756757
}
758+
if !config.was_set().edition() {
759+
match ctx.file_edition(path.clone()) {
760+
Some(edition) => {
761+
let edition = match edition {
762+
Edition::Edition2015 => RustfmtEdition::Edition2015,
763+
Edition::Edition2018 => RustfmtEdition::Edition2018,
764+
};
765+
config.set().edition(edition);
766+
trace!("Detected edition {:?} for file `{}`", edition, path.display());
767+
},
768+
None => {
769+
warn!("Reformat failed: ambiguous edition for `{}`", path.display());
770+
771+
return Err(ResponseError::Message(
772+
ErrorCode::InternalError,
773+
"Reformat failed to complete successfully".into(),
774+
));
775+
}
776+
}
777+
}
757778

758779
if let Some(r) = selection {
759780
let range_of_rls = ls_util::range_to_rls(r).one_indexed();

src/build/cargo.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use serde_json;
2424
use crate::actions::progress::ProgressUpdate;
2525
use crate::build::cargo_plan::CargoPlan;
2626
use crate::build::environment::{self, Environment, EnvironmentLock};
27-
use crate::build::plan::BuildPlan;
27+
use crate::build::plan::{BuildPlan, Crate};
2828
use crate::build::{BufWriter, BuildResult, CompilationContext, Internals, PackageArg};
2929
use crate::config::Config;
3030
use crate::lsp_data::{Position, Range};
@@ -58,6 +58,8 @@ pub(super) fn cargo(
5858
let diagnostics_clone = diagnostics.clone();
5959
let analysis = Arc::new(Mutex::new(vec![]));
6060
let analysis_clone = analysis.clone();
61+
let input_files = Arc::new(Mutex::new(HashMap::new()));
62+
let input_files_clone = input_files.clone();
6163
let out = Arc::new(Mutex::new(vec![]));
6264
let out_clone = out.clone();
6365

@@ -74,6 +76,7 @@ pub(super) fn cargo(
7476
env_lock,
7577
diagnostics,
7678
analysis,
79+
input_files,
7780
out,
7881
progress_sender,
7982
)
@@ -93,7 +96,11 @@ pub(super) fn cargo(
9396
.unwrap()
9497
.into_inner()
9598
.unwrap();
96-
BuildResult::Success(cwd.clone(), diagnostics, analysis, true)
99+
let input_files = Arc::try_unwrap(input_files_clone)
100+
.unwrap()
101+
.into_inner()
102+
.unwrap();
103+
BuildResult::Success(cwd.clone(), diagnostics, analysis, input_files, true)
97104
}
98105
Err(error) => {
99106
let stdout = String::from_utf8(out_clone.lock().unwrap().to_owned()).unwrap();
@@ -123,6 +130,7 @@ fn run_cargo(
123130
env_lock: Arc<EnvironmentLock>,
124131
compiler_messages: Arc<Mutex<Vec<String>>>,
125132
analysis: Arc<Mutex<Vec<Analysis>>>,
133+
input_files: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
126134
out: Arc<Mutex<Vec<u8>>>,
127135
progress_sender: Sender<ProgressUpdate>,
128136
) -> Result<PathBuf, failure::Error> {
@@ -163,6 +171,7 @@ fn run_cargo(
163171
vfs,
164172
compiler_messages,
165173
analysis,
174+
input_files,
166175
progress_sender,
167176
inner_lock,
168177
restore_env,
@@ -180,6 +189,7 @@ fn run_cargo_ws(
180189
vfs: Arc<Vfs>,
181190
compiler_messages: Arc<Mutex<Vec<String>>>,
182191
analysis: Arc<Mutex<Vec<Analysis>>>,
192+
input_files: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
183193
progress_sender: Sender<ProgressUpdate>,
184194
inner_lock: environment::InnerLock,
185195
mut restore_env: Environment<'_>,
@@ -275,6 +285,7 @@ fn run_cargo_ws(
275285
vfs,
276286
compiler_messages,
277287
analysis,
288+
input_files,
278289
progress_sender,
279290
reached_primary.clone(),
280291
);
@@ -321,6 +332,7 @@ struct RlsExecutor {
321332
/// Packages which are directly a member of the workspace, for which
322333
/// analysis and diagnostics will be provided
323334
member_packages: Mutex<HashSet<PackageId>>,
335+
input_files: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
324336
/// JSON compiler messages emitted for each primary compiled crate
325337
compiler_messages: Arc<Mutex<Vec<String>>>,
326338
progress_sender: Mutex<Sender<ProgressUpdate>>,
@@ -341,6 +353,7 @@ impl RlsExecutor {
341353
vfs: Arc<Vfs>,
342354
compiler_messages: Arc<Mutex<Vec<String>>>,
343355
analysis: Arc<Mutex<Vec<Analysis>>>,
356+
input_files: Arc<Mutex<HashMap<PathBuf, HashSet<Crate>>>>,
344357
progress_sender: Sender<ProgressUpdate>,
345358
reached_primary: Arc<AtomicBool>,
346359
) -> RlsExecutor {
@@ -352,6 +365,7 @@ impl RlsExecutor {
352365
env_lock,
353366
vfs,
354367
analysis,
368+
input_files,
355369
member_packages: Mutex::new(member_packages),
356370
compiler_messages,
357371
progress_sender: Mutex::new(progress_sender),
@@ -559,18 +573,32 @@ impl Executor for RlsExecutor {
559573
cx.build_dir.clone().unwrap()
560574
};
561575

562-
if let BuildResult::Success(_, mut messages, mut analysis, success) = super::rustc::rustc(
563-
&self.vfs,
564-
&args,
565-
&envs,
566-
cargo_cmd.get_cwd(),
567-
&build_dir,
568-
Arc::clone(&self.config),
569-
&self.env_lock.as_facade(),
570-
) {
576+
if let BuildResult::Success(_, mut messages, mut analysis, input_files, success) =
577+
super::rustc::rustc(
578+
&self.vfs,
579+
&args,
580+
&envs,
581+
cargo_cmd.get_cwd(),
582+
&build_dir,
583+
Arc::clone(&self.config),
584+
&self.env_lock.as_facade(),
585+
) {
571586
self.compiler_messages.lock().unwrap().append(&mut messages);
572587
self.analysis.lock().unwrap().append(&mut analysis);
573588

589+
// Cache calculated input files for a given rustc invocation
590+
{
591+
let mut cx = self.compilation_cx.lock().unwrap();
592+
let plan = cx.build_plan.as_cargo_mut().unwrap();
593+
let input_files = input_files.keys().cloned().collect();
594+
plan.cache_input_files(id, target, mode, input_files, cargo_cmd.get_cwd());
595+
}
596+
597+
let mut self_input_files = self.input_files.lock().unwrap();
598+
for (file, inputs) in input_files {
599+
self_input_files.entry(file).or_default().extend(inputs);
600+
}
601+
574602
if !success {
575603
return Err(format_err!("Build error"));
576604
}

src/build/cargo_plan.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use url::Url;
3939

4040
use crate::build::PackageArg;
4141
use crate::build::plan::{BuildKey, BuildGraph, JobQueue, WorkStatus};
42+
use crate::build::rustc::src_path;
4243
use crate::lsp_data::parse_file_path;
4344

4445
/// Main key type by which `Unit`s will be distinguished in the build plan.
@@ -58,6 +59,9 @@ crate struct CargoPlan {
5859
crate rev_dep_graph: HashMap<UnitKey, HashSet<UnitKey>>,
5960
/// Cached compiler calls used when creating a compiler call queue.
6061
crate compiler_jobs: HashMap<UnitKey, ProcessBuilder>,
62+
/// Calculated input files that unit depend on.
63+
crate input_files: HashMap<UnitKey, Vec<PathBuf>>,
64+
crate file_key_mapping: HashMap<PathBuf, HashSet<UnitKey>>,
6165
// An object for finding the package which a file belongs to and this inferring
6266
// a package argument.
6367
package_map: Option<PackageMap>,
@@ -101,6 +105,40 @@ impl CargoPlan {
101105
self.compiler_jobs.insert(unit_key, cmd.clone());
102106
}
103107

108+
crate fn cache_input_files(
109+
&mut self,
110+
id: &PackageId,
111+
target: &Target,
112+
mode: CompileMode,
113+
input_files: Vec<PathBuf>,
114+
cwd: Option<&Path>,
115+
) {
116+
let input_files: Vec<_> = input_files
117+
.iter()
118+
.filter_map(|file| src_path(cwd, file))
119+
.filter_map(|file| match std::fs::canonicalize(&file) {
120+
Ok(file) => Some(file),
121+
Err(err) => {
122+
error!("Couldn't canonicalize `{}`: {}", file.display(), err);
123+
None
124+
}
125+
})
126+
.collect();
127+
128+
let unit_key = (id.clone(), target.clone(), mode);
129+
trace!("Caching these files: {:#?} for {:?} key", &input_files, &unit_key);
130+
131+
// Create reverse file -> unit mapping (to be used for dirty unit calculation)
132+
for file in &input_files {
133+
self.file_key_mapping
134+
.entry(file.to_path_buf())
135+
.or_default()
136+
.insert(unit_key.clone());
137+
}
138+
139+
self.input_files.insert(unit_key, input_files);
140+
}
141+
104142
/// Emplace a given `Unit`, along with its `Unit` dependencies (recursively)
105143
/// into the dependency graph as long as the passed `Unit` isn't filtered
106144
/// out by the `filter` closure.

src/build/external.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use std::process::{Command, Stdio};
3131

3232
use crate::build::BuildResult;
3333
use crate::build::plan::{BuildKey, BuildGraph, JobQueue, WorkStatus};
34+
use crate::build::rustc::src_path;
3435

3536
use cargo::util::{process, ProcessBuilder};
3637
use log::trace;
@@ -96,7 +97,7 @@ pub(super) fn build_with_external_cmd<S: AsRef<str>>(
9697
};
9798

9899
let plan = plan_from_analysis(&analyses, &build_dir);
99-
(BuildResult::Success(build_dir, vec![], analyses, false), plan)
100+
(BuildResult::Success(build_dir, vec![], analyses, HashMap::default(), false), plan)
100101
}
101102

102103
/// Reads and deserializes given save-analysis JSON files into corresponding
@@ -453,16 +454,6 @@ fn guess_rustc_src_path(build_dir: &Path, cmd: &ProcessBuilder) -> Option<PathBu
453454
src_path(cwd, file)
454455
}
455456

456-
fn src_path(cwd: Option<&Path>, path: impl AsRef<Path>) -> Option<PathBuf> {
457-
let path = path.as_ref();
458-
459-
Some(match (cwd, path.is_absolute()) {
460-
(_, true) => path.to_owned(),
461-
(Some(cwd), _) => cwd.join(path),
462-
(None, _) => std::env::current_dir().ok()?.join(path)
463-
})
464-
}
465-
466457
#[cfg(test)]
467458
mod tests {
468459
use super::*;

0 commit comments

Comments
 (0)