Catch parser panic in format_snippet (#3103)

This commit is contained in:
Seiichi Uchida 2018-10-17 14:21:04 +09:00 committed by GitHub
parent c09d7ef088
commit 8c4e92a14e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 13 deletions

View file

@ -42,6 +42,7 @@ use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io::{self, Write}; use std::io::{self, Write};
use std::mem; use std::mem;
use std::panic;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use syntax::ast; use syntax::ast;
@ -355,21 +356,28 @@ impl fmt::Display for FormatReport {
/// Format the given snippet. The snippet is expected to be *complete* code. /// Format the given snippet. The snippet is expected to be *complete* code.
/// When we cannot parse the given snippet, this function returns `None`. /// When we cannot parse the given snippet, this function returns `None`.
fn format_snippet(snippet: &str, config: &Config) -> Option<String> { fn format_snippet(snippet: &str, config: &Config) -> Option<String> {
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
let input = Input::Text(snippet.into());
let mut config = config.clone(); let mut config = config.clone();
let out = panic::catch_unwind(|| {
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
config.set().emit_mode(config::EmitMode::Stdout); config.set().emit_mode(config::EmitMode::Stdout);
config.set().verbose(Verbosity::Quiet); config.set().verbose(Verbosity::Quiet);
config.set().hide_parse_errors(true); 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 mut session = Session::new(config, Some(&mut out));
let result = session.format(input); let result = session.format(input);
let formatting_error = session.errors.has_macro_format_failure session.errors.has_macro_format_failure
|| session.out.as_ref().unwrap().is_empty() && !snippet.is_empty(); || session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
if formatting_error || result.is_err() { || result.is_err()
return None; };
} 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() String::from_utf8(out).ok()
} }

View file

@ -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 ;

View file

@ -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;