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