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

Commit 0f39a88

Browse files
committed
Check nothing has changed between receiving a mutating action and returning to the client
1 parent a866127 commit 0f39a88

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

src/actions/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ pub struct InitActionContext {
124124
// Keep a record of builds/post-build tasks currently in flight so that
125125
// mutating actions can block until the data is ready.
126126
active_build_count: Arc<AtomicUsize>,
127+
// Set to true when a potentially mutating request is received. Set to false
128+
// if a change arrives. We can thus tell if the RLS has been quiescent while
129+
// waiting to mutate the client state.
130+
pub quiescent: Arc<AtomicBool>,
127131

128132
prev_changes: Arc<Mutex<HashMap<PathBuf, u64>>>,
129133

@@ -172,8 +176,9 @@ impl InitActionContext {
172176
current_project,
173177
previous_build_results: Arc::new(Mutex::new(HashMap::new())),
174178
build_queue,
175-
prev_changes: Arc::new(Mutex::new(HashMap::new())),
176179
active_build_count: Arc::new(AtomicUsize::new(0)),
180+
quiescent: Arc::new(AtomicBool::new(false)),
181+
prev_changes: Arc::new(Mutex::new(HashMap::new())),
177182
client_capabilities: Arc::new(client_capabilities),
178183
shut_down: Arc::new(AtomicBool::new(false)),
179184
}

src/actions/notifications.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use serde::Deserialize;
1818
use serde::de::Error;
1919
use serde_json;
2020
use Span;
21+
use std::sync::atomic::Ordering;
2122

2223
use build::*;
2324
use lsp_data::*;
@@ -87,6 +88,7 @@ impl BlockingNotificationAction for DidChangeTextDocument {
8788
}
8889

8990
let ctx = ctx.inited();
91+
ctx.quiescent.store(false, Ordering::SeqCst);
9092
let file_path = parse_file_path!(&params.text_document.uri, "on_change")?;
9193
let version_num = params.text_document.version.unwrap();
9294

src/actions/requests.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub use lsp_data::FindImpls;
5151

5252
use std::collections::HashMap;
5353
use std::path::Path;
54+
use std::sync::atomic::Ordering;
55+
5456

5557
/// Represent the result of a deglob action for a single wildcard import.
5658
///
@@ -380,6 +382,7 @@ impl RequestAction for Rename {
380382
ctx: InitActionContext,
381383
params: Self::Params,
382384
) -> Result<Self::Response, ResponseError> {
385+
ctx.quiescent.store(true, Ordering::SeqCst);
383386
// We're going to mutate based on our data so we should block until the
384387
// data is ready.
385388
ctx.block_on_build();
@@ -424,6 +427,10 @@ impl RequestAction for Rename {
424427
});
425428
}
426429

430+
if !ctx.quiescent.load(Ordering::SeqCst) {
431+
return Self::fallback_response();
432+
}
433+
427434
Ok(WorkspaceEdit { changes: Some(edits), document_changes: None })
428435
}
429436
}
@@ -464,15 +471,15 @@ impl RequestAction for ExecuteCommand {
464471

465472
/// Currently supports "rls.applySuggestion", "rls.deglobImports".
466473
fn handle(
467-
_: InitActionContext,
474+
ctx: InitActionContext,
468475
params: ExecuteCommandParams,
469476
) -> Result<Self::Response, ResponseError> {
470477
match &*params.command {
471478
"rls.applySuggestion" => {
472479
apply_suggestion(&params.arguments).map(ExecuteCommandResponse::ApplyEdit)
473480
}
474481
"rls.deglobImports" => {
475-
apply_deglobs(params.arguments).map(ExecuteCommandResponse::ApplyEdit)
482+
apply_deglobs(params.arguments, &ctx).map(ExecuteCommandResponse::ApplyEdit)
476483
}
477484
c => {
478485
debug!("Unknown command: {}", c);
@@ -497,12 +504,13 @@ fn apply_suggestion(
497504
})
498505
}
499506

500-
fn apply_deglobs(args: Vec<serde_json::Value>) -> Result<ApplyWorkspaceEditParams, ResponseError> {
507+
fn apply_deglobs(args: Vec<serde_json::Value>, ctx: &InitActionContext) -> Result<ApplyWorkspaceEditParams, ResponseError> {
508+
ctx.quiescent.store(true, Ordering::SeqCst);
501509
let deglob_results: Vec<DeglobResult> = args.into_iter()
502510
.map(|res| serde_json::from_value(res).expect("Bad argument"))
503511
.collect();
504512

505-
trace!("apply_deglob {:?}", deglob_results);
513+
trace!("apply_deglobs {:?}", deglob_results);
506514

507515
assert!(!deglob_results.is_empty());
508516
let uri = deglob_results[0].location.uri.clone();
@@ -526,6 +534,9 @@ fn apply_deglobs(args: Vec<serde_json::Value>) -> Result<ApplyWorkspaceEditParam
526534
document_changes: None,
527535
};
528536

537+
if !ctx.quiescent.load(Ordering::SeqCst) {
538+
return Err(ResponseError::Empty);
539+
}
529540
Ok(ApplyWorkspaceEditParams { edit })
530541
}
531542

@@ -714,6 +725,7 @@ fn reformat(
714725
opts: &FormattingOptions,
715726
ctx: &InitActionContext,
716727
) -> Result<[TextEdit; 1], ResponseError> {
728+
ctx.quiescent.store(true, Ordering::SeqCst);
717729
trace!(
718730
"Reformat: {:?} {:?} {} {}",
719731
doc,
@@ -771,6 +783,13 @@ fn reformat(
771783
// echos back the change to us.
772784
let text = String::from_utf8(buf).unwrap();
773785

786+
if !ctx.quiescent.load(Ordering::SeqCst) {
787+
return Err(ResponseError::Message(
788+
ErrorCode::InternalError,
789+
"Reformat failed to complete successfully".into(),
790+
))
791+
}
792+
774793
// If Rustfmt returns range of text that changed,
775794
// we will be able to pass only range of changed text to the client.
776795
Ok([

0 commit comments

Comments
 (0)