Skip to content

Commit 1ee5a73

Browse files
committed
Fix for issues 4603 and 4609 - unlimitted indentation of macro code
1 parent 367a874 commit 1ee5a73

File tree

13 files changed

+406
-30
lines changed

13 files changed

+406
-30
lines changed

src/formatting.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,45 @@ pub(crate) mod visitor;
5858

5959
pub(crate) mod report;
6060

61+
// As `catch_unwind` in `format_snippet()` does not allow the the of a `mut bool`,
62+
// this function is used to `format_input_inner()` using a reference to a new
63+
// `bool` variable, and return its value as part of the function return value.
64+
pub(crate) fn format_input_inner_for_catch_unwind(
65+
input: Input,
66+
config: &Config,
67+
operation_setting: OperationSetting,
68+
is_macro_def: bool,
69+
) -> (Result<FormatReport, OperationError>, bool) {
70+
let mut macro_original_code_was_used = false;
71+
let result = crate::format_input_inner(
72+
input,
73+
&config,
74+
operation_setting,
75+
is_macro_def,
76+
&mut macro_original_code_was_used,
77+
);
78+
return (result, macro_original_code_was_used);
79+
}
80+
6181
pub(crate) fn format_input_inner(
6282
input: Input,
6383
config: &Config,
6484
operation_setting: OperationSetting,
6585
is_macro_def: bool,
86+
macro_original_code_was_used: &mut bool,
6687
) -> Result<FormatReport, OperationError> {
6788
if !config.version_meets_requirement() {
6889
return Err(OperationError::VersionMismatch);
6990
}
7091

7192
rustc_span::with_session_globals(config.edition().into(), || {
72-
format_project(input, config, operation_setting, is_macro_def)
93+
format_project(
94+
input,
95+
config,
96+
operation_setting,
97+
is_macro_def,
98+
macro_original_code_was_used,
99+
)
73100
})
74101
}
75102

@@ -78,6 +105,7 @@ fn format_project(
78105
config: &Config,
79106
operation_setting: OperationSetting,
80107
is_macro_def: bool,
108+
macro_original_code_was_used: &mut bool,
81109
) -> Result<FormatReport, OperationError> {
82110
let mut timer = Timer::start();
83111

@@ -87,6 +115,7 @@ fn format_project(
87115
let input_is_stdin = main_file == FileName::Stdin;
88116

89117
let mut parse_session = ParseSess::new(config)?;
118+
90119
if !operation_setting.recursive && parse_session.ignore_file(&main_file) {
91120
format_report.add_ignored_file(main_file);
92121
return Ok(format_report);
@@ -152,6 +181,7 @@ fn format_project(
152181
&files,
153182
original_snippet.clone(),
154183
is_macro_def,
184+
macro_original_code_was_used,
155185
)?;
156186
}
157187
timer = timer.done_formatting();
@@ -177,15 +207,18 @@ fn format_file(
177207
file_mod_map: &FileModMap<'_>,
178208
original_snippet: Option<String>,
179209
is_macro_def: bool,
210+
macro_original_code_was_used: &mut bool,
180211
) -> Result<(), OperationError> {
181212
let snippet_provider = parse_session.snippet_provider(module.as_ref().inner);
213+
182214
let mut visitor = FmtVisitor::from_parse_sess(
183215
&parse_session,
184216
config,
185217
&snippet_provider,
186218
file_mod_map,
187219
report.clone(),
188220
);
221+
189222
visitor.is_macro_def = is_macro_def;
190223
visitor.skip_context.update_with_attrs(&krate.attrs);
191224
visitor.last_pos = snippet_provider.start_pos();
@@ -237,6 +270,10 @@ fn format_file(
237270
);
238271
report.add_format_result(path.clone(), format_result);
239272

273+
if visitor.macro_original_code_was_used.get() {
274+
*macro_original_code_was_used = true;
275+
}
276+
240277
Ok(())
241278
}
242279

src/formatting/comment.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -687,9 +687,13 @@ impl<'a> CommentRewrite<'a> {
687687
let mut config = self.fmt.config.clone();
688688
config.set().wrap_comments(false);
689689
if config.format_code_in_doc_comments() {
690-
if let Some(s) =
691-
format_code_block(&self.code_block_buffer, &config, false)
692-
{
690+
let mut macro_original_code_was_used = false;
691+
if let Some(s) = format_code_block(
692+
&self.code_block_buffer,
693+
&config,
694+
false,
695+
&mut macro_original_code_was_used,
696+
) {
693697
trim_custom_comment_prefix(s.as_ref())
694698
} else {
695699
trim_custom_comment_prefix(&self.code_block_buffer)
@@ -1604,6 +1608,7 @@ pub(crate) fn recover_comment_removed(
16041608
let snippet = context.snippet(span);
16051609
let includes_comment = contains_comment(snippet);
16061610
if snippet != new && includes_comment && changed_comment_content(snippet, &new) {
1611+
context.macro_original_code_was_used.replace(true);
16071612
snippet.to_owned()
16081613
} else {
16091614
new

src/formatting/expr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ pub(crate) fn rewrite_block_with_visitor(
606606
.skipped_range
607607
.borrow_mut()
608608
.append(&mut visitor_context.skipped_range.borrow_mut());
609+
610+
if visitor.macro_original_code_was_used.get() {
611+
context.macro_original_code_was_used.replace(true);
612+
}
613+
609614
Some(format!("{}{}{}", prefix, label_str, visitor.buffer))
610615
}
611616

src/formatting/items.rs

+13
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,10 @@ pub(crate) fn format_impl(
890890
result.push_str(&inner_indent_str);
891891
result.push_str(visitor.buffer.trim());
892892
result.push_str(&outer_indent_str);
893+
894+
if visitor.macro_original_code_was_used.get() {
895+
context.macro_original_code_was_used.replace(true);
896+
}
893897
} else if need_newline || !context.config.empty_item_single_line() {
894898
result.push_str(&sep);
895899
}
@@ -1266,6 +1270,10 @@ pub(crate) fn format_trait(
12661270
result.push_str(&inner_indent_str);
12671271
result.push_str(visitor.buffer.trim());
12681272
result.push_str(&outer_indent_str);
1273+
1274+
if visitor.macro_original_code_was_used.get() {
1275+
context.macro_original_code_was_used.replace(true);
1276+
}
12691277
} else if result.contains('\n') {
12701278
result.push_str(&outer_indent_str);
12711279
}
@@ -3264,6 +3272,11 @@ impl Rewrite for ast::ForeignItem {
32643272
defaultness,
32653273
Some(&inner_attrs),
32663274
);
3275+
3276+
if visitor.macro_original_code_was_used.get() {
3277+
context.macro_original_code_was_used.replace(true);
3278+
}
3279+
32673280
Some(visitor.buffer.to_owned())
32683281
}
32693282
ast::ForeignItemKind::Fn(_, ref fn_sig, ref generics, None) => rewrite_fn_base(

src/formatting/macros.rs

+54-17
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ fn return_macro_parse_failure_fallback(
170170
) -> Option<String> {
171171
// Mark this as a failure however we format it
172172
context.macro_rewrite_failure.replace(true);
173-
173+
context.macro_original_code_was_used.replace(true);
174174
// Heuristically determine whether the last line of the macro uses "Block" style
175175
// rather than using "Visual" style, or another indentation style.
176176
let is_like_block_indent_style = context
@@ -229,6 +229,7 @@ pub(crate) fn rewrite_macro(
229229
guard.is_nested(),
230230
)
231231
}));
232+
232233
match result {
233234
Err(..) | Ok(None) => {
234235
context.macro_rewrite_failure.replace(true);
@@ -510,13 +511,17 @@ pub(crate) fn rewrite_macro_def(
510511
) -> Option<String> {
511512
let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
512513
if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
514+
context.macro_original_code_was_used.replace(true);
513515
return snippet;
514516
}
515517
let ts = def.body.inner_tokens();
516518
let mut parser = MacroParser::new(ts.into_trees());
517519
let parsed_def = match parser.parse(def.macro_rules) {
518520
Some(def) => def,
519-
None => return snippet,
521+
None => {
522+
context.macro_original_code_was_used.replace(true);
523+
return snippet;
524+
}
520525
};
521526

522527
let mut result = if def.macro_rules {
@@ -527,7 +532,6 @@ pub(crate) fn rewrite_macro_def(
527532

528533
result += " ";
529534
result += rewrite_ident(context, ident);
530-
531535
let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
532536

533537
let arm_shape = if multi_branch_style {
@@ -550,6 +554,7 @@ pub(crate) fn rewrite_macro_def(
550554
// if the rewrite returned None because a macro could not be rewritten, then return the
551555
// original body
552556
None if context.macro_rewrite_failure.get() => {
557+
context.macro_original_code_was_used.replace(true);
553558
Some(context.snippet(branch.body).trim().to_string())
554559
}
555560
None => None,
@@ -576,14 +581,16 @@ pub(crate) fn rewrite_macro_def(
576581

577582
match write_list(&branch_items, &fmt) {
578583
Some(ref s) => result += s,
579-
None => return snippet,
584+
None => {
585+
context.macro_original_code_was_used.replace(true);
586+
return snippet;
587+
}
580588
}
581589

582590
if multi_branch_style {
583591
result += &indent.to_string_with_newline(context.config);
584592
result += "}";
585593
}
586-
587594
Some(result)
588595
}
589596

@@ -1274,7 +1281,8 @@ impl MacroParser {
12741281
branches.push(self.parse_branch(is_macro_rules)?);
12751282
}
12761283

1277-
Some(Macro { branches })
1284+
let ret = Some(Macro { branches });
1285+
ret
12781286
}
12791287

12801288
// `(` ... `)` `=>` `{` ... `}`
@@ -1356,6 +1364,10 @@ impl MacroBranch {
13561364
result += " =>";
13571365
}
13581366

1367+
// Prepare for restoring original macro body if original code was use during formatting
1368+
// (since in this case indentation done by this function doesn't work properly).
1369+
let result_without_body = result.clone();
1370+
13591371
if !context.config.format_macro_bodies() {
13601372
result += " ";
13611373
result += context.snippet(self.whole_body);
@@ -1386,23 +1398,44 @@ impl MacroBranch {
13861398
config.set().max_width(new_width);
13871399

13881400
// First try to format as items, then as statements.
1389-
let new_body_snippet = match format_snippet(&body_str, &config, true) {
1390-
Some(new_body) => new_body,
1391-
None => {
1392-
let new_width = new_width + config.tab_spaces();
1393-
config.set().max_width(new_width);
1394-
match format_code_block(&body_str, &config, true) {
1395-
Some(new_body) => new_body,
1396-
None => return None,
1401+
1402+
let mut macro_original_code_was_used = false;
1403+
1404+
let new_body_snippet =
1405+
match format_snippet(&body_str, &config, true, &mut macro_original_code_was_used) {
1406+
Some(new_body) => new_body,
1407+
None => {
1408+
let new_width = new_width + config.tab_spaces();
1409+
config.set().max_width(new_width);
1410+
match format_code_block(
1411+
&body_str,
1412+
&config,
1413+
true,
1414+
&mut macro_original_code_was_used,
1415+
) {
1416+
Some(new_body) => new_body,
1417+
None => {
1418+
return None;
1419+
}
1420+
}
13971421
}
1398-
}
1399-
};
1422+
};
1423+
14001424
let new_body = wrap_str(
14011425
new_body_snippet.as_ref().to_owned(),
14021426
config.max_width(),
14031427
shape,
14041428
)?;
14051429

1430+
// If original code was used during the macro body formatting -
1431+
// use whole original body without formatting
1432+
if macro_original_code_was_used {
1433+
result = result_without_body;
1434+
result += " ";
1435+
result += context.snippet(self.whole_body);
1436+
return Some(result);
1437+
}
1438+
14061439
// Indent the body since it is in a block.
14071440
let indent_str = body_indent.to_string(&config);
14081441
let mut new_body = LineClasses::new(new_body.trim_end())
@@ -1425,7 +1458,6 @@ impl MacroBranch {
14251458
// FIXME: this could be *much* more efficient.
14261459
for (old, new) in &substs {
14271460
if old_body.contains(new) {
1428-
debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
14291461
return None;
14301462
}
14311463
new_body = new_body.replace(new, old);
@@ -1576,6 +1608,11 @@ fn rewrite_macro_with_items(
15761608
result.push_str(&shape.indent.to_string_with_newline(context.config));
15771609
result.push_str(closer);
15781610
result.push_str(trailing_semicolon);
1611+
1612+
if visitor.macro_original_code_was_used.get() {
1613+
context.macro_original_code_was_used.replace(true);
1614+
}
1615+
15791616
Some(result)
15801617
}
15811618

src/formatting/rewrite.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub(crate) struct RewriteContext<'a> {
4444
pub(crate) snippet_provider: &'a SnippetProvider,
4545
// Used for `format_snippet`
4646
pub(crate) macro_rewrite_failure: Cell<bool>,
47+
pub(crate) macro_original_code_was_used: Cell<bool>,
4748
pub(crate) report: FormatReport,
4849
pub(crate) skip_context: SkipContext,
4950
pub(crate) skipped_range: Rc<RefCell<Vec<NonFormattedRange>>>,

0 commit comments

Comments
 (0)