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 };
408 block.rewrite_result(context, shape)
409}
410
411pub(crate) fn rewrite_macro_def(
412 context: &RewriteContext<'_>,
413 shape: Shape,
414 indent: Indent,
415 def: &ast::MacroDef,
416 ident: Ident,
417 vis: &ast::Visibility,
418 span: Span,
419) -> RewriteResult {
420 let snippet = Ok(remove_trailing_white_spaces(context.snippet(span)));
421 if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
422 return snippet;
423 }
424
425 let ts = def.body.tokens.clone();
426 let mut parser = MacroParser::new(ts.iter());
427 let parsed_def = match parser.parse() {
428 Some(def) => def,
429 None => return snippet,
430 };
431
432 let mut result = if def.macro_rules {
433 String::from("macro_rules!")
434 } else {
435 format!("{}macro", format_visibility(context, vis))
436 };
437
438 result += " ";
439 result += rewrite_ident(context, ident);
440
441 let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
442
443 let arm_shape = if multi_branch_style {
444 shape
445 .block_indent(context.config.tab_spaces())
446 .with_max_width(context.config)
447 } else {
448 shape
449 };
450
451 if parsed_def.branches.len() == 0 {
452 let lo = context.snippet_provider.span_before(span, "{");
453 result += " ";
454 result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
455 return Ok(result);
456 }
457
458 let branch_items = itemize_list(
459 context.snippet_provider,
460 parsed_def.branches.iter(),
461 "}",
462 ";",
463 |branch| branch.span.lo(),
464 |branch| branch.span.hi(),
465 |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
466 Ok(v) => Ok(v),
467 Err(_) if context.macro_rewrite_failure.get() => {
471 Ok(context.snippet(branch.body).trim().to_string())
472 }
473 Err(e) => Err(e),
474 },
475 context.snippet_provider.span_after(span, "{"),
476 span.hi(),
477 false,
478 )
479 .collect::<Vec<_>>();
480
481 let fmt = ListFormatting::new(arm_shape, context.config)
482 .separator(if def.macro_rules { ";" } else { "" })
483 .trailing_separator(SeparatorTactic::Always)
484 .preserve_newline(true);
485
486 if multi_branch_style {
487 result += " {";
488 result += &arm_shape.indent.to_string_with_newline(context.config);
489 }
490
491 match write_list(&branch_items, &fmt) {
492 Ok(ref s) => result += s,
493 Err(_) => return snippet,
494 }
495
496 if multi_branch_style {
497 result += &indent.to_string_with_newline(context.config);
498 result += "}";
499 }
500
501 Ok(result)
502}
503
504fn register_metavariable(
505 map: &mut HashMap<String, String>,
506 result: &mut String,
507 name: &str,
508 dollar_count: usize,
509) {
510 let mut new_name = "$".repeat(dollar_count - 1);
511 let mut old_name = "$".repeat(dollar_count);
512
513 new_name.push('z');
514 new_name.push_str(name);
515 old_name.push_str(name);
516
517 result.push_str(&new_name);
518 map.insert(old_name, new_name);
519}
520
521fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
525 let mut result = String::with_capacity(input.len() + 64);
527 let mut substs = HashMap::new();
528 let mut dollar_count = 0;
529 let mut cur_name = String::new();
530
531 for (kind, c) in CharClasses::new(input.chars()) {
532 if kind != FullCodeCharKind::Normal {
533 result.push(c);
534 } else if c == '$' {
535 dollar_count += 1;
536 } else if dollar_count == 0 {
537 result.push(c);
538 } else if !c.is_alphanumeric() && !cur_name.is_empty() {
539 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
541
542 result.push(c);
543 dollar_count = 0;
544 cur_name.clear();
545 } else if c == '(' && cur_name.is_empty() {
546 return None;
548 } else if c.is_alphanumeric() || c == '_' {
549 cur_name.push(c);
550 }
551 }
552
553 if !cur_name.is_empty() {
554 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
555 }
556
557 debug!("replace_names `{}` {:?}", result, substs);
558
559 Some((result, substs))
560}
561
562#[derive(Debug, Clone)]
563enum MacroArgKind {
564 MetaVariable(Symbol, String),
566 Repeat(
568 Delimiter,
570 Vec<ParsedMacroArg>,
572 Option<Box<ParsedMacroArg>>,
574 Token,
576 ),
577 Delimited(Delimiter, Vec<ParsedMacroArg>),
579 Separator(String, String),
581 Other(String, String),
584}
585
586fn delim_token_to_str(
587 context: &RewriteContext<'_>,
588 delim_token: Delimiter,
589 shape: Shape,
590 use_multiple_lines: bool,
591 inner_is_empty: bool,
592) -> (String, String) {
593 let (lhs, rhs) = match delim_token {
594 Delimiter::Parenthesis => ("(", ")"),
595 Delimiter::Bracket => ("[", "]"),
596 Delimiter::Brace => {
597 if inner_is_empty || use_multiple_lines {
598 ("{", "}")
599 } else {
600 ("{ ", " }")
601 }
602 }
603 Delimiter::Invisible(_) => unreachable!(),
604 };
605 if use_multiple_lines {
606 let indent_str = shape.indent.to_string_with_newline(context.config);
607 let nested_indent_str = shape
608 .indent
609 .block_indent(context.config)
610 .to_string_with_newline(context.config);
611 (
612 format!("{lhs}{nested_indent_str}"),
613 format!("{indent_str}{rhs}"),
614 )
615 } else {
616 (lhs.to_owned(), rhs.to_owned())
617 }
618}
619
620impl MacroArgKind {
621 fn starts_with_brace(&self) -> bool {
622 matches!(
623 *self,
624 MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
625 | MacroArgKind::Delimited(Delimiter::Brace, _)
626 )
627 }
628
629 fn starts_with_dollar(&self) -> bool {
630 matches!(
631 *self,
632 MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
633 )
634 }
635
636 fn ends_with_space(&self) -> bool {
637 matches!(*self, MacroArgKind::Separator(..))
638 }
639
640 fn has_meta_var(&self) -> bool {
641 match *self {
642 MacroArgKind::MetaVariable(..) => true,
643 MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
644 _ => false,
645 }
646 }
647
648 fn rewrite(
649 &self,
650 context: &RewriteContext<'_>,
651 shape: Shape,
652 use_multiple_lines: bool,
653 ) -> RewriteResult {
654 type DelimitedArgsRewrite = Result<(String, String, String), RewriteError>;
655 let rewrite_delimited_inner = |delim_tok, args| -> DelimitedArgsRewrite {
656 let inner = wrap_macro_args(context, args, shape)?;
657 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
658 if lhs.len() + inner.len() + rhs.len() <= shape.width {
659 return Ok((lhs, inner, rhs));
660 }
661
662 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
663 let nested_shape = shape
664 .block_indent(context.config.tab_spaces())
665 .with_max_width(context.config);
666 let inner = wrap_macro_args(context, args, nested_shape)?;
667 Ok((lhs, inner, rhs))
668 };
669
670 match *self {
671 MacroArgKind::MetaVariable(ty, ref name) => Ok(format!("${name}:{ty}")),
672 MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
673 let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
674 let another = another
675 .as_ref()
676 .and_then(|a| a.rewrite(context, shape, use_multiple_lines).ok())
677 .unwrap_or_else(|| "".to_owned());
678 let repeat_tok = pprust::token_to_string(tok);
679
680 Ok(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
681 }
682 MacroArgKind::Delimited(delim_tok, ref args) => {
683 rewrite_delimited_inner(delim_tok, args)
684 .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
685 }
686 MacroArgKind::Separator(ref sep, ref prefix) => Ok(format!("{prefix}{sep} ")),
687 MacroArgKind::Other(ref inner, ref prefix) => Ok(format!("{prefix}{inner}")),
688 }
689 }
690}
691
692#[derive(Debug, Clone)]
693struct ParsedMacroArg {
694 kind: MacroArgKind,
695}
696
697impl ParsedMacroArg {
698 fn rewrite(
699 &self,
700 context: &RewriteContext<'_>,
701 shape: Shape,
702 use_multiple_lines: bool,
703 ) -> RewriteResult {
704 self.kind.rewrite(context, shape, use_multiple_lines)
705 }
706}
707
708struct MacroArgParser {
710 buf: String,
712 start_tok: Token,
714 is_meta_var: bool,
716 last_tok: Token,
718 result: Vec<ParsedMacroArg>,
720}
721
722fn last_tok(tt: &TokenTree) -> Token {
723 match *tt {
724 TokenTree::Token(ref t, _) => t.clone(),
725 TokenTree::Delimited(delim_span, _, delim, _) => Token {
726 kind: delim.as_open_token_kind(),
727 span: delim_span.close,
728 },
729 }
730}
731
732impl MacroArgParser {
733 fn new() -> MacroArgParser {
734 MacroArgParser {
735 buf: String::new(),
736 is_meta_var: false,
737 last_tok: Token {
738 kind: TokenKind::Eof,
739 span: DUMMY_SP,
740 },
741 start_tok: Token {
742 kind: TokenKind::Eof,
743 span: DUMMY_SP,
744 },
745 result: vec![],
746 }
747 }
748
749 fn set_last_tok(&mut self, tok: &TokenTree) {
750 self.last_tok = last_tok(tok);
751 }
752
753 fn add_separator(&mut self) {
754 let prefix = if self.need_space_prefix() {
755 " ".to_owned()
756 } else {
757 "".to_owned()
758 };
759 self.result.push(ParsedMacroArg {
760 kind: MacroArgKind::Separator(self.buf.clone(), prefix),
761 });
762 self.buf.clear();
763 }
764
765 fn add_other(&mut self) {
766 let prefix = if self.need_space_prefix() {
767 " ".to_owned()
768 } else {
769 "".to_owned()
770 };
771 self.result.push(ParsedMacroArg {
772 kind: MacroArgKind::Other(self.buf.clone(), prefix),
773 });
774 self.buf.clear();
775 }
776
777 fn add_meta_variable(&mut self, iter: &mut TokenStreamIter<'_>) -> Option<()> {
778 match iter.next() {
779 Some(&TokenTree::Token(
780 Token {
781 kind: TokenKind::Ident(name, _),
782 ..
783 },
784 _,
785 )) => {
786 self.result.push(ParsedMacroArg {
787 kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
788 });
789
790 self.buf.clear();
791 self.is_meta_var = false;
792 Some(())
793 }
794 _ => None,
795 }
796 }
797
798 fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
799 self.result.push(ParsedMacroArg {
800 kind: MacroArgKind::Delimited(delim, inner),
801 });
802 }
803
804 fn add_repeat(
806 &mut self,
807 inner: Vec<ParsedMacroArg>,
808 delim: Delimiter,
809 iter: &mut TokenStreamIter<'_>,
810 ) -> Option<()> {
811 let mut buffer = String::new();
812 let mut first = true;
813
814 for tok in iter {
816 self.set_last_tok(&tok);
817 if first {
818 first = false;
819 }
820
821 match tok {
822 TokenTree::Token(
823 Token {
824 kind: TokenKind::Plus,
825 ..
826 },
827 _,
828 )
829 | TokenTree::Token(
830 Token {
831 kind: TokenKind::Question,
832 ..
833 },
834 _,
835 )
836 | TokenTree::Token(
837 Token {
838 kind: TokenKind::Star,
839 ..
840 },
841 _,
842 ) => {
843 break;
844 }
845 TokenTree::Token(ref t, _) => {
846 buffer.push_str(&pprust::token_to_string(t));
847 }
848 _ => return None,
849 }
850 }
851
852 let another = if buffer.trim().is_empty() {
854 None
855 } else {
856 Some(Box::new(ParsedMacroArg {
857 kind: MacroArgKind::Other(buffer, "".to_owned()),
858 }))
859 };
860
861 self.result.push(ParsedMacroArg {
862 kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok),
863 });
864 Some(())
865 }
866
867 fn update_buffer(&mut self, t: Token) {
868 if self.buf.is_empty() {
869 self.start_tok = t;
870 } else {
871 let needs_space = match next_space(&self.last_tok.kind) {
872 SpaceState::Ident => ident_like(&t),
873 SpaceState::Punctuation => !ident_like(&t),
874 SpaceState::Always => true,
875 SpaceState::Never => false,
876 };
877 if force_space_before(&t.kind) || needs_space {
878 self.buf.push(' ');
879 }
880 }
881
882 self.buf.push_str(&pprust::token_to_string(&t));
883 }
884
885 fn need_space_prefix(&self) -> bool {
886 if self.result.is_empty() {
887 return false;
888 }
889
890 let last_arg = self.result.last().unwrap();
891 if let MacroArgKind::MetaVariable(..) = last_arg.kind {
892 if ident_like(&self.start_tok) {
893 return true;
894 }
895 if self.start_tok.kind == TokenKind::Colon {
896 return true;
897 }
898 }
899
900 if force_space_before(&self.start_tok.kind) {
901 return true;
902 }
903
904 false
905 }
906
907 fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
909 let mut iter = tokens.iter();
910
911 while let Some(tok) = iter.next() {
912 match tok {
913 &TokenTree::Token(
914 Token {
915 kind: TokenKind::Dollar,
916 span,
917 },
918 _,
919 ) => {
920 if !self.buf.is_empty() {
922 self.add_separator();
923 }
924
925 self.is_meta_var = true;
927 self.start_tok = Token {
928 kind: TokenKind::Dollar,
929 span,
930 };
931 }
932 TokenTree::Token(
933 Token {
934 kind: TokenKind::Colon,
935 ..
936 },
937 _,
938 ) if self.is_meta_var => {
939 self.add_meta_variable(&mut iter)?;
940 }
941 &TokenTree::Token(t, _) => self.update_buffer(t),
942 &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => {
943 if !self.buf.is_empty() {
944 if next_space(&self.last_tok.kind) == SpaceState::Always {
945 self.add_separator();
946 } else {
947 self.add_other();
948 }
949 }
950
951 let parser = MacroArgParser::new();
953 let delimited_arg = parser.parse(tts.clone())?;
954
955 if self.is_meta_var {
956 self.add_repeat(delimited_arg, delimited, &mut iter)?;
957 self.is_meta_var = false;
958 } else {
959 self.add_delimited(delimited_arg, delimited);
960 }
961 }
962 }
963
964 self.set_last_tok(&tok);
965 }
966
967 if !self.buf.is_empty() {
970 self.add_other();
971 }
972
973 Some(self.result)
974 }
975}
976
977fn wrap_macro_args(
978 context: &RewriteContext<'_>,
979 args: &[ParsedMacroArg],
980 shape: Shape,
981) -> RewriteResult {
982 wrap_macro_args_inner(context, args, shape, false)
983 .or_else(|_| wrap_macro_args_inner(context, args, shape, true))
984}
985
986fn wrap_macro_args_inner(
987 context: &RewriteContext<'_>,
988 args: &[ParsedMacroArg],
989 shape: Shape,
990 use_multiple_lines: bool,
991) -> RewriteResult {
992 let mut result = String::with_capacity(128);
993 let mut iter = args.iter().peekable();
994 let indent_str = shape.indent.to_string_with_newline(context.config);
995
996 while let Some(arg) = iter.next() {
997 result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
998
999 if use_multiple_lines
1000 && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
1001 {
1002 if arg.kind.ends_with_space() {
1003 result.pop();
1004 }
1005 result.push_str(&indent_str);
1006 } else if let Some(next_arg) = iter.peek() {
1007 let space_before_dollar =
1008 !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
1009 let space_before_brace = next_arg.kind.starts_with_brace();
1010 if space_before_dollar || space_before_brace {
1011 result.push(' ');
1012 }
1013 }
1014 }
1015
1016 if !use_multiple_lines && result.len() >= shape.width {
1017 Err(RewriteError::Unknown)
1018 } else {
1019 Ok(result)
1020 }
1021}
1022
1023fn format_macro_args(
1028 context: &RewriteContext<'_>,
1029 token_stream: TokenStream,
1030 shape: Shape,
1031) -> RewriteResult {
1032 let span = span_for_token_stream(&token_stream);
1033 if !context.config.format_macro_matchers() {
1034 return Ok(match span {
1035 Some(span) => context.snippet(span).to_owned(),
1036 None => String::new(),
1037 });
1038 }
1039 let parsed_args = MacroArgParser::new()
1040 .parse(token_stream)
1041 .macro_error(MacroErrorKind::ParseFailure, span.unwrap())?;
1042 wrap_macro_args(context, &parsed_args, shape)
1043}
1044
1045fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
1046 token_stream.iter().next().map(|tt| tt.span())
1047}
1048
1049#[derive(Copy, Clone, PartialEq)]
1051enum SpaceState {
1052 Never,
1053 Punctuation,
1054 Ident, Always,
1056}
1057
1058fn force_space_before(tok: &TokenKind) -> bool {
1059 debug!("tok: force_space_before {:?}", tok);
1060
1061 match tok {
1062 TokenKind::Eq
1063 | TokenKind::Lt
1064 | TokenKind::Le
1065 | TokenKind::EqEq
1066 | TokenKind::Ne
1067 | TokenKind::Ge
1068 | TokenKind::Gt
1069 | TokenKind::AndAnd
1070 | TokenKind::OrOr
1071 | TokenKind::Bang
1072 | TokenKind::Tilde
1073 | TokenKind::PlusEq
1074 | TokenKind::MinusEq
1075 | TokenKind::StarEq
1076 | TokenKind::SlashEq
1077 | TokenKind::PercentEq
1078 | TokenKind::CaretEq
1079 | TokenKind::AndEq
1080 | TokenKind::OrEq
1081 | TokenKind::ShlEq
1082 | TokenKind::ShrEq
1083 | TokenKind::At
1084 | TokenKind::RArrow
1085 | TokenKind::LArrow
1086 | TokenKind::FatArrow
1087 | TokenKind::Plus
1088 | TokenKind::Minus
1089 | TokenKind::Star
1090 | TokenKind::Slash
1091 | TokenKind::Percent
1092 | TokenKind::Caret
1093 | TokenKind::And
1094 | TokenKind::Or
1095 | TokenKind::Shl
1096 | TokenKind::Shr
1097 | TokenKind::Pound
1098 | TokenKind::Dollar => true,
1099 _ => false,
1100 }
1101}
1102
1103fn ident_like(tok: &Token) -> bool {
1104 matches!(
1105 tok.kind,
1106 TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(..)
1107 )
1108}
1109
1110fn next_space(tok: &TokenKind) -> SpaceState {
1111 debug!("next_space: {:?}", tok);
1112
1113 match tok {
1114 TokenKind::Bang
1115 | TokenKind::And
1116 | TokenKind::Tilde
1117 | TokenKind::At
1118 | TokenKind::Comma
1119 | TokenKind::Dot
1120 | TokenKind::DotDot
1121 | TokenKind::DotDotDot
1122 | TokenKind::DotDotEq
1123 | TokenKind::Question => SpaceState::Punctuation,
1124
1125 TokenKind::PathSep
1126 | TokenKind::Pound
1127 | TokenKind::Dollar
1128 | TokenKind::OpenParen
1129 | TokenKind::CloseParen
1130 | TokenKind::OpenBrace
1131 | TokenKind::CloseBrace
1132 | TokenKind::OpenBracket
1133 | TokenKind::CloseBracket
1134 | TokenKind::OpenInvisible(_)
1135 | TokenKind::CloseInvisible(_) => SpaceState::Never,
1136
1137 TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => {
1138 SpaceState::Ident
1139 }
1140
1141 _ => SpaceState::Always,
1142 }
1143}
1144
1145pub(crate) fn convert_try_mac(
1149 mac: &ast::MacCall,
1150 context: &RewriteContext<'_>,
1151) -> Option<ast::Expr> {
1152 let path = &pprust::path_to_string(&mac.path);
1153 if path == "try" || path == "r#try" {
1154 let ts = mac.args.tokens.clone();
1155
1156 Some(ast::Expr {
1157 id: ast::NodeId::root(), kind: ast::ExprKind::Try(parse_expr(context, ts)?),
1159 span: mac.span(), attrs: ast::AttrVec::new(),
1161 tokens: None,
1162 })
1163 } else {
1164 None
1165 }
1166}
1167
1168pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
1169 let snippet = context.snippet(mac.span());
1170 let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::MAX);
1171 let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::MAX);
1172 let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::MAX);
1173
1174 if paren_pos < bracket_pos && paren_pos < brace_pos {
1175 Delimiter::Parenthesis
1176 } else if bracket_pos < brace_pos {
1177 Delimiter::Bracket
1178 } else {
1179 Delimiter::Brace
1180 }
1181}
1182
1183struct MacroParser<'a> {
1186 iter: TokenStreamIter<'a>,
1187}
1188
1189impl<'a> MacroParser<'a> {
1190 const fn new(iter: TokenStreamIter<'a>) -> Self {
1191 Self { iter }
1192 }
1193
1194 fn parse(&mut self) -> Option<Macro> {
1196 let mut branches = vec![];
1197 while self.iter.peek().is_some() {
1198 branches.push(self.parse_branch()?);
1199 }
1200
1201 Some(Macro { branches })
1202 }
1203
1204 fn parse_branch(&mut self) -> Option<MacroBranch> {
1206 let tok = self.iter.next()?;
1207 let (lo, args_paren_kind) = match tok {
1208 TokenTree::Token(..) => return None,
1209 &TokenTree::Delimited(delimited_span, _, d, _) => (delimited_span.open.lo(), d),
1210 };
1211 let args = TokenStream::new(vec![tok.clone()]);
1212 match self.iter.next()? {
1213 TokenTree::Token(
1214 Token {
1215 kind: TokenKind::FatArrow,
1216 ..
1217 },
1218 _,
1219 ) => {}
1220 _ => return None,
1221 }
1222 let (mut hi, body, whole_body) = match self.iter.next()? {
1223 TokenTree::Token(..) => return None,
1224 TokenTree::Delimited(delimited_span, ..) => {
1225 let data = delimited_span.entire().data();
1226 (
1227 data.hi,
1228 Span::new(
1229 data.lo + BytePos(1),
1230 data.hi - BytePos(1),
1231 data.ctxt,
1232 data.parent,
1233 ),
1234 delimited_span.entire(),
1235 )
1236 }
1237 };
1238 if let Some(TokenTree::Token(
1239 Token {
1240 kind: TokenKind::Semi,
1241 span,
1242 },
1243 _,
1244 )) = self.iter.peek()
1245 {
1246 hi = span.hi();
1247 self.iter.next();
1248 }
1249 Some(MacroBranch {
1250 span: mk_sp(lo, hi),
1251 args_paren_kind,
1252 args,
1253 body,
1254 whole_body,
1255 })
1256 }
1257}
1258
1259struct Macro {
1261 branches: Vec<MacroBranch>,
1262}
1263
1264struct MacroBranch {
1267 span: Span,
1268 args_paren_kind: Delimiter,
1269 args: TokenStream,
1270 body: Span,
1271 whole_body: Span,
1272}
1273
1274impl MacroBranch {
1275 fn rewrite(
1276 &self,
1277 context: &RewriteContext<'_>,
1278 shape: Shape,
1279 multi_branch_style: bool,
1280 ) -> RewriteResult {
1281 if self.args_paren_kind != Delimiter::Parenthesis {
1283 return Err(RewriteError::MacroFailure {
1285 kind: MacroErrorKind::Unknown,
1286 span: self.span,
1287 });
1288 }
1289
1290 let old_body = context.snippet(self.body).trim();
1291 let has_block_body = old_body.starts_with('{');
1292 let mut prefix_width = 5; if context.config.style_edition() >= StyleEdition::Edition2024 {
1294 if has_block_body {
1295 prefix_width = 6; }
1297 }
1298 let mut result = format_macro_args(
1299 context,
1300 self.args.clone(),
1301 shape.sub_width(prefix_width, self.span)?,
1302 )?;
1303
1304 if multi_branch_style {
1305 result += " =>";
1306 }
1307
1308 if !context.config.format_macro_bodies() {
1309 result += " ";
1310 result += context.snippet(self.whole_body);
1311 return Ok(result);
1312 }
1313
1314 let (body_str, substs) =
1321 replace_names(old_body).macro_error(MacroErrorKind::ReplaceMacroVariable, self.span)?;
1322
1323 let mut config = context.config.clone();
1324 config.set().show_parse_errors(false);
1325
1326 result += " {";
1327
1328 let body_indent = if has_block_body {
1329 shape.indent
1330 } else {
1331 shape.indent.block_indent(&config)
1332 };
1333 let new_width = config.max_width() - body_indent.width();
1334 config.set().max_width(new_width);
1335
1336 let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
1338 Some(new_body) => new_body,
1339 None => {
1340 let new_width = new_width + config.tab_spaces();
1341 config.set().max_width(new_width);
1342 match crate::format_code_block(&body_str, &config, true) {
1343 Some(new_body) => new_body,
1344 None => {
1345 return Err(RewriteError::MacroFailure {
1346 kind: MacroErrorKind::Unknown,
1347 span: self.span,
1348 });
1349 }
1350 }
1351 }
1352 };
1353
1354 if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
1355 return Err(RewriteError::ExceedsMaxWidth {
1356 configured_width: shape.width,
1357 span: self.span,
1358 });
1359 }
1360
1361 let indent_str = body_indent.to_string(&config);
1363 let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end())
1364 .enumerate()
1365 .fold(
1366 (String::new(), true),
1367 |(mut s, need_indent), (i, (kind, ref l))| {
1368 if !is_empty_line(l)
1369 && need_indent
1370 && !new_body_snippet.is_line_non_formatted(i + 1)
1371 {
1372 s += &indent_str;
1373 }
1374 (s + l + "\n", indent_next_line(kind, l, &config))
1375 },
1376 )
1377 .0;
1378
1379 for (old, new) in &substs {
1382 if old_body.contains(new) {
1383 debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
1384 return Err(RewriteError::MacroFailure {
1385 kind: MacroErrorKind::ReplaceMacroVariable,
1386 span: self.span,
1387 });
1388 }
1389 new_body = new_body.replace(new, old);
1390 }
1391
1392 if has_block_body {
1393 result += new_body.trim();
1394 } else if !new_body.is_empty() {
1395 result += "\n";
1396 result += &new_body;
1397 result += &shape.indent.to_string(&config);
1398 }
1399
1400 result += "}";
1401
1402 Ok(result)
1403 }
1404}
1405
1406fn format_lazy_static(
1427 context: &RewriteContext<'_>,
1428 shape: Shape,
1429 ts: TokenStream,
1430 span: Span,
1431 macro_name: &str,
1432) -> RewriteResult {
1433 let mut result = String::with_capacity(1024);
1434 let nested_shape = shape
1435 .block_indent(context.config.tab_spaces())
1436 .with_max_width(context.config);
1437
1438 result.push_str(macro_name);
1439 result.push_str(" {");
1440 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1441
1442 let parsed_elems =
1443 parse_lazy_static(context, ts).macro_error(MacroErrorKind::ParseFailure, span)?;
1444 let last = parsed_elems.len() - 1;
1445 for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
1446 let vis = crate::utils::format_visibility(context, vis);
1448 let mut stmt = String::with_capacity(128);
1449 stmt.push_str(&format!(
1450 "{}static ref {}: {} =",
1451 vis,
1452 id,
1453 ty.rewrite_result(context, nested_shape)?
1454 ));
1455 result.push_str(&rewrite_assign_rhs(
1456 context,
1457 stmt,
1458 &*expr,
1459 &RhsAssignKind::Expr(&expr.kind, expr.span),
1460 nested_shape.sub_width(1, expr.span)?,
1461 )?);
1462 result.push(';');
1463 if i != last {
1464 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1465 }
1466 }
1467
1468 result.push_str(&shape.indent.to_string_with_newline(context.config));
1469 result.push('}');
1470
1471 Ok(result)
1472}
1473
1474fn rewrite_macro_with_items(
1475 context: &RewriteContext<'_>,
1476 items: &[MacroArg],
1477 macro_name: &str,
1478 shape: Shape,
1479 style: Delimiter,
1480 original_style: Delimiter,
1481 position: MacroPosition,
1482 span: Span,
1483) -> RewriteResult {
1484 let style_to_delims = |style| match style {
1485 Delimiter::Parenthesis => Ok(("(", ")")),
1486 Delimiter::Bracket => Ok(("[", "]")),
1487 Delimiter::Brace => Ok((" {", "}")),
1488 _ => Err(RewriteError::Unknown),
1489 };
1490
1491 let (opener, closer) = style_to_delims(style)?;
1492 let (original_opener, _) = style_to_delims(original_style)?;
1493 let trailing_semicolon = match style {
1494 Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
1495 _ => "",
1496 };
1497
1498 let mut visitor = FmtVisitor::from_context(context);
1499 visitor.block_indent = shape.indent.block_indent(context.config);
1500
1501 visitor.last_pos = context
1505 .snippet_provider
1506 .span_after(span, original_opener.trim());
1507 for item in items {
1508 let item = match item {
1509 MacroArg::Item(item) => item,
1510 _ => return Err(RewriteError::Unknown),
1511 };
1512 visitor.visit_item(item);
1513 }
1514
1515 let mut result = String::with_capacity(256);
1516 result.push_str(macro_name);
1517 result.push_str(opener);
1518 result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1519 result.push_str(visitor.buffer.trim());
1520 result.push_str(&shape.indent.to_string_with_newline(context.config));
1521 result.push_str(closer);
1522 result.push_str(trailing_semicolon);
1523 Ok(result)
1524}