1use 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
106fn rewrite_macro_name(context: &RewriteContext<'_>, path: &ast::Path) -> String {
108 if path.segments.len() == 1 {
109 format!("{}!", rewrite_ident(context, path.segments[0].ident))
111 } else {
112 format!("{}!", pprust::path_to_string(path))
113 }
114}
115
116fn return_macro_parse_failure_fallback(
120 context: &RewriteContext<'_>,
121 indent: Indent,
122 position: MacroPosition,
123 span: Span,
124) -> RewriteResult {
125 context.macro_rewrite_failure.replace(true);
127
128 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 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(&¯o_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 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(), ¯o_name) {
239 Ok(rw) => return Ok(rw),
240 Err(err) => match err {
241 RewriteError::MacroFailure { kind, span: _ }
244 if kind == MacroErrorKind::ParseFailure => {}
245 _ => 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(), ¯o_name, style, ts.clone()) {
253 Ok(rw) => return Ok(rw),
254 Err(err) => match err {
255 RewriteError::MacroFailure { kind, span: _ }
258 if kind == MacroErrorKind::ParseFailure => {}
259 other => return Err(other),
261 },
262 }
263 }
264
265 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 ¯o_name,
292 shape,
293 style,
294 original_style,
295 position,
296 mac.span(),
297 );
298 }
299
300 match style {
301 Delimiter::Parenthesis => {
302 if vec_with_semi {
304 handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
305 } else {
306 overflow::rewrite_with_parens(
309 context,
310 ¯o_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 if vec_with_semi {
330 handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
331 } else {
332 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 ¯o_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 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 let mac_shape = shape.offset_left(macro_name.len(), span)?;
393 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 Ok(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
404 } else {
405 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 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 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
552fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
556 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 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 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 MetaVariable(Symbol, String),
597 Repeat(
599 Delimiter,
601 Vec<ParsedMacroArg>,
603 Option<Box<ParsedMacroArg>>,
605 Token,
607 ),
608 Delimited(Delimiter, Vec<ParsedMacroArg>),
610 Separator(String, String),
612 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
739struct MacroArgParser {
741 buf: String,
743 start_tok: Token,
745 is_meta_var: bool,
747 last_tok: Token,
749 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 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 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 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 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 if !self.buf.is_empty() {
953 self.add_separator();
954 }
955
956 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 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 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
1054fn 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#[derive(Copy, Clone, PartialEq)]
1082enum SpaceState {
1083 Never,
1084 Punctuation,
1085 Ident, 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
1176pub(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(), kind: ast::ExprKind::Try(parse_expr(context, ts)?),
1190 span: mac.span(), 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
1214struct 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 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 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
1290struct Macro {
1292 branches: Vec<MacroBranch>,
1293}
1294
1295struct 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 if self.args_paren_kind != Delimiter::Parenthesis {
1314 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; if context.config.style_edition() >= StyleEdition::Edition2024 {
1325 if has_block_body {
1326 prefix_width = 6; }
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 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 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 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 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
1437fn 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 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 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 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 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 context.snippet_provider.span_after(span, opening_delim),
1646 span.hi(),
1653 false,
1654 );
1655 let arms_vec: Vec<_> = items.collect();
1656
1657 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}