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