From 8c4e92a14ecd63b71c28cc6461883dc914d47979 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Wed, 17 Oct 2018 14:21:04 +0900 Subject: [PATCH] Catch parser panic in format_snippet (#3103) --- src/lib.rs | 34 ++++++++++++------- .../invalid-rust-code-in-doc-comment.rs | 20 +++++++++++ .../invalid-rust-code-in-doc-comment.rs | 18 ++++++++++ 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 tests/source/invalid-rust-code-in-doc-comment.rs create mode 100644 tests/target/invalid-rust-code-in-doc-comment.rs diff --git a/src/lib.rs b/src/lib.rs index 772ed8cb1417..9540b9fd20e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ use std::collections::HashMap; use std::fmt; use std::io::{self, Write}; use std::mem; +use std::panic; use std::path::PathBuf; use std::rc::Rc; use syntax::ast; @@ -355,21 +356,28 @@ impl fmt::Display for FormatReport { /// Format the given snippet. The snippet is expected to be *complete* code. /// When we cannot parse the given snippet, this function returns `None`. fn format_snippet(snippet: &str, config: &Config) -> Option { - let mut out: Vec = Vec::with_capacity(snippet.len() * 2); - let input = Input::Text(snippet.into()); let mut config = config.clone(); - config.set().emit_mode(config::EmitMode::Stdout); - config.set().verbose(Verbosity::Quiet); - config.set().hide_parse_errors(true); - { - let mut session = Session::new(config, Some(&mut out)); - let result = session.format(input); - let formatting_error = session.errors.has_macro_format_failure - || session.out.as_ref().unwrap().is_empty() && !snippet.is_empty(); - if formatting_error || result.is_err() { - return None; + let out = panic::catch_unwind(|| { + let mut out: Vec = Vec::with_capacity(snippet.len() * 2); + config.set().emit_mode(config::EmitMode::Stdout); + config.set().verbose(Verbosity::Quiet); + config.set().hide_parse_errors(true); + let formatting_error = { + let input = Input::Text(snippet.into()); + let mut session = Session::new(config, Some(&mut out)); + let result = session.format(input); + session.errors.has_macro_format_failure + || session.out.as_ref().unwrap().is_empty() && !snippet.is_empty() + || result.is_err() + }; + if formatting_error { + None + } else { + Some(out) } - } + }) + .ok()??; // The first try operator handles the error from catch_unwind, + // whereas the second one handles None from the closure. String::from_utf8(out).ok() } diff --git a/tests/source/invalid-rust-code-in-doc-comment.rs b/tests/source/invalid-rust-code-in-doc-comment.rs new file mode 100644 index 000000000000..6d33dcfce552 --- /dev/null +++ b/tests/source/invalid-rust-code-in-doc-comment.rs @@ -0,0 +1,20 @@ +// rustfmt-format_doc_comments: true + +/// ```rust +/// if (true) { … } +/// ``` +fn a() { +} + +/// ```rust +/// if foo() { +/// … +/// } +/// ``` +fn a() { +} + +/// ```rust +/// k1 == k2 ⇒ hash(k1) == hash(k2) +/// ``` +pub struct a ; diff --git a/tests/target/invalid-rust-code-in-doc-comment.rs b/tests/target/invalid-rust-code-in-doc-comment.rs new file mode 100644 index 000000000000..2593410a4189 --- /dev/null +++ b/tests/target/invalid-rust-code-in-doc-comment.rs @@ -0,0 +1,18 @@ +// rustfmt-format_doc_comments: true + +/// ```rust +/// if (true) { … } +/// ``` +fn a() {} + +/// ```rust +/// if foo() { +/// … +/// } +/// ``` +fn a() {} + +/// ```rust +/// k1 == k2 ⇒ hash(k1) == hash(k2) +/// ``` +pub struct a;