Skip to main content

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