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