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