Skip to content

Commit a613c57

Browse files
feat: don't insert semi in macro_rules arm body
1 parent eb894d5 commit a613c57

File tree

8 files changed

+65
-18
lines changed

8 files changed

+65
-18
lines changed

Diff for: src/comment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ impl<'a> CommentRewrite<'a> {
659659
config.set().wrap_comments(false);
660660
if config.format_code_in_doc_comments() {
661661
if let Some(s) =
662-
crate::format_code_block(&self.code_block_buffer, &config)
662+
crate::format_code_block(&self.code_block_buffer, &config, false)
663663
{
664664
trim_custom_comment_prefix(&s.snippet)
665665
} else {

Diff for: src/formatting.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ pub(crate) type SourceFile = Vec<FileRecord>;
2525
pub(crate) type FileRecord = (FileName, String);
2626

2727
impl<'b, T: Write + 'b> Session<'b, T> {
28-
pub(crate) fn format_input_inner(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
28+
pub(crate) fn format_input_inner(
29+
&mut self,
30+
input: Input,
31+
is_macro_def: bool,
32+
) -> Result<FormatReport, ErrorKind> {
2933
if !self.config.version_meets_requirement() {
3034
return Err(ErrorKind::VersionMismatch);
3135
}
@@ -42,7 +46,7 @@ impl<'b, T: Write + 'b> Session<'b, T> {
4246
}
4347

4448
let config = &self.config.clone();
45-
let format_result = format_project(input, config, self);
49+
let format_result = format_project(input, config, self, is_macro_def);
4650

4751
format_result.map(|report| {
4852
self.errors.add(&report.internal.borrow().1);
@@ -57,6 +61,7 @@ fn format_project<T: FormatHandler>(
5761
input: Input,
5862
config: &Config,
5963
handler: &mut T,
64+
is_macro_def: bool,
6065
) -> Result<FormatReport, ErrorKind> {
6166
let mut timer = Timer::start();
6267

@@ -103,7 +108,7 @@ fn format_project<T: FormatHandler>(
103108
continue;
104109
}
105110
should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path));
106-
context.format_file(path, &module)?;
111+
context.format_file(path, &module, is_macro_def)?;
107112
}
108113
timer = timer.done_formatting();
109114

@@ -134,7 +139,12 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
134139
}
135140

136141
// Formats a single file/module.
137-
fn format_file(&mut self, path: FileName, module: &Module<'_>) -> Result<(), ErrorKind> {
142+
fn format_file(
143+
&mut self,
144+
path: FileName,
145+
module: &Module<'_>,
146+
is_macro_def: bool,
147+
) -> Result<(), ErrorKind> {
138148
let snippet_provider = self.parse_session.snippet_provider(module.as_ref().inner);
139149
let mut visitor = FmtVisitor::from_parse_sess(
140150
&self.parse_session,
@@ -143,7 +153,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
143153
self.report.clone(),
144154
);
145155
visitor.skip_context.update_with_attrs(&self.krate.attrs);
146-
156+
visitor.is_macro_def = is_macro_def;
147157
visitor.last_pos = snippet_provider.start_pos();
148158
visitor.skip_empty_lines(snippet_provider.end_pos());
149159
visitor.format_separate_mod(module, snippet_provider.end_pos());

Diff for: src/lib.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl fmt::Display for FormatReport {
286286

287287
/// Format the given snippet. The snippet is expected to be *complete* code.
288288
/// When we cannot parse the given snippet, this function returns `None`.
289-
fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
289+
fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option<FormattedSnippet> {
290290
let mut config = config.clone();
291291
panic::catch_unwind(|| {
292292
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
@@ -297,7 +297,7 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
297297
let (formatting_error, result) = {
298298
let input = Input::Text(snippet.into());
299299
let mut session = Session::new(config, Some(&mut out));
300-
let result = session.format(input);
300+
let result = session.format_input_inner(input, is_macro_def);
301301
(
302302
session.errors.has_macro_format_failure
303303
|| session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
@@ -323,7 +323,11 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
323323
/// The code block may be incomplete (i.e., parser may be unable to parse it).
324324
/// To avoid panic in parser, we wrap the code block with a dummy function.
325325
/// The returned code block does **not** end with newline.
326-
fn format_code_block(code_snippet: &str, config: &Config) -> Option<FormattedSnippet> {
326+
fn format_code_block(
327+
code_snippet: &str,
328+
config: &Config,
329+
is_macro_def: bool,
330+
) -> Option<FormattedSnippet> {
327331
const FN_MAIN_PREFIX: &str = "fn main() {\n";
328332

329333
fn enclose_in_main_block(s: &str, config: &Config) -> String {
@@ -356,7 +360,7 @@ fn format_code_block(code_snippet: &str, config: &Config) -> Option<FormattedSni
356360
config_with_unix_newline
357361
.set()
358362
.newline_style(NewlineStyle::Unix);
359-
let mut formatted = format_snippet(&snippet, &config_with_unix_newline)?;
363+
let mut formatted = format_snippet(&snippet, &config_with_unix_newline, is_macro_def)?;
360364
// Remove wrapping main block
361365
formatted.unwrap_code_block();
362366

@@ -435,7 +439,7 @@ impl<'b, T: Write + 'b> Session<'b, T> {
435439
/// The main entry point for Rustfmt. Formats the given input according to the
436440
/// given config. `out` is only necessary if required by the configuration.
437441
pub fn format(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
438-
self.format_input_inner(input)
442+
self.format_input_inner(input, false)
439443
}
440444

441445
pub fn override_config<F, U>(&mut self, mut config: Config, f: F) -> U
@@ -550,15 +554,15 @@ mod unit_tests {
550554
// `format_snippet()` and `format_code_block()` should not panic
551555
// even when we cannot parse the given snippet.
552556
let snippet = "let";
553-
assert!(format_snippet(snippet, &Config::default()).is_none());
554-
assert!(format_code_block(snippet, &Config::default()).is_none());
557+
assert!(format_snippet(snippet, &Config::default(), false).is_none());
558+
assert!(format_code_block(snippet, &Config::default(), false).is_none());
555559
}
556560

557561
fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
558562
where
559-
F: Fn(&str, &Config) -> Option<FormattedSnippet>,
563+
F: Fn(&str, &Config, bool) -> Option<FormattedSnippet>,
560564
{
561-
let output = formatter(input, &Config::default());
565+
let output = formatter(input, &Config::default(), false);
562566
output.is_some() && output.unwrap().snippet == expected
563567
}
564568

@@ -580,7 +584,7 @@ mod unit_tests {
580584
fn test_format_code_block_fail() {
581585
#[rustfmt::skip]
582586
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
583-
assert!(format_code_block(code_block, &Config::default()).is_none());
587+
assert!(format_code_block(code_block, &Config::default(), false).is_none());
584588
}
585589

586590
#[test]

Diff for: src/macros.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1363,12 +1363,12 @@ impl MacroBranch {
13631363
config.set().max_width(new_width);
13641364

13651365
// First try to format as items, then as statements.
1366-
let new_body_snippet = match crate::format_snippet(&body_str, &config) {
1366+
let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
13671367
Some(new_body) => new_body,
13681368
None => {
13691369
let new_width = new_width + config.tab_spaces();
13701370
config.set().max_width(new_width);
1371-
match crate::format_code_block(&body_str, &config) {
1371+
match crate::format_code_block(&body_str, &config, true) {
13721372
Some(new_body) => new_body,
13731373
None => return None,
13741374
}

Diff for: src/rewrite.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub(crate) struct RewriteContext<'a> {
3939
pub(crate) snippet_provider: &'a SnippetProvider,
4040
// Used for `format_snippet`
4141
pub(crate) macro_rewrite_failure: Cell<bool>,
42+
pub(crate) is_macro_def: bool,
4243
pub(crate) report: FormatReport,
4344
pub(crate) skip_context: SkipContext,
4445
pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,

Diff for: src/utils.rs

+7
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ pub(crate) fn contains_skip(attrs: &[Attribute]) -> bool {
279279

280280
#[inline]
281281
pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool {
282+
// Never try to insert semicolons on expressions when we're inside
283+
// a macro definition - this can prevent the macro from compiling
284+
// when used in expression position
285+
if context.is_macro_def {
286+
return false;
287+
}
288+
282289
match expr.kind {
283290
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
284291
context.config.trailing_semicolon()

Diff for: src/visitor.rs

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub(crate) struct FmtVisitor<'a> {
8686
pub(crate) macro_rewrite_failure: bool,
8787
pub(crate) report: FormatReport,
8888
pub(crate) skip_context: SkipContext,
89+
pub(crate) is_macro_def: bool,
8990
}
9091

9192
impl<'a> Drop for FmtVisitor<'a> {
@@ -811,6 +812,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
811812
snippet_provider,
812813
line_number: 0,
813814
skipped_range: Rc::new(RefCell::new(vec![])),
815+
is_macro_def: false,
814816
macro_rewrite_failure: false,
815817
report,
816818
skip_context: Default::default(),
@@ -1003,6 +1005,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
10031005
force_one_line_chain: Cell::new(false),
10041006
snippet_provider: self.snippet_provider,
10051007
macro_rewrite_failure: Cell::new(false),
1008+
is_macro_def: self.is_macro_def,
10061009
report: self.report.clone(),
10071010
skip_context: self.skip_context.clone(),
10081011
skipped_range: self.skipped_range.clone(),

Diff for: tests/target/macro_rules_semi.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
macro_rules! expr {
2+
(no_semi) => {
3+
return true
4+
};
5+
(semi) => {
6+
return true;
7+
};
8+
}
9+
10+
fn foo() -> bool {
11+
match true {
12+
true => expr!(no_semi),
13+
false if false => {
14+
expr!(semi)
15+
}
16+
false => {
17+
expr!(semi);
18+
}
19+
}
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)