Skip to content

Commit

Permalink
Catch parser panic in format_snippet (rust-lang#3103)
Browse files Browse the repository at this point in the history
  • Loading branch information
topecongiro authored Oct 17, 2018
1 parent c09d7ef commit 8c4e92a
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 13 deletions.
34 changes: 21 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> {
let mut out: Vec<u8> = 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<u8> = 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()
}

Expand Down
20 changes: 20 additions & 0 deletions tests/source/invalid-rust-code-in-doc-comment.rs
Original file line number Diff line number Diff line change
@@ -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 ;
18 changes: 18 additions & 0 deletions tests/target/invalid-rust-code-in-doc-comment.rs
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 8c4e92a

Please sign in to comment.