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        tokens: None,
408    };
409    block.rewrite_result(context, shape)
410}
411
412pub(crate) fn rewrite_macro_def(
413    context: &RewriteContext<'_>,
414    shape: Shape,
415    indent: Indent,
416    def: &ast::MacroDef,
417    ident: Ident,
418    vis: &ast::Visibility,
419    span: Span,
420) -> RewriteResult {
421    let snippet = Ok(remove_trailing_white_spaces(context.snippet(span)));
422    if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
423        return snippet;
424    }
425
426    let ts = def.body.tokens.clone();
427    let mut parser = MacroParser::new(ts.iter());
428    let parsed_def = match parser.parse() {
429        Some(def) => def,
430        None => return snippet,
431    };
432
433    let mut result = if def.macro_rules {
434        String::from("macro_rules!")
435    } else {
436        format!("{}macro", format_visibility(context, vis))
437    };
438
439    result += " ";
440    result += rewrite_ident(context, ident);
441
442    let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
443
444    let arm_shape = if multi_branch_style {
445        shape
446            .block_indent(context.config.tab_spaces())
447            .with_max_width(context.config)
448    } else {
449        shape
450    };
451
452    if parsed_def.branches.len() == 0 {
453        let lo = context.snippet_provider.span_before(span, "{");
454        result += " ";
455        result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
456        return Ok(result);
457    }
458
459    let branch_items = itemize_list(
460        context.snippet_provider,
461        parsed_def.branches.iter(),
462        "}",
463        ";",
464        |branch| branch.span.lo(),
465        |branch| branch.span.hi(),
466        |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
467            Ok(v) => Ok(v),
468            // if the rewrite returned None because a macro could not be rewritten, then return the
469            // original body
470            // TODO(ding-young) report rewrite error even if we return Ok with original snippet
471            Err(_) if context.macro_rewrite_failure.get() => {
472                Ok(context.snippet(branch.body).trim().to_string())
473            }
474            Err(e) => Err(e),
475        },
476        context.snippet_provider.span_after(span, "{"),
477        span.hi(),
478        false,
479    )
480    .collect::<Vec<_>>();
481
482    let fmt = ListFormatting::new(arm_shape, context.config)
483        .separator(if def.macro_rules { ";" } else { "" })
484        .trailing_separator(SeparatorTactic::Always)
485        .preserve_newline(true);
486
487    if multi_branch_style {
488        result += " {";
489        result += &arm_shape.indent.to_string_with_newline(context.config);
490    }
491
492    match write_list(&branch_items, &fmt) {
493        Ok(ref s) => result += s,
494        Err(_) => return snippet,
495    }
496
497    if multi_branch_style {
498        result += &indent.to_string_with_newline(context.config);
499        result += "}";
500    }
501
502    Ok(result)
503}
504
505fn register_metavariable(
506    map: &mut HashMap<String, String>,
507    result: &mut String,
508    name: &str,
509    dollar_count: usize,
510) {
511    let mut new_name = "$".repeat(dollar_count - 1);
512    let mut old_name = "$".repeat(dollar_count);
513
514    new_name.push('z');
515    new_name.push_str(name);
516    old_name.push_str(name);
517
518    result.push_str(&new_name);
519    map.insert(old_name, new_name);
520}
521
522// Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
523// aren't causing problems.
524// This should also work for escaped `$` variables, where we leave earlier `$`s.
525fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
526    // Each substitution will require five or six extra bytes.
527    let mut result = String::with_capacity(input.len() + 64);
528    let mut substs = HashMap::new();
529    let mut dollar_count = 0;
530    let mut cur_name = String::new();
531
532    for (kind, c) in CharClasses::new(input.chars()) {
533        if kind != FullCodeCharKind::Normal {
534            result.push(c);
535        } else if c == '$' {
536            dollar_count += 1;
537        } else if dollar_count == 0 {
538            result.push(c);
539        } else if !c.is_alphanumeric() && !cur_name.is_empty() {
540            // Terminates a name following one or more dollars.
541            register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
542
543            result.push(c);
544            dollar_count = 0;
545            cur_name.clear();
546        } else if c == '(' && cur_name.is_empty() {
547            // FIXME: Support macro def with repeat.
548            return None;
549        } else if c.is_alphanumeric() || c == '_' {
550            cur_name.push(c);
551        }
552    }
553
554    if !cur_name.is_empty() {
555        register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
556    }
557
558    debug!("replace_names `{}` {:?}", result, substs);
559
560    Some((result, substs))
561}
562
563#[derive(Debug, Clone)]
564enum MacroArgKind {
565    /// e.g., `$x: expr`.
566    MetaVariable(Symbol, String),
567    /// e.g., `$($foo: expr),*`
568    Repeat(
569        /// `()`, `[]` or `{}`.
570        Delimiter,
571        /// Inner arguments inside delimiters.
572        Vec<ParsedMacroArg>,
573        /// Something after the closing delimiter and the repeat token, if available.
574        Option<Box<ParsedMacroArg>>,
575        /// The repeat token. This could be one of `*`, `+` or `?`.
576        Token,
577    ),
578    /// e.g., `[derive(Debug)]`
579    Delimited(Delimiter, Vec<ParsedMacroArg>),
580    /// A possible separator. e.g., `,` or `;`.
581    Separator(String, String),
582    /// Other random stuff that does not fit to other kinds.
583    /// e.g., `== foo` in `($x: expr == foo)`.
584    Other(String, String),
585}
586
587fn delim_token_to_str(
588    context: &RewriteContext<'_>,
589    delim_token: Delimiter,
590    shape: Shape,
591    use_multiple_lines: bool,
592    inner_is_empty: bool,
593) -> (String, String) {
594    let (lhs, rhs) = match delim_token {
595        Delimiter::Parenthesis => ("(", ")"),
596        Delimiter::Bracket => ("[", "]"),
597        Delimiter::Brace => {
598            if inner_is_empty || use_multiple_lines {
599                ("{", "}")
600            } else {
601                ("{ ", " }")
602            }
603        }
604        Delimiter::Invisible(_) => unreachable!(),
605    };
606    if use_multiple_lines {
607        let indent_str = shape.indent.to_string_with_newline(context.config);
608        let nested_indent_str = shape
609            .indent
610            .block_indent(context.config)
611            .to_string_with_newline(context.config);
612        (
613            format!("{lhs}{nested_indent_str}"),
614            format!("{indent_str}{rhs}"),
615        )
616    } else {
617        (lhs.to_owned(), rhs.to_owned())
618    }
619}
620
621impl MacroArgKind {
622    fn starts_with_brace(&self) -> bool {
623        matches!(
624            *self,
625            MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
626                | MacroArgKind::Delimited(Delimiter::Brace, _)
627        )
628    }
629
630    fn starts_with_dollar(&self) -> bool {
631        matches!(
632            *self,
633            MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
634        )
635    }
636
637    fn ends_with_space(&self) -> bool {
638        matches!(*self, MacroArgKind::Separator(..))
639    }
640
641    fn has_meta_var(&self) -> bool {
642        match *self {
643            MacroArgKind::MetaVariable(..) => true,
644            MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
645            _ => false,
646        }
647    }
648
649    fn rewrite(
650        &self,
651        context: &RewriteContext<'_>,
652        shape: Shape,
653        use_multiple_lines: bool,
654    ) -> RewriteResult {
655        type DelimitedArgsRewrite = Result<(String, String, String), RewriteError>;
656        let rewrite_delimited_inner = |delim_tok, args| -> DelimitedArgsRewrite {
657            let inner = wrap_macro_args(context, args, shape)?;
658            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
659            if lhs.len() + inner.len() + rhs.len() <= shape.width {
660                return Ok((lhs, inner, rhs));
661            }
662
663            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
664            let nested_shape = shape
665                .block_indent(context.config.tab_spaces())
666                .with_max_width(context.config);
667            let inner = wrap_macro_args(context, args, nested_shape)?;
668            Ok((lhs, inner, rhs))
669        };
670
671        match *self {
672            MacroArgKind::MetaVariable(ty, ref name) => Ok(format!("${name}:{ty}")),
673            MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
674                let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
675                let another = another
676                    .as_ref()
677                    .and_then(|a| a.rewrite(context, shape, use_multiple_lines).ok())
678                    .unwrap_or_else(|| "".to_owned());
679                let repeat_tok = pprust::token_to_string(tok);
680
681                Ok(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
682            }
683            MacroArgKind::Delimited(delim_tok, ref args) => {
684                rewrite_delimited_inner(delim_tok, args)
685                    .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
686            }
687            MacroArgKind::Separator(ref sep, ref prefix) => Ok(format!("{prefix}{sep} ")),
688            MacroArgKind::Other(ref inner, ref prefix) => Ok(format!("{prefix}{inner}")),
689        }
690    }
691}
692
693#[derive(Debug, Clone)]
694struct ParsedMacroArg {
695    kind: MacroArgKind,
696}
697
698impl ParsedMacroArg {
699    fn rewrite(
700        &self,
701        context: &RewriteContext<'_>,
702        shape: Shape,
703        use_multiple_lines: bool,
704    ) -> RewriteResult {
705        self.kind.rewrite(context, shape, use_multiple_lines)
706    }
707}
708
709/// Parses macro arguments on macro def.
710struct MacroArgParser {
711    /// Either a name of the next metavariable, a separator, or junk.
712    buf: String,
713    /// The first token of the current buffer.
714    start_tok: Token,
715    /// `true` if we are parsing a metavariable or a repeat.
716    is_meta_var: bool,
717    /// The last token parsed.
718    last_tok: Token,
719    /// Holds the parsed arguments.
720    result: Vec<ParsedMacroArg>,
721}
722
723fn last_tok(tt: &TokenTree) -> Token {
724    match *tt {
725        TokenTree::Token(ref t, _) => t.clone(),
726        TokenTree::Delimited(delim_span, _, delim, _) => Token {
727            kind: delim.as_open_token_kind(),
728            span: delim_span.close,
729        },
730    }
731}
732
733impl MacroArgParser {
734    fn new() -> MacroArgParser {
735        MacroArgParser {
736            buf: String::new(),
737            is_meta_var: false,
738            last_tok: Token {
739                kind: TokenKind::Eof,
740                span: DUMMY_SP,
741            },
742            start_tok: Token {
743                kind: TokenKind::Eof,
744                span: DUMMY_SP,
745            },
746            result: vec![],
747        }
748    }
749
750    fn set_last_tok(&mut self, tok: &TokenTree) {
751        self.last_tok = last_tok(tok);
752    }
753
754    fn add_separator(&mut self) {
755        let prefix = if self.need_space_prefix() {
756            " ".to_owned()
757        } else {
758            "".to_owned()
759        };
760        self.result.push(ParsedMacroArg {
761            kind: MacroArgKind::Separator(self.buf.clone(), prefix),
762        });
763        self.buf.clear();
764    }
765
766    fn add_other(&mut self) {
767        let prefix = if self.need_space_prefix() {
768            " ".to_owned()
769        } else {
770            "".to_owned()
771        };
772        self.result.push(ParsedMacroArg {
773            kind: MacroArgKind::Other(self.buf.clone(), prefix),
774        });
775        self.buf.clear();
776    }
777
778    fn add_meta_variable(&mut self, iter: &mut TokenStreamIter<'_>) -> Option<()> {
779        match iter.next() {
780            Some(&TokenTree::Token(
781                Token {
782                    kind: TokenKind::Ident(name, _),
783                    ..
784                },
785                _,
786            )) => {
787                self.result.push(ParsedMacroArg {
788                    kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
789                });
790
791                self.buf.clear();
792                self.is_meta_var = false;
793                Some(())
794            }
795            _ => None,
796        }
797    }
798
799    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
800        self.result.push(ParsedMacroArg {
801            kind: MacroArgKind::Delimited(delim, inner),
802        });
803    }
804
805    // $($foo: expr),?
806    fn add_repeat(
807        &mut self,
808        inner: Vec<ParsedMacroArg>,
809        delim: Delimiter,
810        iter: &mut TokenStreamIter<'_>,
811    ) -> Option<()> {
812        let mut buffer = String::new();
813        let mut first = true;
814
815        // Parse '*', '+' or '?.
816        for tok in iter {
817            self.set_last_tok(&tok);
818            if first {
819                first = false;
820            }
821
822            match tok {
823                TokenTree::Token(
824                    Token {
825                        kind: TokenKind::Plus,
826                        ..
827                    },
828                    _,
829                )
830                | TokenTree::Token(
831                    Token {
832                        kind: TokenKind::Question,
833                        ..
834                    },
835                    _,
836                )
837                | TokenTree::Token(
838                    Token {
839                        kind: TokenKind::Star,
840                        ..
841                    },
842                    _,
843                ) => {
844                    break;
845                }
846                TokenTree::Token(ref t, _) => {
847                    buffer.push_str(&pprust::token_to_string(t));
848                }
849                _ => return None,
850            }
851        }
852
853        // There could be some random stuff between ')' and '*', '+' or '?'.
854        let another = if buffer.trim().is_empty() {
855            None
856        } else {
857            Some(Box::new(ParsedMacroArg {
858                kind: MacroArgKind::Other(buffer, "".to_owned()),
859            }))
860        };
861
862        self.result.push(ParsedMacroArg {
863            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok),
864        });
865        Some(())
866    }
867
868    fn update_buffer(&mut self, t: Token) {
869        if self.buf.is_empty() {
870            self.start_tok = t;
871        } else {
872            let needs_space = match next_space(&self.last_tok.kind) {
873                SpaceState::Ident => ident_like(&t),
874                SpaceState::Punctuation => !ident_like(&t),
875                SpaceState::Always => true,
876                SpaceState::Never => false,
877            };
878            if force_space_before(&t.kind) || needs_space {
879                self.buf.push(' ');
880            }
881        }
882
883        self.buf.push_str(&pprust::token_to_string(&t));
884    }
885
886    fn need_space_prefix(&self) -> bool {
887        if self.result.is_empty() {
888            return false;
889        }
890
891        let last_arg = self.result.last().unwrap();
892        if let MacroArgKind::MetaVariable(..) = last_arg.kind {
893            if ident_like(&self.start_tok) {
894                return true;
895            }
896            if self.start_tok.kind == TokenKind::Colon {
897                return true;
898            }
899        }
900
901        if force_space_before(&self.start_tok.kind) {
902            return true;
903        }
904
905        false
906    }
907
908    /// Returns a collection of parsed macro def's arguments.
909    fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
910        let mut iter = tokens.iter();
911
912        while let Some(tok) = iter.next() {
913            match tok {
914                &TokenTree::Token(
915                    Token {
916                        kind: TokenKind::Dollar,
917                        span,
918                    },
919                    _,
920                ) => {
921                    // We always want to add a separator before meta variables.
922                    if !self.buf.is_empty() {
923                        self.add_separator();
924                    }
925
926                    // Start keeping the name of this metavariable in the buffer.
927                    self.is_meta_var = true;
928                    self.start_tok = Token {
929                        kind: TokenKind::Dollar,
930                        span,
931                    };
932                }
933                TokenTree::Token(
934                    Token {
935                        kind: TokenKind::Colon,
936                        ..
937                    },
938                    _,
939                ) if self.is_meta_var => {
940                    self.add_meta_variable(&mut iter)?;
941                }
942                &TokenTree::Token(t, _) => self.update_buffer(t),
943                &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => {
944                    if !self.buf.is_empty() {
945                        if next_space(&self.last_tok.kind) == SpaceState::Always {
946                            self.add_separator();
947                        } else {
948                            self.add_other();
949                        }
950                    }
951
952                    // Parse the stuff inside delimiters.
953                    let parser = MacroArgParser::new();
954                    let delimited_arg = parser.parse(tts.clone())?;
955
956                    if self.is_meta_var {
957                        self.add_repeat(delimited_arg, delimited, &mut iter)?;
958                        self.is_meta_var = false;
959                    } else {
960                        self.add_delimited(delimited_arg, delimited);
961                    }
962                }
963            }
964
965            self.set_last_tok(&tok);
966        }
967
968        // We are left with some stuff in the buffer. Since there is nothing
969        // left to separate, add this as `Other`.
970        if !self.buf.is_empty() {
971            self.add_other();
972        }
973
974        Some(self.result)
975    }
976}
977
978fn wrap_macro_args(
979    context: &RewriteContext<'_>,
980    args: &[ParsedMacroArg],
981    shape: Shape,
982) -> RewriteResult {
983    wrap_macro_args_inner(context, args, shape, false)
984        .or_else(|_| wrap_macro_args_inner(context, args, shape, true))
985}
986
987fn wrap_macro_args_inner(
988    context: &RewriteContext<'_>,
989    args: &[ParsedMacroArg],
990    shape: Shape,
991    use_multiple_lines: bool,
992) -> RewriteResult {
993    let mut result = String::with_capacity(128);
994    let mut iter = args.iter().peekable();
995    let indent_str = shape.indent.to_string_with_newline(context.config);
996
997    while let Some(arg) = iter.next() {
998        result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
999
1000        if use_multiple_lines
1001            && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
1002        {
1003            if arg.kind.ends_with_space() {
1004                result.pop();
1005            }
1006            result.push_str(&indent_str);
1007        } else if let Some(next_arg) = iter.peek() {
1008            let space_before_dollar =
1009                !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
1010            let space_before_brace = next_arg.kind.starts_with_brace();
1011            if space_before_dollar || space_before_brace {
1012                result.push(' ');
1013            }
1014        }
1015    }
1016
1017    if !use_multiple_lines && result.len() >= shape.width {
1018        Err(RewriteError::Unknown)
1019    } else {
1020        Ok(result)
1021    }
1022}
1023
1024// This is a bit sketchy. The token rules probably need tweaking, but it works
1025// for some common cases. I hope the basic logic is sufficient. Note that the
1026// meaning of some tokens is a bit different here from usual Rust, e.g., `*`
1027// and `(`/`)` have special meaning.
1028fn format_macro_args(
1029    context: &RewriteContext<'_>,
1030    token_stream: TokenStream,
1031    shape: Shape,
1032) -> RewriteResult {
1033    let span = span_for_token_stream(&token_stream);
1034    if !context.config.format_macro_matchers() {
1035        return Ok(match span {
1036            Some(span) => context.snippet(span).to_owned(),
1037            None => String::new(),
1038        });
1039    }
1040    let parsed_args = MacroArgParser::new()
1041        .parse(token_stream)
1042        .macro_error(MacroErrorKind::ParseFailure, span.unwrap())?;
1043    wrap_macro_args(context, &parsed_args, shape)
1044}
1045
1046fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
1047    token_stream.iter().next().map(|tt| tt.span())
1048}
1049
1050// We should insert a space if the next token is a:
1051#[derive(Copy, Clone, PartialEq)]
1052enum SpaceState {
1053    Never,
1054    Punctuation,
1055    Ident, // Or ident/literal-like thing.
1056    Always,
1057}
1058
1059fn force_space_before(tok: &TokenKind) -> bool {
1060    debug!("tok: force_space_before {:?}", tok);
1061
1062    match tok {
1063        TokenKind::Eq
1064        | TokenKind::Lt
1065        | TokenKind::Le
1066        | TokenKind::EqEq
1067        | TokenKind::Ne
1068        | TokenKind::Ge
1069        | TokenKind::Gt
1070        | TokenKind::AndAnd
1071        | TokenKind::OrOr
1072        | TokenKind::Bang
1073        | TokenKind::Tilde
1074        | TokenKind::PlusEq
1075        | TokenKind::MinusEq
1076        | TokenKind::StarEq
1077        | TokenKind::SlashEq
1078        | TokenKind::PercentEq
1079        | TokenKind::CaretEq
1080        | TokenKind::AndEq
1081        | TokenKind::OrEq
1082        | TokenKind::ShlEq
1083        | TokenKind::ShrEq
1084        | TokenKind::At
1085        | TokenKind::RArrow
1086        | TokenKind::LArrow
1087        | TokenKind::FatArrow
1088        | TokenKind::Plus
1089        | TokenKind::Minus
1090        | TokenKind::Star
1091        | TokenKind::Slash
1092        | TokenKind::Percent
1093        | TokenKind::Caret
1094        | TokenKind::And
1095        | TokenKind::Or
1096        | TokenKind::Shl
1097        | TokenKind::Shr
1098        | TokenKind::Pound
1099        | TokenKind::Dollar => true,
1100        _ => false,
1101    }
1102}
1103
1104fn ident_like(tok: &Token) -> bool {
1105    matches!(
1106        tok.kind,
1107        TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(..)
1108    )
1109}
1110
1111fn next_space(tok: &TokenKind) -> SpaceState {
1112    debug!("next_space: {:?}", tok);
1113
1114    match tok {
1115        TokenKind::Bang
1116        | TokenKind::And
1117        | TokenKind::Tilde
1118        | TokenKind::At
1119        | TokenKind::Comma
1120        | TokenKind::Dot
1121        | TokenKind::DotDot
1122        | TokenKind::DotDotDot
1123        | TokenKind::DotDotEq
1124        | TokenKind::Question => SpaceState::Punctuation,
1125
1126        TokenKind::PathSep
1127        | TokenKind::Pound
1128        | TokenKind::Dollar
1129        | TokenKind::OpenParen
1130        | TokenKind::CloseParen
1131        | TokenKind::OpenBrace
1132        | TokenKind::CloseBrace
1133        | TokenKind::OpenBracket
1134        | TokenKind::CloseBracket
1135        | TokenKind::OpenInvisible(_)
1136        | TokenKind::CloseInvisible(_) => SpaceState::Never,
1137
1138        TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => {
1139            SpaceState::Ident
1140        }
1141
1142        _ => SpaceState::Always,
1143    }
1144}
1145
1146/// Tries to convert a macro use into a short hand try expression. Returns `None`
1147/// when the macro is not an instance of `try!` (or parsing the inner expression
1148/// failed).
1149pub(crate) fn convert_try_mac(
1150    mac: &ast::MacCall,
1151    context: &RewriteContext<'_>,
1152) -> Option<ast::Expr> {
1153    let path = &pprust::path_to_string(&mac.path);
1154    if path == "try" || path == "r#try" {
1155        let ts = mac.args.tokens.clone();
1156
1157        Some(ast::Expr {
1158            id: ast::NodeId::root(), // dummy value
1159            kind: ast::ExprKind::Try(parse_expr(context, ts)?),
1160            span: mac.span(), // incorrect span, but shouldn't matter too much
1161            attrs: ast::AttrVec::new(),
1162            tokens: None,
1163        })
1164    } else {
1165        None
1166    }
1167}
1168
1169pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
1170    let snippet = context.snippet(mac.span());
1171    let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::MAX);
1172    let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::MAX);
1173    let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::MAX);
1174
1175    if paren_pos < bracket_pos && paren_pos < brace_pos {
1176        Delimiter::Parenthesis
1177    } else if bracket_pos < brace_pos {
1178        Delimiter::Bracket
1179    } else {
1180        Delimiter::Brace
1181    }
1182}
1183
1184// A very simple parser that just parses a macros 2.0 definition into its branches.
1185// Currently we do not attempt to parse any further than that.
1186struct MacroParser<'a> {
1187    iter: TokenStreamIter<'a>,
1188}
1189
1190impl<'a> MacroParser<'a> {
1191    const fn new(iter: TokenStreamIter<'a>) -> Self {
1192        Self { iter }
1193    }
1194
1195    // (`(` ... `)` `=>` `{` ... `}`)*
1196    fn parse(&mut self) -> Option<Macro> {
1197        let mut branches = vec![];
1198        while self.iter.peek().is_some() {
1199            branches.push(self.parse_branch()?);
1200        }
1201
1202        Some(Macro { branches })
1203    }
1204
1205    // `(` ... `)` `=>` `{` ... `}`
1206    fn parse_branch(&mut self) -> Option<MacroBranch> {
1207        let tok = self.iter.next()?;
1208        let (lo, args_paren_kind) = match tok {
1209            TokenTree::Token(..) => return None,
1210            &TokenTree::Delimited(delimited_span, _, d, _) => (delimited_span.open.lo(), d),
1211        };
1212        let args = TokenStream::new(vec![tok.clone()]);
1213        match self.iter.next()? {
1214            TokenTree::Token(
1215                Token {
1216                    kind: TokenKind::FatArrow,
1217                    ..
1218                },
1219                _,
1220            ) => {}
1221            _ => return None,
1222        }
1223        let (mut hi, body, whole_body) = match self.iter.next()? {
1224            TokenTree::Token(..) => return None,
1225            TokenTree::Delimited(delimited_span, ..) => {
1226                let data = delimited_span.entire().data();
1227                (
1228                    data.hi,
1229                    Span::new(
1230                        data.lo + BytePos(1),
1231                        data.hi - BytePos(1),
1232                        data.ctxt,
1233                        data.parent,
1234                    ),
1235                    delimited_span.entire(),
1236                )
1237            }
1238        };
1239        if let Some(TokenTree::Token(
1240            Token {
1241                kind: TokenKind::Semi,
1242                span,
1243            },
1244            _,
1245        )) = self.iter.peek()
1246        {
1247            hi = span.hi();
1248            self.iter.next();
1249        }
1250        Some(MacroBranch {
1251            span: mk_sp(lo, hi),
1252            args_paren_kind,
1253            args,
1254            body,
1255            whole_body,
1256        })
1257    }
1258}
1259
1260// A parsed macros 2.0 macro definition.
1261struct Macro {
1262    branches: Vec<MacroBranch>,
1263}
1264
1265// FIXME: it would be more efficient to use references to the token streams
1266// rather than clone them, if we can make the borrowing work out.
1267struct MacroBranch {
1268    span: Span,
1269    args_paren_kind: Delimiter,
1270    args: TokenStream,
1271    body: Span,
1272    whole_body: Span,
1273}
1274
1275impl MacroBranch {
1276    fn rewrite(
1277        &self,
1278        context: &RewriteContext<'_>,
1279        shape: Shape,
1280        multi_branch_style: bool,
1281    ) -> RewriteResult {
1282        // Only attempt to format function-like macros.
1283        if self.args_paren_kind != Delimiter::Parenthesis {
1284            // FIXME(#1539): implement for non-sugared macros.
1285            return Err(RewriteError::MacroFailure {
1286                kind: MacroErrorKind::Unknown,
1287                span: self.span,
1288            });
1289        }
1290
1291        let old_body = context.snippet(self.body).trim();
1292        let has_block_body = old_body.starts_with('{');
1293        let mut prefix_width = 5; // 5 = " => {"
1294        if context.config.style_edition() >= StyleEdition::Edition2024 {
1295            if has_block_body {
1296                prefix_width = 6; // 6 = " => {{"
1297            }
1298        }
1299        let mut result = format_macro_args(
1300            context,
1301            self.args.clone(),
1302            shape.sub_width(prefix_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!` and `lazy_static::lazy_static!`
1408/// from <https://crates.io/crates/lazy_static>.
1409///
1410/// # Expected syntax
1411///
1412/// ```text
1413/// lazy_static! {
1414///     [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1415///     [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1416///     ...
1417///     [pub] static ref NAME_N: TYPE_N = EXPR_N;
1418/// }
1419///
1420/// lazy_static::lazy_static! {
1421///     [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1422///     [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1423///     ...
1424///     [pub] static ref NAME_N: TYPE_N = EXPR_N;
1425/// }
1426/// ```
1427fn format_lazy_static(
1428    context: &RewriteContext<'_>,
1429    shape: Shape,
1430    ts: TokenStream,
1431    span: Span,
1432    macro_name: &str,
1433) -> RewriteResult {
1434    let mut result = String::with_capacity(1024);
1435    let nested_shape = shape
1436        .block_indent(context.config.tab_spaces())
1437        .with_max_width(context.config);
1438
1439    result.push_str(macro_name);
1440    result.push_str(" {");
1441    result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1442
1443    let parsed_elems =
1444        parse_lazy_static(context, ts).macro_error(MacroErrorKind::ParseFailure, span)?;
1445    let last = parsed_elems.len() - 1;
1446    for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
1447        // Rewrite as a static item.
1448        let vis = crate::utils::format_visibility(context, vis);
1449        let mut stmt = String::with_capacity(128);
1450        stmt.push_str(&format!(
1451            "{}static ref {}: {} =",
1452            vis,
1453            id,
1454            ty.rewrite_result(context, nested_shape)?
1455        ));
1456        result.push_str(&rewrite_assign_rhs(
1457            context,
1458            stmt,
1459            &*expr,
1460            &RhsAssignKind::Expr(&expr.kind, expr.span),
1461            nested_shape.sub_width(1, expr.span)?,
1462        )?);
1463        result.push(';');
1464        if i != last {
1465            result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1466        }
1467    }
1468
1469    result.push_str(&shape.indent.to_string_with_newline(context.config));
1470    result.push('}');
1471
1472    Ok(result)
1473}
1474
1475fn rewrite_macro_with_items(
1476    context: &RewriteContext<'_>,
1477    items: &[MacroArg],
1478    macro_name: &str,
1479    shape: Shape,
1480    style: Delimiter,
1481    original_style: Delimiter,
1482    position: MacroPosition,
1483    span: Span,
1484) -> RewriteResult {
1485    let style_to_delims = |style| match style {
1486        Delimiter::Parenthesis => Ok(("(", ")")),
1487        Delimiter::Bracket => Ok(("[", "]")),
1488        Delimiter::Brace => Ok((" {", "}")),
1489        _ => Err(RewriteError::Unknown),
1490    };
1491
1492    let (opener, closer) = style_to_delims(style)?;
1493    let (original_opener, _) = style_to_delims(original_style)?;
1494    let trailing_semicolon = match style {
1495        Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
1496        _ => "",
1497    };
1498
1499    let mut visitor = FmtVisitor::from_context(context);
1500    visitor.block_indent = shape.indent.block_indent(context.config);
1501
1502    // The current opener may be different from the original opener. This can happen
1503    // if our macro is a forced bracket macro originally written with non-bracket
1504    // delimiters. We need to use the original opener to locate the span after it.
1505    visitor.last_pos = context
1506        .snippet_provider
1507        .span_after(span, original_opener.trim());
1508    for item in items {
1509        let item = match item {
1510            MacroArg::Item(item) => item,
1511            _ => return Err(RewriteError::Unknown),
1512        };
1513        visitor.visit_item(item);
1514    }
1515
1516    let mut result = String::with_capacity(256);
1517    result.push_str(macro_name);
1518    result.push_str(opener);
1519    result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1520    result.push_str(visitor.buffer.trim());
1521    result.push_str(&shape.indent.to_string_with_newline(context.config));
1522    result.push_str(closer);
1523    result.push_str(trailing_semicolon);
1524    Ok(result)
1525}