rustfmt_nightly/
macros.rs

1// Format list-like macro invocations. These are invocations whose token trees
2// can be interpreted as expressions and separated by commas.
3// Note that these token trees do not actually have to be interpreted as
4// expressions by the compiler. An example of an invocation we would reformat is
5// foo!( x, y, z ). The token x may represent an identifier in the code, but we
6// interpreted as an expression.
7// Macro uses which are not-list like, such as bar!(key => val), will not be
8// reformatted.
9// List-like invocations with parentheses will be formatted as function calls,
10// and those with brackets will be formatted as array literals.
11
12use std::collections::HashMap;
13use std::panic::{AssertUnwindSafe, catch_unwind};
14
15use rustc_ast::token::{Delimiter, Token, TokenKind};
16use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree};
17use rustc_ast::{ast, ptr};
18use rustc_ast_pretty::pprust;
19use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol};
20use tracing::debug;
21
22use crate::comment::{
23    CharClasses, FindUncommented, FullCodeCharKind, LineClasses, contains_comment,
24};
25use crate::config::StyleEdition;
26use crate::config::lists::*;
27use crate::expr::{RhsAssignKind, rewrite_array, rewrite_assign_rhs};
28use crate::lists::{ListFormatting, itemize_list, write_list};
29use crate::overflow;
30use crate::parse::macros::lazy_static::parse_lazy_static;
31use crate::parse::macros::{ParsedMacroArgs, parse_expr, parse_macro_args};
32use crate::rewrite::{
33    MacroErrorKind, Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult,
34};
35use crate::shape::{Indent, Shape};
36use crate::source_map::SpanUtils;
37use crate::spanned::Spanned;
38use crate::utils::{
39    NodeIdExt, filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp,
40    remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout,
41};
42use crate::visitor::FmtVisitor;
43
44const FORCED_BRACKET_MACROS: &[&str] = &["vec!"];
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub(crate) enum MacroPosition {
48    Item,
49    Statement,
50    Expression,
51    Pat,
52}
53
54#[derive(Debug)]
55pub(crate) enum MacroArg {
56    Expr(ptr::P<ast::Expr>),
57    Ty(ptr::P<ast::Ty>),
58    Pat(ptr::P<ast::Pat>),
59    Item(ptr::P<ast::Item>),
60    Keyword(Ident, Span),
61}
62
63impl MacroArg {
64    pub(crate) fn is_item(&self) -> bool {
65        match self {
66            MacroArg::Item(..) => true,
67            _ => false,
68        }
69    }
70}
71
72impl Rewrite for ast::Item {
73    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
74        self.rewrite_result(context, shape).ok()
75    }
76
77    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
78        let mut visitor = crate::visitor::FmtVisitor::from_context(context);
79        visitor.block_indent = shape.indent;
80        visitor.last_pos = self.span().lo();
81        visitor.visit_item(self);
82        Ok(visitor.buffer.to_owned())
83    }
84}
85
86impl Rewrite for MacroArg {
87    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
88        self.rewrite_result(context, shape).ok()
89    }
90
91    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
92        match *self {
93            MacroArg::Expr(ref expr) => expr.rewrite_result(context, shape),
94            MacroArg::Ty(ref ty) => ty.rewrite_result(context, shape),
95            MacroArg::Pat(ref pat) => pat.rewrite_result(context, shape),
96            MacroArg::Item(ref item) => item.rewrite_result(context, shape),
97            MacroArg::Keyword(ident, _) => Ok(ident.name.to_string()),
98        }
99    }
100}
101
102/// Rewrite macro name without using pretty-printer if possible.
103fn rewrite_macro_name(context: &RewriteContext<'_>, path: &ast::Path) -> String {
104    if path.segments.len() == 1 {
105        // Avoid using pretty-printer in the common case.
106        format!("{}!", rewrite_ident(context, path.segments[0].ident))
107    } else {
108        format!("{}!", pprust::path_to_string(path))
109    }
110}
111
112// Use this on failing to format the macro call.
113// TODO(ding-young) We should also report macro parse failure to tell users why given snippet
114// is left unformatted. One possible improvement is appending formatting error to context.report
115fn return_macro_parse_failure_fallback(
116    context: &RewriteContext<'_>,
117    indent: Indent,
118    position: MacroPosition,
119    span: Span,
120) -> RewriteResult {
121    // Mark this as a failure however we format it
122    context.macro_rewrite_failure.replace(true);
123
124    // Heuristically determine whether the last line of the macro uses "Block" style
125    // rather than using "Visual" style, or another indentation style.
126    let is_like_block_indent_style = context
127        .snippet(span)
128        .lines()
129        .last()
130        .map(|closing_line| {
131            closing_line
132                .trim()
133                .chars()
134                .all(|ch| matches!(ch, '}' | ')' | ']'))
135        })
136        .unwrap_or(false);
137    if is_like_block_indent_style {
138        return trim_left_preserve_layout(context.snippet(span), indent, context.config)
139            .macro_error(MacroErrorKind::Unknown, span);
140    }
141
142    context.skipped_range.borrow_mut().push((
143        context.psess.line_of_byte_pos(span.lo()),
144        context.psess.line_of_byte_pos(span.hi()),
145    ));
146
147    // Return the snippet unmodified if the macro is not block-like
148    let mut snippet = context.snippet(span).to_owned();
149    if position == MacroPosition::Item {
150        snippet.push(';');
151    }
152    Ok(snippet)
153}
154
155pub(crate) fn rewrite_macro(
156    mac: &ast::MacCall,
157    context: &RewriteContext<'_>,
158    shape: Shape,
159    position: MacroPosition,
160) -> RewriteResult {
161    let should_skip = context
162        .skip_context
163        .macros
164        .skip(context.snippet(mac.path.span));
165    if should_skip {
166        Err(RewriteError::SkipFormatting)
167    } else {
168        let guard = context.enter_macro();
169        let result = catch_unwind(AssertUnwindSafe(|| {
170            rewrite_macro_inner(mac, context, shape, position, guard.is_nested())
171        }));
172        match result {
173            Err(..) => {
174                context.macro_rewrite_failure.replace(true);
175                Err(RewriteError::MacroFailure {
176                    kind: MacroErrorKind::Unknown,
177                    span: mac.span(),
178                })
179            }
180            Ok(Err(e)) => {
181                context.macro_rewrite_failure.replace(true);
182                Err(e)
183            }
184            Ok(rw) => rw,
185        }
186    }
187}
188
189fn rewrite_macro_inner(
190    mac: &ast::MacCall,
191    context: &RewriteContext<'_>,
192    shape: Shape,
193    position: MacroPosition,
194    is_nested_macro: bool,
195) -> RewriteResult {
196    if context.config.use_try_shorthand() {
197        if let Some(expr) = convert_try_mac(mac, context) {
198            context.leave_macro();
199            return expr.rewrite_result(context, shape);
200        }
201    }
202
203    let original_style = macro_style(mac, context);
204
205    let macro_name = rewrite_macro_name(context, &mac.path);
206    let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&&macro_name[..]);
207
208    let style = if is_forced_bracket && !is_nested_macro {
209        Delimiter::Bracket
210    } else {
211        original_style
212    };
213
214    let ts = mac.args.tokens.clone();
215    let has_comment = contains_comment(context.snippet(mac.span()));
216    if ts.is_empty() && !has_comment {
217        return match style {
218            Delimiter::Parenthesis if position == MacroPosition::Item => {
219                Ok(format!("{macro_name}();"))
220            }
221            Delimiter::Bracket if position == MacroPosition::Item => Ok(format!("{macro_name}[];")),
222            Delimiter::Parenthesis => Ok(format!("{macro_name}()")),
223            Delimiter::Bracket => Ok(format!("{macro_name}[]")),
224            Delimiter::Brace => Ok(format!("{macro_name} {{}}")),
225            _ => unreachable!(),
226        };
227    }
228    // Format well-known macros which cannot be parsed as a valid AST.
229    if macro_name == "lazy_static!" && !has_comment {
230        match format_lazy_static(context, shape, ts.clone(), mac.span()) {
231            Ok(rw) => return Ok(rw),
232            Err(err) => match err {
233                // We will move on to parsing macro args just like other macros
234                // if we could not parse lazy_static! with known syntax
235                RewriteError::MacroFailure { kind, span: _ }
236                    if kind == MacroErrorKind::ParseFailure => {}
237                // If formatting fails even though parsing succeeds, return the err early
238                _ => return Err(err),
239            },
240        }
241    }
242
243    let ParsedMacroArgs {
244        args: arg_vec,
245        vec_with_semi,
246        trailing_comma,
247    } = match parse_macro_args(context, ts, style, is_forced_bracket) {
248        Some(args) => args,
249        None => {
250            return return_macro_parse_failure_fallback(
251                context,
252                shape.indent,
253                position,
254                mac.span(),
255            );
256        }
257    };
258
259    if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) {
260        return rewrite_macro_with_items(
261            context,
262            &arg_vec,
263            &macro_name,
264            shape,
265            style,
266            original_style,
267            position,
268            mac.span(),
269        );
270    }
271
272    match style {
273        Delimiter::Parenthesis => {
274            // Handle special case: `vec!(expr; expr)`
275            if vec_with_semi {
276                handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
277            } else {
278                // Format macro invocation as function call, preserve the trailing
279                // comma because not all macros support them.
280                overflow::rewrite_with_parens(
281                    context,
282                    &macro_name,
283                    arg_vec.iter(),
284                    shape,
285                    mac.span(),
286                    context.config.fn_call_width(),
287                    if trailing_comma {
288                        Some(SeparatorTactic::Always)
289                    } else {
290                        Some(SeparatorTactic::Never)
291                    },
292                )
293                .map(|rw| match position {
294                    MacroPosition::Item => format!("{};", rw),
295                    _ => rw,
296                })
297            }
298        }
299        Delimiter::Bracket => {
300            // Handle special case: `vec![expr; expr]`
301            if vec_with_semi {
302                handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
303            } else {
304                // If we are rewriting `vec!` macro or other special macros,
305                // then we can rewrite this as a usual array literal.
306                // Otherwise, we must preserve the original existence of trailing comma.
307                let mut force_trailing_comma = if trailing_comma {
308                    Some(SeparatorTactic::Always)
309                } else {
310                    Some(SeparatorTactic::Never)
311                };
312                if is_forced_bracket && !is_nested_macro {
313                    context.leave_macro();
314                    if context.use_block_indent() {
315                        force_trailing_comma = Some(SeparatorTactic::Vertical);
316                    };
317                }
318                let rewrite = rewrite_array(
319                    &macro_name,
320                    arg_vec.iter(),
321                    mac.span(),
322                    context,
323                    shape,
324                    force_trailing_comma,
325                    Some(original_style),
326                )?;
327                let comma = match position {
328                    MacroPosition::Item => ";",
329                    _ => "",
330                };
331
332                Ok(format!("{rewrite}{comma}"))
333            }
334        }
335        Delimiter::Brace => {
336            // For macro invocations with braces, always put a space between
337            // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
338            // anything in between the braces (for now).
339            let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
340            match trim_left_preserve_layout(snippet, shape.indent, context.config) {
341                Some(macro_body) => Ok(format!("{macro_name} {macro_body}")),
342                None => Ok(format!("{macro_name} {snippet}")),
343            }
344        }
345        _ => unreachable!(),
346    }
347}
348
349fn handle_vec_semi(
350    context: &RewriteContext<'_>,
351    shape: Shape,
352    arg_vec: Vec<MacroArg>,
353    macro_name: String,
354    delim_token: Delimiter,
355    span: Span,
356) -> RewriteResult {
357    let (left, right) = match delim_token {
358        Delimiter::Parenthesis => ("(", ")"),
359        Delimiter::Bracket => ("[", "]"),
360        _ => unreachable!(),
361    };
362
363    // Should we return MaxWidthError, Or Macro failure
364    let mac_shape = shape
365        .offset_left(macro_name.len())
366        .max_width_error(shape.width, span)?;
367    // 8 = `vec![]` + `; ` or `vec!()` + `; `
368    let total_overhead = 8;
369    let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
370    let lhs = arg_vec[0].rewrite_result(context, nested_shape)?;
371    let rhs = arg_vec[1].rewrite_result(context, nested_shape)?;
372    if !lhs.contains('\n')
373        && !rhs.contains('\n')
374        && lhs.len() + rhs.len() + total_overhead <= shape.width
375    {
376        // macro_name(lhs; rhs) or macro_name[lhs; rhs]
377        Ok(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
378    } else {
379        // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
380        Ok(format!(
381            "{}{}{}{};{}{}{}{}",
382            macro_name,
383            left,
384            nested_shape.indent.to_string_with_newline(context.config),
385            lhs,
386            nested_shape.indent.to_string_with_newline(context.config),
387            rhs,
388            shape.indent.to_string_with_newline(context.config),
389            right
390        ))
391    }
392}
393
394fn rewrite_empty_macro_def_body(
395    context: &RewriteContext<'_>,
396    span: Span,
397    shape: Shape,
398) -> RewriteResult {
399    // Create an empty, dummy `ast::Block` representing an empty macro body
400    let block = ast::Block {
401        stmts: vec![].into(),
402        id: rustc_ast::node_id::DUMMY_NODE_ID,
403        rules: ast::BlockCheckMode::Default,
404        span,
405        tokens: None,
406    };
407    block.rewrite_result(context, shape)
408}
409
410pub(crate) fn rewrite_macro_def(
411    context: &RewriteContext<'_>,
412    shape: Shape,
413    indent: Indent,
414    def: &ast::MacroDef,
415    ident: Ident,
416    vis: &ast::Visibility,
417    span: Span,
418) -> RewriteResult {
419    let snippet = Ok(remove_trailing_white_spaces(context.snippet(span)));
420    if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
421        return snippet;
422    }
423
424    let ts = def.body.tokens.clone();
425    let mut parser = MacroParser::new(ts.iter());
426    let parsed_def = match parser.parse() {
427        Some(def) => def,
428        None => return snippet,
429    };
430
431    let mut result = if def.macro_rules {
432        String::from("macro_rules!")
433    } else {
434        format!("{}macro", format_visibility(context, vis))
435    };
436
437    result += " ";
438    result += rewrite_ident(context, ident);
439
440    let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
441
442    let arm_shape = if multi_branch_style {
443        shape
444            .block_indent(context.config.tab_spaces())
445            .with_max_width(context.config)
446    } else {
447        shape
448    };
449
450    if parsed_def.branches.len() == 0 {
451        let lo = context.snippet_provider.span_before(span, "{");
452        result += " ";
453        result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
454        return Ok(result);
455    }
456
457    let branch_items = itemize_list(
458        context.snippet_provider,
459        parsed_def.branches.iter(),
460        "}",
461        ";",
462        |branch| branch.span.lo(),
463        |branch| branch.span.hi(),
464        |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
465            Ok(v) => Ok(v),
466            // if the rewrite returned None because a macro could not be rewritten, then return the
467            // original body
468            // TODO(ding-young) report rewrite error even if we return Ok with original snippet
469            Err(_) if context.macro_rewrite_failure.get() => {
470                Ok(context.snippet(branch.body).trim().to_string())
471            }
472            Err(e) => Err(e),
473        },
474        context.snippet_provider.span_after(span, "{"),
475        span.hi(),
476        false,
477    )
478    .collect::<Vec<_>>();
479
480    let fmt = ListFormatting::new(arm_shape, context.config)
481        .separator(if def.macro_rules { ";" } else { "" })
482        .trailing_separator(SeparatorTactic::Always)
483        .preserve_newline(true);
484
485    if multi_branch_style {
486        result += " {";
487        result += &arm_shape.indent.to_string_with_newline(context.config);
488    }
489
490    match write_list(&branch_items, &fmt) {
491        Ok(ref s) => result += s,
492        Err(_) => return snippet,
493    }
494
495    if multi_branch_style {
496        result += &indent.to_string_with_newline(context.config);
497        result += "}";
498    }
499
500    Ok(result)
501}
502
503fn register_metavariable(
504    map: &mut HashMap<String, String>,
505    result: &mut String,
506    name: &str,
507    dollar_count: usize,
508) {
509    let mut new_name = "$".repeat(dollar_count - 1);
510    let mut old_name = "$".repeat(dollar_count);
511
512    new_name.push('z');
513    new_name.push_str(name);
514    old_name.push_str(name);
515
516    result.push_str(&new_name);
517    map.insert(old_name, new_name);
518}
519
520// Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
521// aren't causing problems.
522// This should also work for escaped `$` variables, where we leave earlier `$`s.
523fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
524    // Each substitution will require five or six extra bytes.
525    let mut result = String::with_capacity(input.len() + 64);
526    let mut substs = HashMap::new();
527    let mut dollar_count = 0;
528    let mut cur_name = String::new();
529
530    for (kind, c) in CharClasses::new(input.chars()) {
531        if kind != FullCodeCharKind::Normal {
532            result.push(c);
533        } else if c == '$' {
534            dollar_count += 1;
535        } else if dollar_count == 0 {
536            result.push(c);
537        } else if !c.is_alphanumeric() && !cur_name.is_empty() {
538            // Terminates a name following one or more dollars.
539            register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
540
541            result.push(c);
542            dollar_count = 0;
543            cur_name.clear();
544        } else if c == '(' && cur_name.is_empty() {
545            // FIXME: Support macro def with repeat.
546            return None;
547        } else if c.is_alphanumeric() || c == '_' {
548            cur_name.push(c);
549        }
550    }
551
552    if !cur_name.is_empty() {
553        register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
554    }
555
556    debug!("replace_names `{}` {:?}", result, substs);
557
558    Some((result, substs))
559}
560
561#[derive(Debug, Clone)]
562enum MacroArgKind {
563    /// e.g., `$x: expr`.
564    MetaVariable(Symbol, String),
565    /// e.g., `$($foo: expr),*`
566    Repeat(
567        /// `()`, `[]` or `{}`.
568        Delimiter,
569        /// Inner arguments inside delimiters.
570        Vec<ParsedMacroArg>,
571        /// Something after the closing delimiter and the repeat token, if available.
572        Option<Box<ParsedMacroArg>>,
573        /// The repeat token. This could be one of `*`, `+` or `?`.
574        Token,
575    ),
576    /// e.g., `[derive(Debug)]`
577    Delimited(Delimiter, Vec<ParsedMacroArg>),
578    /// A possible separator. e.g., `,` or `;`.
579    Separator(String, String),
580    /// Other random stuff that does not fit to other kinds.
581    /// e.g., `== foo` in `($x: expr == foo)`.
582    Other(String, String),
583}
584
585fn delim_token_to_str(
586    context: &RewriteContext<'_>,
587    delim_token: Delimiter,
588    shape: Shape,
589    use_multiple_lines: bool,
590    inner_is_empty: bool,
591) -> (String, String) {
592    let (lhs, rhs) = match delim_token {
593        Delimiter::Parenthesis => ("(", ")"),
594        Delimiter::Bracket => ("[", "]"),
595        Delimiter::Brace => {
596            if inner_is_empty || use_multiple_lines {
597                ("{", "}")
598            } else {
599                ("{ ", " }")
600            }
601        }
602        Delimiter::Invisible(_) => unreachable!(),
603    };
604    if use_multiple_lines {
605        let indent_str = shape.indent.to_string_with_newline(context.config);
606        let nested_indent_str = shape
607            .indent
608            .block_indent(context.config)
609            .to_string_with_newline(context.config);
610        (
611            format!("{lhs}{nested_indent_str}"),
612            format!("{indent_str}{rhs}"),
613        )
614    } else {
615        (lhs.to_owned(), rhs.to_owned())
616    }
617}
618
619impl MacroArgKind {
620    fn starts_with_brace(&self) -> bool {
621        matches!(
622            *self,
623            MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
624                | MacroArgKind::Delimited(Delimiter::Brace, _)
625        )
626    }
627
628    fn starts_with_dollar(&self) -> bool {
629        matches!(
630            *self,
631            MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
632        )
633    }
634
635    fn ends_with_space(&self) -> bool {
636        matches!(*self, MacroArgKind::Separator(..))
637    }
638
639    fn has_meta_var(&self) -> bool {
640        match *self {
641            MacroArgKind::MetaVariable(..) => true,
642            MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
643            _ => false,
644        }
645    }
646
647    fn rewrite(
648        &self,
649        context: &RewriteContext<'_>,
650        shape: Shape,
651        use_multiple_lines: bool,
652    ) -> RewriteResult {
653        type DelimitedArgsRewrite = Result<(String, String, String), RewriteError>;
654        let rewrite_delimited_inner = |delim_tok, args| -> DelimitedArgsRewrite {
655            let inner = wrap_macro_args(context, args, shape)?;
656            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
657            if lhs.len() + inner.len() + rhs.len() <= shape.width {
658                return Ok((lhs, inner, rhs));
659            }
660
661            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
662            let nested_shape = shape
663                .block_indent(context.config.tab_spaces())
664                .with_max_width(context.config);
665            let inner = wrap_macro_args(context, args, nested_shape)?;
666            Ok((lhs, inner, rhs))
667        };
668
669        match *self {
670            MacroArgKind::MetaVariable(ty, ref name) => Ok(format!("${name}:{ty}")),
671            MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
672                let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
673                let another = another
674                    .as_ref()
675                    .and_then(|a| a.rewrite(context, shape, use_multiple_lines).ok())
676                    .unwrap_or_else(|| "".to_owned());
677                let repeat_tok = pprust::token_to_string(tok);
678
679                Ok(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
680            }
681            MacroArgKind::Delimited(delim_tok, ref args) => {
682                rewrite_delimited_inner(delim_tok, args)
683                    .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
684            }
685            MacroArgKind::Separator(ref sep, ref prefix) => Ok(format!("{prefix}{sep} ")),
686            MacroArgKind::Other(ref inner, ref prefix) => Ok(format!("{prefix}{inner}")),
687        }
688    }
689}
690
691#[derive(Debug, Clone)]
692struct ParsedMacroArg {
693    kind: MacroArgKind,
694}
695
696impl ParsedMacroArg {
697    fn rewrite(
698        &self,
699        context: &RewriteContext<'_>,
700        shape: Shape,
701        use_multiple_lines: bool,
702    ) -> RewriteResult {
703        self.kind.rewrite(context, shape, use_multiple_lines)
704    }
705}
706
707/// Parses macro arguments on macro def.
708struct MacroArgParser {
709    /// Either a name of the next metavariable, a separator, or junk.
710    buf: String,
711    /// The first token of the current buffer.
712    start_tok: Token,
713    /// `true` if we are parsing a metavariable or a repeat.
714    is_meta_var: bool,
715    /// The last token parsed.
716    last_tok: Token,
717    /// Holds the parsed arguments.
718    result: Vec<ParsedMacroArg>,
719}
720
721fn last_tok(tt: &TokenTree) -> Token {
722    match *tt {
723        TokenTree::Token(ref t, _) => t.clone(),
724        TokenTree::Delimited(delim_span, _, delim, _) => Token {
725            kind: delim.as_open_token_kind(),
726            span: delim_span.close,
727        },
728    }
729}
730
731impl MacroArgParser {
732    fn new() -> MacroArgParser {
733        MacroArgParser {
734            buf: String::new(),
735            is_meta_var: false,
736            last_tok: Token {
737                kind: TokenKind::Eof,
738                span: DUMMY_SP,
739            },
740            start_tok: Token {
741                kind: TokenKind::Eof,
742                span: DUMMY_SP,
743            },
744            result: vec![],
745        }
746    }
747
748    fn set_last_tok(&mut self, tok: &TokenTree) {
749        self.last_tok = last_tok(tok);
750    }
751
752    fn add_separator(&mut self) {
753        let prefix = if self.need_space_prefix() {
754            " ".to_owned()
755        } else {
756            "".to_owned()
757        };
758        self.result.push(ParsedMacroArg {
759            kind: MacroArgKind::Separator(self.buf.clone(), prefix),
760        });
761        self.buf.clear();
762    }
763
764    fn add_other(&mut self) {
765        let prefix = if self.need_space_prefix() {
766            " ".to_owned()
767        } else {
768            "".to_owned()
769        };
770        self.result.push(ParsedMacroArg {
771            kind: MacroArgKind::Other(self.buf.clone(), prefix),
772        });
773        self.buf.clear();
774    }
775
776    fn add_meta_variable(&mut self, iter: &mut TokenStreamIter<'_>) -> Option<()> {
777        match iter.next() {
778            Some(&TokenTree::Token(
779                Token {
780                    kind: TokenKind::Ident(name, _),
781                    ..
782                },
783                _,
784            )) => {
785                self.result.push(ParsedMacroArg {
786                    kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
787                });
788
789                self.buf.clear();
790                self.is_meta_var = false;
791                Some(())
792            }
793            _ => None,
794        }
795    }
796
797    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
798        self.result.push(ParsedMacroArg {
799            kind: MacroArgKind::Delimited(delim, inner),
800        });
801    }
802
803    // $($foo: expr),?
804    fn add_repeat(
805        &mut self,
806        inner: Vec<ParsedMacroArg>,
807        delim: Delimiter,
808        iter: &mut TokenStreamIter<'_>,
809    ) -> Option<()> {
810        let mut buffer = String::new();
811        let mut first = true;
812
813        // Parse '*', '+' or '?.
814        for tok in iter {
815            self.set_last_tok(&tok);
816            if first {
817                first = false;
818            }
819
820            match tok {
821                TokenTree::Token(
822                    Token {
823                        kind: TokenKind::Plus,
824                        ..
825                    },
826                    _,
827                )
828                | TokenTree::Token(
829                    Token {
830                        kind: TokenKind::Question,
831                        ..
832                    },
833                    _,
834                )
835                | TokenTree::Token(
836                    Token {
837                        kind: TokenKind::Star,
838                        ..
839                    },
840                    _,
841                ) => {
842                    break;
843                }
844                TokenTree::Token(ref t, _) => {
845                    buffer.push_str(&pprust::token_to_string(t));
846                }
847                _ => return None,
848            }
849        }
850
851        // There could be some random stuff between ')' and '*', '+' or '?'.
852        let another = if buffer.trim().is_empty() {
853            None
854        } else {
855            Some(Box::new(ParsedMacroArg {
856                kind: MacroArgKind::Other(buffer, "".to_owned()),
857            }))
858        };
859
860        self.result.push(ParsedMacroArg {
861            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok),
862        });
863        Some(())
864    }
865
866    fn update_buffer(&mut self, t: Token) {
867        if self.buf.is_empty() {
868            self.start_tok = t;
869        } else {
870            let needs_space = match next_space(&self.last_tok.kind) {
871                SpaceState::Ident => ident_like(&t),
872                SpaceState::Punctuation => !ident_like(&t),
873                SpaceState::Always => true,
874                SpaceState::Never => false,
875            };
876            if force_space_before(&t.kind) || needs_space {
877                self.buf.push(' ');
878            }
879        }
880
881        self.buf.push_str(&pprust::token_to_string(&t));
882    }
883
884    fn need_space_prefix(&self) -> bool {
885        if self.result.is_empty() {
886            return false;
887        }
888
889        let last_arg = self.result.last().unwrap();
890        if let MacroArgKind::MetaVariable(..) = last_arg.kind {
891            if ident_like(&self.start_tok) {
892                return true;
893            }
894            if self.start_tok.kind == TokenKind::Colon {
895                return true;
896            }
897        }
898
899        if force_space_before(&self.start_tok.kind) {
900            return true;
901        }
902
903        false
904    }
905
906    /// Returns a collection of parsed macro def's arguments.
907    fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
908        let mut iter = tokens.iter();
909
910        while let Some(tok) = iter.next() {
911            match tok {
912                &TokenTree::Token(
913                    Token {
914                        kind: TokenKind::Dollar,
915                        span,
916                    },
917                    _,
918                ) => {
919                    // We always want to add a separator before meta variables.
920                    if !self.buf.is_empty() {
921                        self.add_separator();
922                    }
923
924                    // Start keeping the name of this metavariable in the buffer.
925                    self.is_meta_var = true;
926                    self.start_tok = Token {
927                        kind: TokenKind::Dollar,
928                        span,
929                    };
930                }
931                TokenTree::Token(
932                    Token {
933                        kind: TokenKind::Colon,
934                        ..
935                    },
936                    _,
937                ) if self.is_meta_var => {
938                    self.add_meta_variable(&mut iter)?;
939                }
940                &TokenTree::Token(t, _) => self.update_buffer(t),
941                &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => {
942                    if !self.buf.is_empty() {
943                        if next_space(&self.last_tok.kind) == SpaceState::Always {
944                            self.add_separator();
945                        } else {
946                            self.add_other();
947                        }
948                    }
949
950                    // Parse the stuff inside delimiters.
951                    let parser = MacroArgParser::new();
952                    let delimited_arg = parser.parse(tts.clone())?;
953
954                    if self.is_meta_var {
955                        self.add_repeat(delimited_arg, delimited, &mut iter)?;
956                        self.is_meta_var = false;
957                    } else {
958                        self.add_delimited(delimited_arg, delimited);
959                    }
960                }
961            }
962
963            self.set_last_tok(&tok);
964        }
965
966        // We are left with some stuff in the buffer. Since there is nothing
967        // left to separate, add this as `Other`.
968        if !self.buf.is_empty() {
969            self.add_other();
970        }
971
972        Some(self.result)
973    }
974}
975
976fn wrap_macro_args(
977    context: &RewriteContext<'_>,
978    args: &[ParsedMacroArg],
979    shape: Shape,
980) -> RewriteResult {
981    wrap_macro_args_inner(context, args, shape, false)
982        .or_else(|_| wrap_macro_args_inner(context, args, shape, true))
983}
984
985fn wrap_macro_args_inner(
986    context: &RewriteContext<'_>,
987    args: &[ParsedMacroArg],
988    shape: Shape,
989    use_multiple_lines: bool,
990) -> RewriteResult {
991    let mut result = String::with_capacity(128);
992    let mut iter = args.iter().peekable();
993    let indent_str = shape.indent.to_string_with_newline(context.config);
994
995    while let Some(arg) = iter.next() {
996        result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
997
998        if use_multiple_lines
999            && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
1000        {
1001            if arg.kind.ends_with_space() {
1002                result.pop();
1003            }
1004            result.push_str(&indent_str);
1005        } else if let Some(next_arg) = iter.peek() {
1006            let space_before_dollar =
1007                !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
1008            let space_before_brace = next_arg.kind.starts_with_brace();
1009            if space_before_dollar || space_before_brace {
1010                result.push(' ');
1011            }
1012        }
1013    }
1014
1015    if !use_multiple_lines && result.len() >= shape.width {
1016        Err(RewriteError::Unknown)
1017    } else {
1018        Ok(result)
1019    }
1020}
1021
1022// This is a bit sketchy. The token rules probably need tweaking, but it works
1023// for some common cases. I hope the basic logic is sufficient. Note that the
1024// meaning of some tokens is a bit different here from usual Rust, e.g., `*`
1025// and `(`/`)` have special meaning.
1026fn format_macro_args(
1027    context: &RewriteContext<'_>,
1028    token_stream: TokenStream,
1029    shape: Shape,
1030) -> RewriteResult {
1031    let span = span_for_token_stream(&token_stream);
1032    if !context.config.format_macro_matchers() {
1033        return Ok(match span {
1034            Some(span) => context.snippet(span).to_owned(),
1035            None => String::new(),
1036        });
1037    }
1038    let parsed_args = MacroArgParser::new()
1039        .parse(token_stream)
1040        .macro_error(MacroErrorKind::ParseFailure, span.unwrap())?;
1041    wrap_macro_args(context, &parsed_args, shape)
1042}
1043
1044fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
1045    token_stream.iter().next().map(|tt| tt.span())
1046}
1047
1048// We should insert a space if the next token is a:
1049#[derive(Copy, Clone, PartialEq)]
1050enum SpaceState {
1051    Never,
1052    Punctuation,
1053    Ident, // Or ident/literal-like thing.
1054    Always,
1055}
1056
1057fn force_space_before(tok: &TokenKind) -> bool {
1058    debug!("tok: force_space_before {:?}", tok);
1059
1060    match tok {
1061        TokenKind::Eq
1062        | TokenKind::Lt
1063        | TokenKind::Le
1064        | TokenKind::EqEq
1065        | TokenKind::Ne
1066        | TokenKind::Ge
1067        | TokenKind::Gt
1068        | TokenKind::AndAnd
1069        | TokenKind::OrOr
1070        | TokenKind::Bang
1071        | TokenKind::Tilde
1072        | TokenKind::PlusEq
1073        | TokenKind::MinusEq
1074        | TokenKind::StarEq
1075        | TokenKind::SlashEq
1076        | TokenKind::PercentEq
1077        | TokenKind::CaretEq
1078        | TokenKind::AndEq
1079        | TokenKind::OrEq
1080        | TokenKind::ShlEq
1081        | TokenKind::ShrEq
1082        | TokenKind::At
1083        | TokenKind::RArrow
1084        | TokenKind::LArrow
1085        | TokenKind::FatArrow
1086        | TokenKind::Plus
1087        | TokenKind::Minus
1088        | TokenKind::Star
1089        | TokenKind::Slash
1090        | TokenKind::Percent
1091        | TokenKind::Caret
1092        | TokenKind::And
1093        | TokenKind::Or
1094        | TokenKind::Shl
1095        | TokenKind::Shr
1096        | TokenKind::Pound
1097        | TokenKind::Dollar => true,
1098        _ => false,
1099    }
1100}
1101
1102fn ident_like(tok: &Token) -> bool {
1103    matches!(
1104        tok.kind,
1105        TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(..)
1106    )
1107}
1108
1109fn next_space(tok: &TokenKind) -> SpaceState {
1110    debug!("next_space: {:?}", tok);
1111
1112    match tok {
1113        TokenKind::Bang
1114        | TokenKind::And
1115        | TokenKind::Tilde
1116        | TokenKind::At
1117        | TokenKind::Comma
1118        | TokenKind::Dot
1119        | TokenKind::DotDot
1120        | TokenKind::DotDotDot
1121        | TokenKind::DotDotEq
1122        | TokenKind::Question => SpaceState::Punctuation,
1123
1124        TokenKind::PathSep
1125        | TokenKind::Pound
1126        | TokenKind::Dollar
1127        | TokenKind::OpenParen
1128        | TokenKind::CloseParen
1129        | TokenKind::OpenBrace
1130        | TokenKind::CloseBrace
1131        | TokenKind::OpenBracket
1132        | TokenKind::CloseBracket
1133        | TokenKind::OpenInvisible(_)
1134        | TokenKind::CloseInvisible(_) => SpaceState::Never,
1135
1136        TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => {
1137            SpaceState::Ident
1138        }
1139
1140        _ => SpaceState::Always,
1141    }
1142}
1143
1144/// Tries to convert a macro use into a short hand try expression. Returns `None`
1145/// when the macro is not an instance of `try!` (or parsing the inner expression
1146/// failed).
1147pub(crate) fn convert_try_mac(
1148    mac: &ast::MacCall,
1149    context: &RewriteContext<'_>,
1150) -> Option<ast::Expr> {
1151    let path = &pprust::path_to_string(&mac.path);
1152    if path == "try" || path == "r#try" {
1153        let ts = mac.args.tokens.clone();
1154
1155        Some(ast::Expr {
1156            id: ast::NodeId::root(), // dummy value
1157            kind: ast::ExprKind::Try(parse_expr(context, ts)?),
1158            span: mac.span(), // incorrect span, but shouldn't matter too much
1159            attrs: ast::AttrVec::new(),
1160            tokens: None,
1161        })
1162    } else {
1163        None
1164    }
1165}
1166
1167pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
1168    let snippet = context.snippet(mac.span());
1169    let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::MAX);
1170    let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::MAX);
1171    let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::MAX);
1172
1173    if paren_pos < bracket_pos && paren_pos < brace_pos {
1174        Delimiter::Parenthesis
1175    } else if bracket_pos < brace_pos {
1176        Delimiter::Bracket
1177    } else {
1178        Delimiter::Brace
1179    }
1180}
1181
1182// A very simple parser that just parses a macros 2.0 definition into its branches.
1183// Currently we do not attempt to parse any further than that.
1184struct MacroParser<'a> {
1185    iter: TokenStreamIter<'a>,
1186}
1187
1188impl<'a> MacroParser<'a> {
1189    const fn new(iter: TokenStreamIter<'a>) -> Self {
1190        Self { iter }
1191    }
1192
1193    // (`(` ... `)` `=>` `{` ... `}`)*
1194    fn parse(&mut self) -> Option<Macro> {
1195        let mut branches = vec![];
1196        while self.iter.peek().is_some() {
1197            branches.push(self.parse_branch()?);
1198        }
1199
1200        Some(Macro { branches })
1201    }
1202
1203    // `(` ... `)` `=>` `{` ... `}`
1204    fn parse_branch(&mut self) -> Option<MacroBranch> {
1205        let tok = self.iter.next()?;
1206        let (lo, args_paren_kind) = match tok {
1207            TokenTree::Token(..) => return None,
1208            &TokenTree::Delimited(delimited_span, _, d, _) => (delimited_span.open.lo(), d),
1209        };
1210        let args = TokenStream::new(vec![tok.clone()]);
1211        match self.iter.next()? {
1212            TokenTree::Token(
1213                Token {
1214                    kind: TokenKind::FatArrow,
1215                    ..
1216                },
1217                _,
1218            ) => {}
1219            _ => return None,
1220        }
1221        let (mut hi, body, whole_body) = match self.iter.next()? {
1222            TokenTree::Token(..) => return None,
1223            TokenTree::Delimited(delimited_span, ..) => {
1224                let data = delimited_span.entire().data();
1225                (
1226                    data.hi,
1227                    Span::new(
1228                        data.lo + BytePos(1),
1229                        data.hi - BytePos(1),
1230                        data.ctxt,
1231                        data.parent,
1232                    ),
1233                    delimited_span.entire(),
1234                )
1235            }
1236        };
1237        if let Some(TokenTree::Token(
1238            Token {
1239                kind: TokenKind::Semi,
1240                span,
1241            },
1242            _,
1243        )) = self.iter.peek()
1244        {
1245            hi = span.hi();
1246            self.iter.next();
1247        }
1248        Some(MacroBranch {
1249            span: mk_sp(lo, hi),
1250            args_paren_kind,
1251            args,
1252            body,
1253            whole_body,
1254        })
1255    }
1256}
1257
1258// A parsed macros 2.0 macro definition.
1259struct Macro {
1260    branches: Vec<MacroBranch>,
1261}
1262
1263// FIXME: it would be more efficient to use references to the token streams
1264// rather than clone them, if we can make the borrowing work out.
1265struct MacroBranch {
1266    span: Span,
1267    args_paren_kind: Delimiter,
1268    args: TokenStream,
1269    body: Span,
1270    whole_body: Span,
1271}
1272
1273impl MacroBranch {
1274    fn rewrite(
1275        &self,
1276        context: &RewriteContext<'_>,
1277        shape: Shape,
1278        multi_branch_style: bool,
1279    ) -> RewriteResult {
1280        // Only attempt to format function-like macros.
1281        if self.args_paren_kind != Delimiter::Parenthesis {
1282            // FIXME(#1539): implement for non-sugared macros.
1283            return Err(RewriteError::MacroFailure {
1284                kind: MacroErrorKind::Unknown,
1285                span: self.span,
1286            });
1287        }
1288
1289        let old_body = context.snippet(self.body).trim();
1290        let has_block_body = old_body.starts_with('{');
1291        let mut prefix_width = 5; // 5 = " => {"
1292        if context.config.style_edition() >= StyleEdition::Edition2024 {
1293            if has_block_body {
1294                prefix_width = 6; // 6 = " => {{"
1295            }
1296        }
1297        let mut result = format_macro_args(
1298            context,
1299            self.args.clone(),
1300            shape
1301                .sub_width(prefix_width)
1302                .max_width_error(shape.width, self.span)?,
1303        )?;
1304
1305        if multi_branch_style {
1306            result += " =>";
1307        }
1308
1309        if !context.config.format_macro_bodies() {
1310            result += " ";
1311            result += context.snippet(self.whole_body);
1312            return Ok(result);
1313        }
1314
1315        // The macro body is the most interesting part. It might end up as various
1316        // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1317        // parsed as regular Rust code (and note that these can be escaped using
1318        // `$$`). We'll try and format like an AST node, but we'll substitute
1319        // variables for new names with the same length first.
1320
1321        let (body_str, substs) =
1322            replace_names(old_body).macro_error(MacroErrorKind::ReplaceMacroVariable, self.span)?;
1323
1324        let mut config = context.config.clone();
1325        config.set().show_parse_errors(false);
1326
1327        result += " {";
1328
1329        let body_indent = if has_block_body {
1330            shape.indent
1331        } else {
1332            shape.indent.block_indent(&config)
1333        };
1334        let new_width = config.max_width() - body_indent.width();
1335        config.set().max_width(new_width);
1336
1337        // First try to format as items, then as statements.
1338        let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
1339            Some(new_body) => new_body,
1340            None => {
1341                let new_width = new_width + config.tab_spaces();
1342                config.set().max_width(new_width);
1343                match crate::format_code_block(&body_str, &config, true) {
1344                    Some(new_body) => new_body,
1345                    None => {
1346                        return Err(RewriteError::MacroFailure {
1347                            kind: MacroErrorKind::Unknown,
1348                            span: self.span,
1349                        });
1350                    }
1351                }
1352            }
1353        };
1354
1355        if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
1356            return Err(RewriteError::ExceedsMaxWidth {
1357                configured_width: shape.width,
1358                span: self.span,
1359            });
1360        }
1361
1362        // Indent the body since it is in a block.
1363        let indent_str = body_indent.to_string(&config);
1364        let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end())
1365            .enumerate()
1366            .fold(
1367                (String::new(), true),
1368                |(mut s, need_indent), (i, (kind, ref l))| {
1369                    if !is_empty_line(l)
1370                        && need_indent
1371                        && !new_body_snippet.is_line_non_formatted(i + 1)
1372                    {
1373                        s += &indent_str;
1374                    }
1375                    (s + l + "\n", indent_next_line(kind, l, &config))
1376                },
1377            )
1378            .0;
1379
1380        // Undo our replacement of macro variables.
1381        // FIXME: this could be *much* more efficient.
1382        for (old, new) in &substs {
1383            if old_body.contains(new) {
1384                debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
1385                return Err(RewriteError::MacroFailure {
1386                    kind: MacroErrorKind::ReplaceMacroVariable,
1387                    span: self.span,
1388                });
1389            }
1390            new_body = new_body.replace(new, old);
1391        }
1392
1393        if has_block_body {
1394            result += new_body.trim();
1395        } else if !new_body.is_empty() {
1396            result += "\n";
1397            result += &new_body;
1398            result += &shape.indent.to_string(&config);
1399        }
1400
1401        result += "}";
1402
1403        Ok(result)
1404    }
1405}
1406
1407/// Format `lazy_static!` from <https://crates.io/crates/lazy_static>.
1408///
1409/// # Expected syntax
1410///
1411/// ```text
1412/// lazy_static! {
1413///     [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1414///     [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1415///     ...
1416///     [pub] static ref NAME_N: TYPE_N = EXPR_N;
1417/// }
1418/// ```
1419fn format_lazy_static(
1420    context: &RewriteContext<'_>,
1421    shape: Shape,
1422    ts: TokenStream,
1423    span: Span,
1424) -> RewriteResult {
1425    let mut result = String::with_capacity(1024);
1426    let nested_shape = shape
1427        .block_indent(context.config.tab_spaces())
1428        .with_max_width(context.config);
1429
1430    result.push_str("lazy_static! {");
1431    result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1432
1433    let parsed_elems =
1434        parse_lazy_static(context, ts).macro_error(MacroErrorKind::ParseFailure, span)?;
1435    let last = parsed_elems.len() - 1;
1436    for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
1437        // Rewrite as a static item.
1438        let vis = crate::utils::format_visibility(context, vis);
1439        let mut stmt = String::with_capacity(128);
1440        stmt.push_str(&format!(
1441            "{}static ref {}: {} =",
1442            vis,
1443            id,
1444            ty.rewrite_result(context, nested_shape)?
1445        ));
1446        result.push_str(&rewrite_assign_rhs(
1447            context,
1448            stmt,
1449            &*expr,
1450            &RhsAssignKind::Expr(&expr.kind, expr.span),
1451            nested_shape
1452                .sub_width(1)
1453                .max_width_error(nested_shape.width, expr.span)?,
1454        )?);
1455        result.push(';');
1456        if i != last {
1457            result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1458        }
1459    }
1460
1461    result.push_str(&shape.indent.to_string_with_newline(context.config));
1462    result.push('}');
1463
1464    Ok(result)
1465}
1466
1467fn rewrite_macro_with_items(
1468    context: &RewriteContext<'_>,
1469    items: &[MacroArg],
1470    macro_name: &str,
1471    shape: Shape,
1472    style: Delimiter,
1473    original_style: Delimiter,
1474    position: MacroPosition,
1475    span: Span,
1476) -> RewriteResult {
1477    let style_to_delims = |style| match style {
1478        Delimiter::Parenthesis => Ok(("(", ")")),
1479        Delimiter::Bracket => Ok(("[", "]")),
1480        Delimiter::Brace => Ok((" {", "}")),
1481        _ => Err(RewriteError::Unknown),
1482    };
1483
1484    let (opener, closer) = style_to_delims(style)?;
1485    let (original_opener, _) = style_to_delims(original_style)?;
1486    let trailing_semicolon = match style {
1487        Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
1488        _ => "",
1489    };
1490
1491    let mut visitor = FmtVisitor::from_context(context);
1492    visitor.block_indent = shape.indent.block_indent(context.config);
1493
1494    // The current opener may be different from the original opener. This can happen
1495    // if our macro is a forced bracket macro originally written with non-bracket
1496    // delimiters. We need to use the original opener to locate the span after it.
1497    visitor.last_pos = context
1498        .snippet_provider
1499        .span_after(span, original_opener.trim());
1500    for item in items {
1501        let item = match item {
1502            MacroArg::Item(item) => item,
1503            _ => return Err(RewriteError::Unknown),
1504        };
1505        visitor.visit_item(item);
1506    }
1507
1508    let mut result = String::with_capacity(256);
1509    result.push_str(macro_name);
1510    result.push_str(opener);
1511    result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1512    result.push_str(visitor.buffer.trim());
1513    result.push_str(&shape.indent.to_string_with_newline(context.config));
1514    result.push_str(closer);
1515    result.push_str(trailing_semicolon);
1516    Ok(result)
1517}