rustfmt_nightly/
macros.rs

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