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