fix(parser): better unclosed delims handling

This commit is contained in:
Caleb Cartwright 2020-10-29 22:50:25 -05:00 committed by Caleb Cartwright
parent e131797b62
commit 9faba4539b
4 changed files with 86 additions and 49 deletions

View File

@ -23,7 +23,6 @@ pub(crate) struct Directory {
/// A parser for Rust source code.
pub(crate) struct Parser<'a> {
parser: RawParser<'a>,
sess: &'a ParseSess,
}
/// A builder for the `Parser`.
@ -71,7 +70,7 @@ impl<'a> ParserBuilder<'a> {
}
};
Ok(Parser { parser, sess })
Ok(Parser { parser })
}
fn parser(
@ -150,6 +149,25 @@ impl<'a> Parser<'a> {
input: Input,
directory_ownership: Option<DirectoryOwnership>,
sess: &'a ParseSess,
) -> Result<ast::Crate, ParserError> {
let krate = Parser::parse_crate_inner(config, input, directory_ownership, sess)?;
if !sess.has_errors() {
return Ok(krate);
}
if sess.can_reset_errors() {
sess.reset_errors();
return Ok(krate);
}
Err(ParserError::ParseError)
}
fn parse_crate_inner(
config: &'a Config,
input: Input,
directory_ownership: Option<DirectoryOwnership>,
sess: &'a ParseSess,
) -> Result<ast::Crate, ParserError> {
let mut parser = ParserBuilder::default()
.config(config)
@ -157,26 +175,14 @@ impl<'a> Parser<'a> {
.directory_ownership(directory_ownership)
.sess(sess)
.build()?;
parser.parse_crate_inner()
parser.parse_crate_mod()
}
fn parse_crate_inner(&mut self) -> Result<ast::Crate, ParserError> {
fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
let mut parser = AssertUnwindSafe(&mut self.parser);
match catch_unwind(move || parser.parse_crate_mod()) {
Ok(Ok(krate)) => {
if !self.sess.has_errors() {
return Ok(krate);
}
if self.sess.can_reset_errors() {
self.sess.reset_errors();
return Ok(krate);
}
Err(ParserError::ParseError)
}
Ok(Ok(k)) => Ok(k),
Ok(Err(mut db)) => {
db.emit();
Err(ParserError::ParseError)

View File

@ -11,14 +11,12 @@ use std::thread;
use crate::config::{Color, Config, EmitMode, FileName, NewlineStyle, ReportTactic};
use crate::formatting::{ReportedErrors, SourceFile};
use crate::modules::{ModuleResolutionError, ModuleResolutionErrorKind};
use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChunk, OutputWriter};
use crate::source_file;
use crate::{
is_nightly_channel, ErrorKind, FormatReport, FormatReportFormatterBuilder, Input, Session,
};
use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
mod configuration_snippet;
mod parser;
const DIFF_CONTEXT_SIZE: usize = 3;
@ -485,34 +483,6 @@ fn format_lines_errors_are_reported_with_tabs() {
assert!(session.has_formatting_errors());
}
#[test]
fn parser_errors_in_submods_are_surfaced() {
// See also https://github.com/rust-lang/rustfmt/issues/4126
let filename = "tests/parser/issue-4126/lib.rs";
let input_file = PathBuf::from(filename);
let exp_mod_name = "invalid";
let config = read_config(&input_file);
let mut session = Session::<io::Stdout>::new(config, None);
if let Err(ErrorKind::ModuleResolutionError(ModuleResolutionError { module, kind })) =
session.format(Input::File(filename.into()))
{
assert_eq!(&module, exp_mod_name);
if let ModuleResolutionErrorKind::ParseError {
file: unparseable_file,
} = kind
{
assert_eq!(
unparseable_file,
PathBuf::from("tests/parser/issue-4126/invalid.rs"),
);
} else {
panic!("Expected parser error");
}
} else {
panic!("Expected ModuleResolution operation error");
}
}
// For each file, run rustfmt and collect the output.
// Returns the number of files checked and the number of failures.
fn check_files(files: Vec<PathBuf>, opt_config: &Option<PathBuf>) -> (Vec<FormatReport>, u32, u32) {

50
src/test/parser.rs Normal file
View File

@ -0,0 +1,50 @@
use std::io;
use std::path::PathBuf;
use super::read_config;
use crate::modules::{ModuleResolutionError, ModuleResolutionErrorKind};
use crate::{ErrorKind, Input, Session};
#[test]
fn parser_errors_in_submods_are_surfaced() {
// See also https://github.com/rust-lang/rustfmt/issues/4126
let filename = "tests/parser/issue-4126/lib.rs";
let input_file = PathBuf::from(filename);
let exp_mod_name = "invalid";
let config = read_config(&input_file);
let mut session = Session::<io::Stdout>::new(config, None);
if let Err(ErrorKind::ModuleResolutionError(ModuleResolutionError { module, kind })) =
session.format(Input::File(filename.into()))
{
assert_eq!(&module, exp_mod_name);
if let ModuleResolutionErrorKind::ParseError {
file: unparseable_file,
} = kind
{
assert_eq!(
unparseable_file,
PathBuf::from("tests/parser/issue-4126/invalid.rs"),
);
} else {
panic!("Expected parser error");
}
} else {
panic!("Expected ModuleResolution operation error");
}
}
fn assert_parser_error(filename: &str) {
let file = PathBuf::from(filename);
let config = read_config(&file);
let mut session = Session::<io::Stdout>::new(config, None);
let _ = session.format(Input::File(filename.into())).unwrap();
assert!(session.has_parsing_errors());
}
#[test]
fn crate_parsing_errors_on_unclosed_delims() {
// See also https://github.com/rust-lang/rustfmt/issues/4466
let filename = "tests/parser/unclosed-delims/issue_4466.rs";
assert_parser_error(filename);
}

View File

@ -0,0 +1,11 @@
fn main() {
if true {
println!("answer: {}", a_func();
} else {
println!("don't think so.");
}
}
fn a_func() -> i32 {
42
}