Skip to content

Commit c9aebea

Browse files
fix(parser): better unclosed delims handling (#4472)
1 parent 4834547 commit c9aebea

File tree

4 files changed

+94
-57
lines changed

4 files changed

+94
-57
lines changed

src/formatting/syntux/parser.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ pub(crate) struct Directory {
2323
/// A parser for Rust source code.
2424
pub(crate) struct Parser<'a> {
2525
parser: RawParser<'a>,
26-
sess: &'a ParseSess,
2726
}
2827

2928
/// A builder for the `Parser`.
@@ -74,7 +73,7 @@ impl<'a> ParserBuilder<'a> {
7473
}
7574
};
7675

77-
Ok(Parser { parser, sess })
76+
Ok(Parser { parser })
7877
}
7978

8079
fn parser(
@@ -159,6 +158,25 @@ impl<'a> Parser<'a> {
159158
input: Input,
160159
directory_ownership: Option<DirectoryOwnership>,
161160
sess: &'a ParseSess,
161+
) -> Result<ast::Crate, ParserError> {
162+
let krate = Parser::parse_crate_inner(config, input, directory_ownership, sess)?;
163+
if !sess.has_errors() {
164+
return Ok(krate);
165+
}
166+
167+
if sess.can_reset_errors() {
168+
sess.reset_errors();
169+
return Ok(krate);
170+
}
171+
172+
Err(ParserError::ParseError)
173+
}
174+
175+
fn parse_crate_inner(
176+
config: &'a Config,
177+
input: Input,
178+
directory_ownership: Option<DirectoryOwnership>,
179+
sess: &'a ParseSess,
162180
) -> Result<ast::Crate, ParserError> {
163181
let mut parser = ParserBuilder::default()
164182
.config(config)
@@ -167,25 +185,14 @@ impl<'a> Parser<'a> {
167185
.sess(sess)
168186
.build()?;
169187

170-
parser.parse_crate_inner()
188+
parser.parse_crate_mod()
171189
}
172190

173-
fn parse_crate_inner(&mut self) -> Result<ast::Crate, ParserError> {
191+
fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
174192
let mut parser = AssertUnwindSafe(&mut self.parser);
175193

176194
match catch_unwind(move || parser.parse_crate_mod()) {
177-
Ok(Ok(krate)) => {
178-
if !self.sess.has_errors() {
179-
return Ok(krate);
180-
}
181-
182-
if self.sess.can_reset_errors() {
183-
self.sess.reset_errors();
184-
return Ok(krate);
185-
}
186-
187-
Err(ParserError::ParseError)
188-
}
195+
Ok(Ok(k)) => Ok(k),
189196
Ok(Err(mut db)) => {
190197
db.emit();
191198
Err(ParserError::ParseError)

src/test/mod.rs

+2-41
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ use crate::emitter::rustfmt_diff::{make_diff, print_diff, Mismatch, ModifiedChun
1111
use crate::config::{Config, FileName, NewlineStyle};
1212
use crate::{
1313
emitter::{emit_format_report, Color, EmitMode, EmitterConfig},
14-
format,
15-
formatting::modules::{ModuleResolutionError, ModuleResolutionErrorKind},
16-
is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, OperationError,
14+
format, is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, OperationError,
1715
OperationSetting,
1816
};
1917

2018
mod configuration_snippet;
19+
mod parser;
2120

2221
const DIFF_CONTEXT_SIZE: usize = 3;
2322

@@ -523,44 +522,6 @@ fn format_lines_errors_are_reported_with_tabs() {
523522
assert!(report.has_errors());
524523
}
525524

526-
#[test]
527-
fn parser_errors_in_submods_are_surfaced() {
528-
// See also https://github.com/rust-lang/rustfmt/issues/4126
529-
let filename = "tests/parser/issue-4126/lib.rs";
530-
let file = PathBuf::from(filename);
531-
let exp_mod_name = "invalid";
532-
let (config, operation, _) = read_config(&file);
533-
if let Err(OperationError::ModuleResolutionError { 0: inner }) =
534-
format_file(&file, operation, config)
535-
{
536-
let ModuleResolutionError { module, kind } = inner;
537-
assert_eq!(&module, exp_mod_name);
538-
if let ModuleResolutionErrorKind::ParseError { file } = kind {
539-
assert_eq!(file, PathBuf::from("tests/parser/issue-4126/invalid.rs"));
540-
} else {
541-
panic!("Expected parser error");
542-
}
543-
} else {
544-
panic!("Expected ModuleResolution operation error");
545-
}
546-
}
547-
548-
#[test]
549-
fn parser_creation_errors_on_entry_new_parser_from_file_panic() {
550-
// See also https://github.com/rust-lang/rustfmt/issues/4418
551-
let filename = "tests/parser/issue_4418.rs";
552-
let file = PathBuf::from(filename);
553-
let (config, operation, _) = read_config(&file);
554-
if let Err(OperationError::ParseError { input, is_panic }) =
555-
format_file(&file, operation, config)
556-
{
557-
assert_eq!(input.as_path().unwrap(), file);
558-
assert!(is_panic);
559-
} else {
560-
panic!("Expected ParseError operation error");
561-
}
562-
}
563-
564525
// For each file, run rustfmt and collect the output.
565526
// Returns the number of files checked and the number of failures.
566527
fn check_files(files: Vec<PathBuf>, opt_config: &Option<PathBuf>) -> (Vec<FormatReport>, u32, u32) {

src/test/parser.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::path::PathBuf;
2+
3+
use super::{format_file, read_config};
4+
use crate::{
5+
formatting::modules::{ModuleResolutionError, ModuleResolutionErrorKind},
6+
OperationError,
7+
};
8+
9+
#[test]
10+
fn parser_errors_in_submods_are_surfaced() {
11+
// See also https://github.com/rust-lang/rustfmt/issues/4126
12+
let filename = "tests/parser/issue-4126/lib.rs";
13+
let file = PathBuf::from(filename);
14+
let exp_mod_name = "invalid";
15+
let (config, operation, _) = read_config(&file);
16+
if let Err(OperationError::ModuleResolutionError { 0: inner }) =
17+
format_file(&file, operation, config)
18+
{
19+
let ModuleResolutionError { module, kind } = inner;
20+
assert_eq!(&module, exp_mod_name);
21+
if let ModuleResolutionErrorKind::ParseError { file } = kind {
22+
assert_eq!(file, PathBuf::from("tests/parser/issue-4126/invalid.rs"));
23+
} else {
24+
panic!("Expected parser error");
25+
}
26+
} else {
27+
panic!("Expected ModuleResolution operation error");
28+
}
29+
}
30+
31+
fn assert_parser_error(filename: &str, exp_panic: bool) {
32+
let file = PathBuf::from(filename);
33+
let (config, operation, _) = read_config(&file);
34+
if let Err(OperationError::ParseError { input, is_panic }) =
35+
format_file(&file, operation, config)
36+
{
37+
assert_eq!(input.as_path().unwrap(), file);
38+
assert_eq!(is_panic, exp_panic);
39+
} else {
40+
panic!("Expected ParseError operation error");
41+
}
42+
}
43+
44+
#[test]
45+
fn parser_creation_errors_on_entry_new_parser_from_file_panic() {
46+
// See also https://github.com/rust-lang/rustfmt/issues/4418
47+
let filename = "tests/parser/issue_4418.rs";
48+
let should_panic = true;
49+
assert_parser_error(filename, should_panic);
50+
}
51+
52+
#[test]
53+
fn crate_parsing_errors_on_unclosed_delims() {
54+
// See also https://github.com/rust-lang/rustfmt/issues/4466
55+
let filename = "tests/parser/unclosed-delims/issue_4466.rs";
56+
let should_panic = false;
57+
assert_parser_error(filename, should_panic);
58+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
if true {
3+
println!("answer: {}", a_func();
4+
} else {
5+
println!("don't think so.");
6+
}
7+
}
8+
9+
fn a_func() -> i32 {
10+
42
11+
}

0 commit comments

Comments
 (0)