Skip to content

Commit 6c36c2c

Browse files
committed
fix crash a flycheck is canceled
1 parent 747d97f commit 6c36c2c

File tree

1 file changed

+37
-24
lines changed

1 file changed

+37
-24
lines changed

crates/flycheck/src/lib.rs

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
66

77
use std::{
8+
cell::OnceCell,
89
fmt, io,
910
process::{ChildStderr, ChildStdout, Command, Stdio},
1011
time::Duration,
1112
};
1213

1314
use command_group::{CommandGroup, GroupChild};
1415
use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
15-
use paths::AbsPathBuf;
16+
use paths::{AbsPath, AbsPathBuf};
1617
use rustc_hash::FxHashMap;
1718
use serde::Deserialize;
1819
use stdx::process::streaming_output;
@@ -173,6 +174,7 @@ struct FlycheckActor {
173174
/// Either the workspace root of the workspace we are flychecking,
174175
/// or the project root of the project.
175176
root: AbsPathBuf,
177+
state: OnceCell<FlycheckState>,
176178
/// CargoHandle exists to wrap around the communication needed to be able to
177179
/// run `cargo check` without blocking. Currently the Rust standard library
178180
/// doesn't provide a way to read sub-process output without blocking, so we
@@ -181,6 +183,11 @@ struct FlycheckActor {
181183
cargo_handle: Option<CargoHandle>,
182184
}
183185

186+
#[derive(Debug)]
187+
struct FlycheckState {
188+
command: Command,
189+
}
190+
184191
enum Event {
185192
RequestStateChange(StateChange),
186193
CheckEvent(Option<CargoMessage>),
@@ -194,7 +201,14 @@ impl FlycheckActor {
194201
workspace_root: AbsPathBuf,
195202
) -> FlycheckActor {
196203
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
197-
FlycheckActor { id, sender, config, root: workspace_root, cargo_handle: None }
204+
FlycheckActor {
205+
id,
206+
sender,
207+
config,
208+
root: workspace_root,
209+
state: OnceCell::new(),
210+
cargo_handle: None,
211+
}
198212
}
199213

200214
fn report_progress(&self, progress: Progress) {
@@ -230,15 +244,25 @@ impl FlycheckActor {
230244
}
231245
}
232246

233-
let command = self.check_command(saved_file);
234-
let command_string = format!("{:?}", command);
247+
let command = self.make_check_command(saved_file.as_deref());
248+
let state = FlycheckState { command };
249+
match self.state.get_mut() {
250+
Some(old_state) => *old_state = state,
251+
None => {
252+
self.state.set(state).expect(
253+
"Unreachable code, as the state of the OnceCell was checked.",
254+
);
255+
}
256+
};
257+
258+
tracing::debug!(state = ?self.config, "restarting flycheck");
235259

236-
tracing::debug!(?command, "restarting flycheck");
260+
let command = self.state.get_mut().unwrap();
237261

238-
match CargoHandle::spawn(command) {
262+
match CargoHandle::spawn(&mut command.command) {
239263
Ok(cargo_handle) => {
240264
tracing::debug!(
241-
command = ?command_string,
265+
command = ?self.state,
242266
"did restart flycheck"
243267
);
244268
self.cargo_handle = Some(cargo_handle);
@@ -247,7 +271,7 @@ impl FlycheckActor {
247271
Err(error) => {
248272
self.report_progress(Progress::DidFailToRestart(format!(
249273
"Failed to run the following command: {:?} error={}",
250-
command_string, error
274+
&self.state, error
251275
)));
252276
}
253277
}
@@ -261,7 +285,7 @@ impl FlycheckActor {
261285
if res.is_err() {
262286
tracing::error!(
263287
"Flycheck failed to run the following command: {:?}",
264-
self.check_command(None)
288+
self.config
265289
);
266290
}
267291
self.report_progress(Progress::DidFinish(res));
@@ -297,13 +321,13 @@ impl FlycheckActor {
297321

298322
fn cancel_check_process(&mut self) {
299323
if let Some(cargo_handle) = self.cargo_handle.take() {
300-
tracing::debug!(command = ?self.check_command(None), "did cancel flycheck");
324+
tracing::debug!(command = ?self.config, "did cancel flycheck");
301325
cargo_handle.cancel();
302326
self.report_progress(Progress::DidCancel);
303327
}
304328
}
305329

306-
fn check_command(&self, saved_file: Option<AbsPathBuf>) -> Command {
330+
fn make_check_command(&self, saved_file: Option<&AbsPath>) -> Command {
307331
let (mut cmd, args) = match &self.config {
308332
FlycheckConfig::CargoCommand {
309333
command,
@@ -385,18 +409,7 @@ impl FlycheckActor {
385409
args[i] = saved_file.to_string();
386410
(cmd, args)
387411
}
388-
(None, Some(saved_file)) => {
389-
dbg!("no index, saved file included: {}", &saved_file);
390-
unreachable!()
391-
}
392-
(Some(i), None) => {
393-
dbg!("index, no saved file included: {}", &i);
394-
unreachable!()
395-
}
396-
(None, None) => {
397-
dbg!("No index or no saved file included");
398-
unreachable!()
399-
}
412+
_ => unreachable!("This is a broken invariant inside of rust-analyzer"),
400413
}
401414
} else {
402415
(cmd, args.clone())
@@ -433,7 +446,7 @@ struct CargoHandle {
433446
}
434447

435448
impl CargoHandle {
436-
fn spawn(mut command: Command) -> std::io::Result<CargoHandle> {
449+
fn spawn(command: &mut Command) -> std::io::Result<CargoHandle> {
437450
command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
438451
let mut child = command.group_spawn().map(JodGroupChild)?;
439452

0 commit comments

Comments
 (0)