aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-21 22:56:54 +0100
committerGitHub <[email protected]>2021-04-21 22:56:54 +0100
commit32491c09787fa3b386d067f0ce95d744c1480e0b (patch)
treeb34adf250a8f7b43b7bfc2ecda2fb1f8f5614917
parentb21701c5ee77f30d3d5f2e69980c6d03618390d6 (diff)
parentb3a7953cae4f14f74934cc64ba7ccf7b3eb6cd08 (diff)
Merge #8570
8570: Flycheck tries to parse both Cargo and Rustc messages. r=rickvanprim a=rickvanprim This change allows non-Cargo build systems to be used for Flycheck provided they call `rustc` with `--error-format=json` and emit those JSON messages to `stdout`. Co-authored-by: James Leitch <[email protected]>
-rw-r--r--Cargo.lock1
-rw-r--r--crates/flycheck/Cargo.toml1
-rw-r--r--crates/flycheck/src/lib.rs68
3 files changed, 48 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3a6df4f48..98141f5cd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -396,6 +396,7 @@ dependencies = [
396 "crossbeam-channel", 396 "crossbeam-channel",
397 "jod-thread", 397 "jod-thread",
398 "log", 398 "log",
399 "serde",
399 "serde_json", 400 "serde_json",
400 "stdx", 401 "stdx",
401 "toolchain", 402 "toolchain",
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 2a1a21b28..18b9ce7df 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
13crossbeam-channel = "0.5.0" 13crossbeam-channel = "0.5.0"
14log = "0.4.8" 14log = "0.4.8"
15cargo_metadata = "0.13" 15cargo_metadata = "0.13"
16serde = { version = "1.0.106", features = ["derive"] }
16serde_json = "1.0.48" 17serde_json = "1.0.48"
17jod-thread = "0.1.1" 18jod-thread = "0.1.1"
18 19
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index e2a59497a..1682d8bde 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -4,13 +4,14 @@
4 4
5use std::{ 5use std::{
6 fmt, 6 fmt,
7 io::{self, BufReader}, 7 io::{self, BufRead, BufReader},
8 path::PathBuf, 8 path::PathBuf,
9 process::{self, Command, Stdio}, 9 process::{self, Command, Stdio},
10 time::Duration, 10 time::Duration,
11}; 11};
12 12
13use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; 13use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
14use serde::Deserialize;
14use stdx::JodChild; 15use stdx::JodChild;
15 16
16pub use cargo_metadata::diagnostic::{ 17pub use cargo_metadata::diagnostic::{
@@ -128,7 +129,7 @@ struct FlycheckActor {
128 129
129enum Event { 130enum Event {
130 Restart(Restart), 131 Restart(Restart),
131 CheckEvent(Option<cargo_metadata::Message>), 132 CheckEvent(Option<CargoMessage>),
132} 133}
133 134
134impl FlycheckActor { 135impl FlycheckActor {
@@ -180,21 +181,16 @@ impl FlycheckActor {
180 self.progress(Progress::DidFinish(res)); 181 self.progress(Progress::DidFinish(res));
181 } 182 }
182 Event::CheckEvent(Some(message)) => match message { 183 Event::CheckEvent(Some(message)) => match message {
183 cargo_metadata::Message::CompilerArtifact(msg) => { 184 CargoMessage::CompilerArtifact(msg) => {
184 self.progress(Progress::DidCheckCrate(msg.target.name)); 185 self.progress(Progress::DidCheckCrate(msg.target.name));
185 } 186 }
186 187
187 cargo_metadata::Message::CompilerMessage(msg) => { 188 CargoMessage::Diagnostic(msg) => {
188 self.send(Message::AddDiagnostic { 189 self.send(Message::AddDiagnostic {
189 workspace_root: self.workspace_root.clone(), 190 workspace_root: self.workspace_root.clone(),
190 diagnostic: msg.message, 191 diagnostic: msg,
191 }); 192 });
192 } 193 }
193
194 cargo_metadata::Message::BuildScriptExecuted(_)
195 | cargo_metadata::Message::BuildFinished(_)
196 | cargo_metadata::Message::TextLine(_)
197 | _ => {}
198 }, 194 },
199 } 195 }
200 } 196 }
@@ -261,7 +257,7 @@ struct CargoHandle {
261 child: JodChild, 257 child: JodChild,
262 #[allow(unused)] 258 #[allow(unused)]
263 thread: jod_thread::JoinHandle<io::Result<bool>>, 259 thread: jod_thread::JoinHandle<io::Result<bool>>,
264 receiver: Receiver<cargo_metadata::Message>, 260 receiver: Receiver<CargoMessage>,
265} 261}
266 262
267impl CargoHandle { 263impl CargoHandle {
@@ -294,14 +290,11 @@ impl CargoHandle {
294 290
295struct CargoActor { 291struct CargoActor {
296 child_stdout: process::ChildStdout, 292 child_stdout: process::ChildStdout,
297 sender: Sender<cargo_metadata::Message>, 293 sender: Sender<CargoMessage>,
298} 294}
299 295
300impl CargoActor { 296impl CargoActor {
301 fn new( 297 fn new(child_stdout: process::ChildStdout, sender: Sender<CargoMessage>) -> CargoActor {
302 child_stdout: process::ChildStdout,
303 sender: Sender<cargo_metadata::Message>,
304 ) -> CargoActor {
305 CargoActor { child_stdout, sender } 298 CargoActor { child_stdout, sender }
306 } 299 }
307 fn run(self) -> io::Result<bool> { 300 fn run(self) -> io::Result<bool> {
@@ -315,7 +308,7 @@ impl CargoActor {
315 // erroneus output. 308 // erroneus output.
316 let stdout = BufReader::new(self.child_stdout); 309 let stdout = BufReader::new(self.child_stdout);
317 let mut read_at_least_one_message = false; 310 let mut read_at_least_one_message = false;
318 for message in cargo_metadata::Message::parse_stream(stdout) { 311 for message in stdout.lines() {
319 let message = match message { 312 let message = match message {
320 Ok(message) => message, 313 Ok(message) => message,
321 Err(err) => { 314 Err(err) => {
@@ -326,13 +319,44 @@ impl CargoActor {
326 319
327 read_at_least_one_message = true; 320 read_at_least_one_message = true;
328 321
329 // Skip certain kinds of messages to only spend time on what's useful 322 // Try to deserialize a message from Cargo or Rustc.
330 match &message { 323 let mut deserializer = serde_json::Deserializer::from_str(&message);
331 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (), 324 deserializer.disable_recursion_limit();
332 cargo_metadata::Message::BuildScriptExecuted(_) => (), 325 if let Ok(message) = JsonMessage::deserialize(&mut deserializer) {
333 _ => self.sender.send(message).unwrap(), 326 match message {
327 // Skip certain kinds of messages to only spend time on what's useful
328 JsonMessage::Cargo(message) => match message {
329 cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => {
330 self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap()
331 }
332 cargo_metadata::Message::CompilerMessage(msg) => {
333 self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap()
334 }
335
336 cargo_metadata::Message::CompilerArtifact(_)
337 | cargo_metadata::Message::BuildScriptExecuted(_)
338 | cargo_metadata::Message::BuildFinished(_)
339 | cargo_metadata::Message::TextLine(_)
340 | _ => (),
341 },
342 JsonMessage::Rustc(message) => {
343 self.sender.send(CargoMessage::Diagnostic(message)).unwrap()
344 }
345 }
334 } 346 }
335 } 347 }
336 Ok(read_at_least_one_message) 348 Ok(read_at_least_one_message)
337 } 349 }
338} 350}
351
352enum CargoMessage {
353 CompilerArtifact(cargo_metadata::Artifact),
354 Diagnostic(Diagnostic),
355}
356
357#[derive(Deserialize)]
358#[serde(untagged)]
359enum JsonMessage {
360 Cargo(cargo_metadata::Message),
361 Rustc(Diagnostic),
362}