]> git.lizzy.rs Git - rust.git/blob - src/tools/rustfmt/src/macros.rs
Rollup merge of #104402 - joboet:sync_remutex, r=m-ou-se
[rust.git] / src / tools / rustfmt / src / macros.rs
1 // Format list-like macro invocations. These are invocations whose token trees
2 // can be interpreted as expressions and separated by commas.
3 // Note that these token trees do not actually have to be interpreted as
4 // expressions by the compiler. An example of an invocation we would reformat is
5 // foo!( x, y, z ). The token x may represent an identifier in the code, but we
6 // interpreted as an expression.
7 // Macro uses which are not-list like, such as bar!(key => val), will not be
8 // reformatted.
9 // List-like invocations with parentheses will be formatted as function calls,
10 // and those with brackets will be formatted as array literals.
11
12 use std::collections::HashMap;
13 use std::panic::{catch_unwind, AssertUnwindSafe};
14
15 use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
16 use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
17 use rustc_ast::{ast, ptr};
18 use rustc_ast_pretty::pprust;
19 use rustc_span::{
20     symbol::{self, kw},
21     BytePos, Span, Symbol, DUMMY_SP,
22 };
23
24 use crate::comment::{
25     contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
26 };
27 use crate::config::lists::*;
28 use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
29 use crate::lists::{itemize_list, write_list, ListFormatting};
30 use crate::overflow;
31 use crate::parse::macros::lazy_static::parse_lazy_static;
32 use crate::parse::macros::{parse_expr, parse_macro_args, ParsedMacroArgs};
33 use crate::rewrite::{Rewrite, RewriteContext};
34 use crate::shape::{Indent, Shape};
35 use crate::source_map::SpanUtils;
36 use crate::spanned::Spanned;
37 use crate::utils::{
38     format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces,
39     rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt,
40 };
41 use crate::visitor::FmtVisitor;
42
43 const FORCED_BRACKET_MACROS: &[&str] = &["vec!"];
44
45 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
46 pub(crate) enum MacroPosition {
47     Item,
48     Statement,
49     Expression,
50     Pat,
51 }
52
53 #[derive(Debug)]
54 pub(crate) enum MacroArg {
55     Expr(ptr::P<ast::Expr>),
56     Ty(ptr::P<ast::Ty>),
57     Pat(ptr::P<ast::Pat>),
58     Item(ptr::P<ast::Item>),
59     Keyword(symbol::Ident, Span),
60 }
61
62 impl MacroArg {
63     pub(crate) fn is_item(&self) -> bool {
64         match self {
65             MacroArg::Item(..) => true,
66             _ => false,
67         }
68     }
69 }
70
71 impl Rewrite for ast::Item {
72     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
73         let mut visitor = crate::visitor::FmtVisitor::from_context(context);
74         visitor.block_indent = shape.indent;
75         visitor.last_pos = self.span().lo();
76         visitor.visit_item(self);
77         Some(visitor.buffer.to_owned())
78     }
79 }
80
81 impl Rewrite for MacroArg {
82     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
83         match *self {
84             MacroArg::Expr(ref expr) => expr.rewrite(context, shape),
85             MacroArg::Ty(ref ty) => ty.rewrite(context, shape),
86             MacroArg::Pat(ref pat) => pat.rewrite(context, shape),
87             MacroArg::Item(ref item) => item.rewrite(context, shape),
88             MacroArg::Keyword(ident, _) => Some(ident.name.to_string()),
89         }
90     }
91 }
92
93 /// Rewrite macro name without using pretty-printer if possible.
94 fn rewrite_macro_name(
95     context: &RewriteContext<'_>,
96     path: &ast::Path,
97     extra_ident: Option<symbol::Ident>,
98 ) -> String {
99     let name = if path.segments.len() == 1 {
100         // Avoid using pretty-printer in the common case.
101         format!("{}!", rewrite_ident(context, path.segments[0].ident))
102     } else {
103         format!("{}!", pprust::path_to_string(path))
104     };
105     match extra_ident {
106         Some(ident) if ident.name != kw::Empty => format!("{} {}", name, ident),
107         _ => name,
108     }
109 }
110
111 // Use this on failing to format the macro call.
112 fn return_macro_parse_failure_fallback(
113     context: &RewriteContext<'_>,
114     indent: Indent,
115     position: MacroPosition,
116     span: Span,
117 ) -> Option<String> {
118     // Mark this as a failure however we format it
119     context.macro_rewrite_failure.replace(true);
120
121     // Heuristically determine whether the last line of the macro uses "Block" style
122     // rather than using "Visual" style, or another indentation style.
123     let is_like_block_indent_style = context
124         .snippet(span)
125         .lines()
126         .last()
127         .map(|closing_line| {
128             closing_line
129                 .trim()
130                 .chars()
131                 .all(|ch| matches!(ch, '}' | ')' | ']'))
132         })
133         .unwrap_or(false);
134     if is_like_block_indent_style {
135         return trim_left_preserve_layout(context.snippet(span), indent, context.config);
136     }
137
138     context.skipped_range.borrow_mut().push((
139         context.parse_sess.line_of_byte_pos(span.lo()),
140         context.parse_sess.line_of_byte_pos(span.hi()),
141     ));
142
143     // Return the snippet unmodified if the macro is not block-like
144     let mut snippet = context.snippet(span).to_owned();
145     if position == MacroPosition::Item {
146         snippet.push(';');
147     }
148     Some(snippet)
149 }
150
151 pub(crate) fn rewrite_macro(
152     mac: &ast::MacCall,
153     extra_ident: Option<symbol::Ident>,
154     context: &RewriteContext<'_>,
155     shape: Shape,
156     position: MacroPosition,
157 ) -> Option<String> {
158     let should_skip = context
159         .skip_context
160         .skip_macro(context.snippet(mac.path.span));
161     if should_skip {
162         None
163     } else {
164         let guard = context.enter_macro();
165         let result = catch_unwind(AssertUnwindSafe(|| {
166             rewrite_macro_inner(
167                 mac,
168                 extra_ident,
169                 context,
170                 shape,
171                 position,
172                 guard.is_nested(),
173             )
174         }));
175         match result {
176             Err(..) | Ok(None) => {
177                 context.macro_rewrite_failure.replace(true);
178                 None
179             }
180             Ok(rw) => rw,
181         }
182     }
183 }
184
185 fn rewrite_macro_inner(
186     mac: &ast::MacCall,
187     extra_ident: Option<symbol::Ident>,
188     context: &RewriteContext<'_>,
189     shape: Shape,
190     position: MacroPosition,
191     is_nested_macro: bool,
192 ) -> Option<String> {
193     if context.config.use_try_shorthand() {
194         if let Some(expr) = convert_try_mac(mac, context) {
195             context.leave_macro();
196             return expr.rewrite(context, shape);
197         }
198     }
199
200     let original_style = macro_style(mac, context);
201
202     let macro_name = rewrite_macro_name(context, &mac.path, extra_ident);
203     let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&&macro_name[..]);
204
205     let style = if is_forced_bracket && !is_nested_macro {
206         Delimiter::Bracket
207     } else {
208         original_style
209     };
210
211     let ts = mac.args.tokens.clone();
212     let has_comment = contains_comment(context.snippet(mac.span()));
213     if ts.is_empty() && !has_comment {
214         return match style {
215             Delimiter::Parenthesis if position == MacroPosition::Item => {
216                 Some(format!("{}();", macro_name))
217             }
218             Delimiter::Bracket if position == MacroPosition::Item => {
219                 Some(format!("{}[];", macro_name))
220             }
221             Delimiter::Parenthesis => Some(format!("{}()", macro_name)),
222             Delimiter::Bracket => Some(format!("{}[]", macro_name)),
223             Delimiter::Brace => Some(format!("{} {{}}", macro_name)),
224             _ => unreachable!(),
225         };
226     }
227     // Format well-known macros which cannot be parsed as a valid AST.
228     if macro_name == "lazy_static!" && !has_comment {
229         if let success @ Some(..) = format_lazy_static(context, shape, ts.clone()) {
230             return success;
231         }
232     }
233
234     let ParsedMacroArgs {
235         args: arg_vec,
236         vec_with_semi,
237         trailing_comma,
238     } = match parse_macro_args(context, ts, style, is_forced_bracket) {
239         Some(args) => args,
240         None => {
241             return return_macro_parse_failure_fallback(
242                 context,
243                 shape.indent,
244                 position,
245                 mac.span(),
246             );
247         }
248     };
249
250     if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) {
251         return rewrite_macro_with_items(
252             context,
253             &arg_vec,
254             &macro_name,
255             shape,
256             style,
257             position,
258             mac.span(),
259         );
260     }
261
262     match style {
263         Delimiter::Parenthesis => {
264             // Handle special case: `vec!(expr; expr)`
265             if vec_with_semi {
266                 handle_vec_semi(context, shape, arg_vec, macro_name, style)
267             } else {
268                 // Format macro invocation as function call, preserve the trailing
269                 // comma because not all macros support them.
270                 overflow::rewrite_with_parens(
271                     context,
272                     &macro_name,
273                     arg_vec.iter(),
274                     shape,
275                     mac.span(),
276                     context.config.fn_call_width(),
277                     if trailing_comma {
278                         Some(SeparatorTactic::Always)
279                     } else {
280                         Some(SeparatorTactic::Never)
281                     },
282                 )
283                 .map(|rw| match position {
284                     MacroPosition::Item => format!("{};", rw),
285                     _ => rw,
286                 })
287             }
288         }
289         Delimiter::Bracket => {
290             // Handle special case: `vec![expr; expr]`
291             if vec_with_semi {
292                 handle_vec_semi(context, shape, arg_vec, macro_name, style)
293             } else {
294                 // If we are rewriting `vec!` macro or other special macros,
295                 // then we can rewrite this as a usual array literal.
296                 // Otherwise, we must preserve the original existence of trailing comma.
297                 let macro_name = &macro_name.as_str();
298                 let mut force_trailing_comma = if trailing_comma {
299                     Some(SeparatorTactic::Always)
300                 } else {
301                     Some(SeparatorTactic::Never)
302                 };
303                 if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
304                     context.leave_macro();
305                     if context.use_block_indent() {
306                         force_trailing_comma = Some(SeparatorTactic::Vertical);
307                     };
308                 }
309                 let rewrite = rewrite_array(
310                     macro_name,
311                     arg_vec.iter(),
312                     mac.span(),
313                     context,
314                     shape,
315                     force_trailing_comma,
316                     Some(original_style),
317                 )?;
318                 let comma = match position {
319                     MacroPosition::Item => ";",
320                     _ => "",
321                 };
322
323                 Some(format!("{}{}", rewrite, comma))
324             }
325         }
326         Delimiter::Brace => {
327             // For macro invocations with braces, always put a space between
328             // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
329             // anything in between the braces (for now).
330             let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
331             match trim_left_preserve_layout(snippet, shape.indent, context.config) {
332                 Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
333                 None => Some(format!("{} {}", macro_name, snippet)),
334             }
335         }
336         _ => unreachable!(),
337     }
338 }
339
340 fn handle_vec_semi(
341     context: &RewriteContext<'_>,
342     shape: Shape,
343     arg_vec: Vec<MacroArg>,
344     macro_name: String,
345     delim_token: Delimiter,
346 ) -> Option<String> {
347     let (left, right) = match delim_token {
348         Delimiter::Parenthesis => ("(", ")"),
349         Delimiter::Bracket => ("[", "]"),
350         _ => unreachable!(),
351     };
352
353     let mac_shape = shape.offset_left(macro_name.len())?;
354     // 8 = `vec![]` + `; ` or `vec!()` + `; `
355     let total_overhead = 8;
356     let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
357     let lhs = arg_vec[0].rewrite(context, nested_shape)?;
358     let rhs = arg_vec[1].rewrite(context, nested_shape)?;
359     if !lhs.contains('\n')
360         && !rhs.contains('\n')
361         && lhs.len() + rhs.len() + total_overhead <= shape.width
362     {
363         // macro_name(lhs; rhs) or macro_name[lhs; rhs]
364         Some(format!("{}{}{}; {}{}", macro_name, left, lhs, rhs, right))
365     } else {
366         // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
367         Some(format!(
368             "{}{}{}{};{}{}{}{}",
369             macro_name,
370             left,
371             nested_shape.indent.to_string_with_newline(context.config),
372             lhs,
373             nested_shape.indent.to_string_with_newline(context.config),
374             rhs,
375             shape.indent.to_string_with_newline(context.config),
376             right
377         ))
378     }
379 }
380
381 pub(crate) fn rewrite_macro_def(
382     context: &RewriteContext<'_>,
383     shape: Shape,
384     indent: Indent,
385     def: &ast::MacroDef,
386     ident: symbol::Ident,
387     vis: &ast::Visibility,
388     span: Span,
389 ) -> Option<String> {
390     let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
391     if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
392         return snippet;
393     }
394
395     let ts = def.body.tokens.clone();
396     let mut parser = MacroParser::new(ts.into_trees());
397     let parsed_def = match parser.parse() {
398         Some(def) => def,
399         None => return snippet,
400     };
401
402     let mut result = if def.macro_rules {
403         String::from("macro_rules!")
404     } else {
405         format!("{}macro", format_visibility(context, vis))
406     };
407
408     result += " ";
409     result += rewrite_ident(context, ident);
410
411     let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
412
413     let arm_shape = if multi_branch_style {
414         shape
415             .block_indent(context.config.tab_spaces())
416             .with_max_width(context.config)
417     } else {
418         shape
419     };
420
421     let branch_items = itemize_list(
422         context.snippet_provider,
423         parsed_def.branches.iter(),
424         "}",
425         ";",
426         |branch| branch.span.lo(),
427         |branch| branch.span.hi(),
428         |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
429             Some(v) => Some(v),
430             // if the rewrite returned None because a macro could not be rewritten, then return the
431             // original body
432             None if context.macro_rewrite_failure.get() => {
433                 Some(context.snippet(branch.body).trim().to_string())
434             }
435             None => None,
436         },
437         context.snippet_provider.span_after(span, "{"),
438         span.hi(),
439         false,
440     )
441     .collect::<Vec<_>>();
442
443     let fmt = ListFormatting::new(arm_shape, context.config)
444         .separator(if def.macro_rules { ";" } else { "" })
445         .trailing_separator(SeparatorTactic::Always)
446         .preserve_newline(true);
447
448     if multi_branch_style {
449         result += " {";
450         result += &arm_shape.indent.to_string_with_newline(context.config);
451     }
452
453     match write_list(&branch_items, &fmt) {
454         Some(ref s) => result += s,
455         None => return snippet,
456     }
457
458     if multi_branch_style {
459         result += &indent.to_string_with_newline(context.config);
460         result += "}";
461     }
462
463     Some(result)
464 }
465
466 fn register_metavariable(
467     map: &mut HashMap<String, String>,
468     result: &mut String,
469     name: &str,
470     dollar_count: usize,
471 ) {
472     let mut new_name = "$".repeat(dollar_count - 1);
473     let mut old_name = "$".repeat(dollar_count);
474
475     new_name.push('z');
476     new_name.push_str(name);
477     old_name.push_str(name);
478
479     result.push_str(&new_name);
480     map.insert(old_name, new_name);
481 }
482
483 // Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
484 // aren't causing problems.
485 // This should also work for escaped `$` variables, where we leave earlier `$`s.
486 fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
487     // Each substitution will require five or six extra bytes.
488     let mut result = String::with_capacity(input.len() + 64);
489     let mut substs = HashMap::new();
490     let mut dollar_count = 0;
491     let mut cur_name = String::new();
492
493     for (kind, c) in CharClasses::new(input.chars()) {
494         if kind != FullCodeCharKind::Normal {
495             result.push(c);
496         } else if c == '$' {
497             dollar_count += 1;
498         } else if dollar_count == 0 {
499             result.push(c);
500         } else if !c.is_alphanumeric() && !cur_name.is_empty() {
501             // Terminates a name following one or more dollars.
502             register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
503
504             result.push(c);
505             dollar_count = 0;
506             cur_name.clear();
507         } else if c == '(' && cur_name.is_empty() {
508             // FIXME: Support macro def with repeat.
509             return None;
510         } else if c.is_alphanumeric() || c == '_' {
511             cur_name.push(c);
512         }
513     }
514
515     if !cur_name.is_empty() {
516         register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
517     }
518
519     debug!("replace_names `{}` {:?}", result, substs);
520
521     Some((result, substs))
522 }
523
524 #[derive(Debug, Clone)]
525 enum MacroArgKind {
526     /// e.g., `$x: expr`.
527     MetaVariable(Symbol, String),
528     /// e.g., `$($foo: expr),*`
529     Repeat(
530         /// `()`, `[]` or `{}`.
531         Delimiter,
532         /// Inner arguments inside delimiters.
533         Vec<ParsedMacroArg>,
534         /// Something after the closing delimiter and the repeat token, if available.
535         Option<Box<ParsedMacroArg>>,
536         /// The repeat token. This could be one of `*`, `+` or `?`.
537         Token,
538     ),
539     /// e.g., `[derive(Debug)]`
540     Delimited(Delimiter, Vec<ParsedMacroArg>),
541     /// A possible separator. e.g., `,` or `;`.
542     Separator(String, String),
543     /// Other random stuff that does not fit to other kinds.
544     /// e.g., `== foo` in `($x: expr == foo)`.
545     Other(String, String),
546 }
547
548 fn delim_token_to_str(
549     context: &RewriteContext<'_>,
550     delim_token: Delimiter,
551     shape: Shape,
552     use_multiple_lines: bool,
553     inner_is_empty: bool,
554 ) -> (String, String) {
555     let (lhs, rhs) = match delim_token {
556         Delimiter::Parenthesis => ("(", ")"),
557         Delimiter::Bracket => ("[", "]"),
558         Delimiter::Brace => {
559             if inner_is_empty || use_multiple_lines {
560                 ("{", "}")
561             } else {
562                 ("{ ", " }")
563             }
564         }
565         Delimiter::Invisible => unreachable!(),
566     };
567     if use_multiple_lines {
568         let indent_str = shape.indent.to_string_with_newline(context.config);
569         let nested_indent_str = shape
570             .indent
571             .block_indent(context.config)
572             .to_string_with_newline(context.config);
573         (
574             format!("{}{}", lhs, nested_indent_str),
575             format!("{}{}", indent_str, rhs),
576         )
577     } else {
578         (lhs.to_owned(), rhs.to_owned())
579     }
580 }
581
582 impl MacroArgKind {
583     fn starts_with_brace(&self) -> bool {
584         matches!(
585             *self,
586             MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
587                 | MacroArgKind::Delimited(Delimiter::Brace, _)
588         )
589     }
590
591     fn starts_with_dollar(&self) -> bool {
592         matches!(
593             *self,
594             MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
595         )
596     }
597
598     fn ends_with_space(&self) -> bool {
599         matches!(*self, MacroArgKind::Separator(..))
600     }
601
602     fn has_meta_var(&self) -> bool {
603         match *self {
604             MacroArgKind::MetaVariable(..) => true,
605             MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
606             _ => false,
607         }
608     }
609
610     fn rewrite(
611         &self,
612         context: &RewriteContext<'_>,
613         shape: Shape,
614         use_multiple_lines: bool,
615     ) -> Option<String> {
616         let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
617             let inner = wrap_macro_args(context, args, shape)?;
618             let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
619             if lhs.len() + inner.len() + rhs.len() <= shape.width {
620                 return Some((lhs, inner, rhs));
621             }
622
623             let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
624             let nested_shape = shape
625                 .block_indent(context.config.tab_spaces())
626                 .with_max_width(context.config);
627             let inner = wrap_macro_args(context, args, nested_shape)?;
628             Some((lhs, inner, rhs))
629         };
630
631         match *self {
632             MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${}:{}", name, ty)),
633             MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
634                 let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
635                 let another = another
636                     .as_ref()
637                     .and_then(|a| a.rewrite(context, shape, use_multiple_lines))
638                     .unwrap_or_else(|| "".to_owned());
639                 let repeat_tok = pprust::token_to_string(tok);
640
641                 Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
642             }
643             MacroArgKind::Delimited(delim_tok, ref args) => {
644                 rewrite_delimited_inner(delim_tok, args)
645                     .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
646             }
647             MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
648             MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
649         }
650     }
651 }
652
653 #[derive(Debug, Clone)]
654 struct ParsedMacroArg {
655     kind: MacroArgKind,
656 }
657
658 impl ParsedMacroArg {
659     fn rewrite(
660         &self,
661         context: &RewriteContext<'_>,
662         shape: Shape,
663         use_multiple_lines: bool,
664     ) -> Option<String> {
665         self.kind.rewrite(context, shape, use_multiple_lines)
666     }
667 }
668
669 /// Parses macro arguments on macro def.
670 struct MacroArgParser {
671     /// Either a name of the next metavariable, a separator, or junk.
672     buf: String,
673     /// The first token of the current buffer.
674     start_tok: Token,
675     /// `true` if we are parsing a metavariable or a repeat.
676     is_meta_var: bool,
677     /// The last token parsed.
678     last_tok: Token,
679     /// Holds the parsed arguments.
680     result: Vec<ParsedMacroArg>,
681 }
682
683 fn last_tok(tt: &TokenTree) -> Token {
684     match *tt {
685         TokenTree::Token(ref t, _) => t.clone(),
686         TokenTree::Delimited(delim_span, delim, _) => Token {
687             kind: TokenKind::CloseDelim(delim),
688             span: delim_span.close,
689         },
690     }
691 }
692
693 impl MacroArgParser {
694     fn new() -> MacroArgParser {
695         MacroArgParser {
696             buf: String::new(),
697             is_meta_var: false,
698             last_tok: Token {
699                 kind: TokenKind::Eof,
700                 span: DUMMY_SP,
701             },
702             start_tok: Token {
703                 kind: TokenKind::Eof,
704                 span: DUMMY_SP,
705             },
706             result: vec![],
707         }
708     }
709
710     fn set_last_tok(&mut self, tok: &TokenTree) {
711         self.last_tok = last_tok(tok);
712     }
713
714     fn add_separator(&mut self) {
715         let prefix = if self.need_space_prefix() {
716             " ".to_owned()
717         } else {
718             "".to_owned()
719         };
720         self.result.push(ParsedMacroArg {
721             kind: MacroArgKind::Separator(self.buf.clone(), prefix),
722         });
723         self.buf.clear();
724     }
725
726     fn add_other(&mut self) {
727         let prefix = if self.need_space_prefix() {
728             " ".to_owned()
729         } else {
730             "".to_owned()
731         };
732         self.result.push(ParsedMacroArg {
733             kind: MacroArgKind::Other(self.buf.clone(), prefix),
734         });
735         self.buf.clear();
736     }
737
738     fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
739         match iter.next() {
740             Some(TokenTree::Token(
741                 Token {
742                     kind: TokenKind::Ident(name, _),
743                     ..
744                 },
745                 _,
746             )) => {
747                 self.result.push(ParsedMacroArg {
748                     kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
749                 });
750
751                 self.buf.clear();
752                 self.is_meta_var = false;
753                 Some(())
754             }
755             _ => None,
756         }
757     }
758
759     fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
760         self.result.push(ParsedMacroArg {
761             kind: MacroArgKind::Delimited(delim, inner),
762         });
763     }
764
765     // $($foo: expr),?
766     fn add_repeat(
767         &mut self,
768         inner: Vec<ParsedMacroArg>,
769         delim: Delimiter,
770         iter: &mut Cursor,
771     ) -> Option<()> {
772         let mut buffer = String::new();
773         let mut first = true;
774
775         // Parse '*', '+' or '?.
776         for tok in iter {
777             self.set_last_tok(&tok);
778             if first {
779                 first = false;
780             }
781
782             match tok {
783                 TokenTree::Token(
784                     Token {
785                         kind: TokenKind::BinOp(BinOpToken::Plus),
786                         ..
787                     },
788                     _,
789                 )
790                 | TokenTree::Token(
791                     Token {
792                         kind: TokenKind::Question,
793                         ..
794                     },
795                     _,
796                 )
797                 | TokenTree::Token(
798                     Token {
799                         kind: TokenKind::BinOp(BinOpToken::Star),
800                         ..
801                     },
802                     _,
803                 ) => {
804                     break;
805                 }
806                 TokenTree::Token(ref t, _) => {
807                     buffer.push_str(&pprust::token_to_string(t));
808                 }
809                 _ => return None,
810             }
811         }
812
813         // There could be some random stuff between ')' and '*', '+' or '?'.
814         let another = if buffer.trim().is_empty() {
815             None
816         } else {
817             Some(Box::new(ParsedMacroArg {
818                 kind: MacroArgKind::Other(buffer, "".to_owned()),
819             }))
820         };
821
822         self.result.push(ParsedMacroArg {
823             kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
824         });
825         Some(())
826     }
827
828     fn update_buffer(&mut self, t: &Token) {
829         if self.buf.is_empty() {
830             self.start_tok = t.clone();
831         } else {
832             let needs_space = match next_space(&self.last_tok.kind) {
833                 SpaceState::Ident => ident_like(t),
834                 SpaceState::Punctuation => !ident_like(t),
835                 SpaceState::Always => true,
836                 SpaceState::Never => false,
837             };
838             if force_space_before(&t.kind) || needs_space {
839                 self.buf.push(' ');
840             }
841         }
842
843         self.buf.push_str(&pprust::token_to_string(t));
844     }
845
846     fn need_space_prefix(&self) -> bool {
847         if self.result.is_empty() {
848             return false;
849         }
850
851         let last_arg = self.result.last().unwrap();
852         if let MacroArgKind::MetaVariable(..) = last_arg.kind {
853             if ident_like(&self.start_tok) {
854                 return true;
855             }
856             if self.start_tok.kind == TokenKind::Colon {
857                 return true;
858             }
859         }
860
861         if force_space_before(&self.start_tok.kind) {
862             return true;
863         }
864
865         false
866     }
867
868     /// Returns a collection of parsed macro def's arguments.
869     fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
870         let mut iter = tokens.into_trees();
871
872         while let Some(tok) = iter.next() {
873             match tok {
874                 TokenTree::Token(
875                     Token {
876                         kind: TokenKind::Dollar,
877                         span,
878                     },
879                     _,
880                 ) => {
881                     // We always want to add a separator before meta variables.
882                     if !self.buf.is_empty() {
883                         self.add_separator();
884                     }
885
886                     // Start keeping the name of this metavariable in the buffer.
887                     self.is_meta_var = true;
888                     self.start_tok = Token {
889                         kind: TokenKind::Dollar,
890                         span,
891                     };
892                 }
893                 TokenTree::Token(
894                     Token {
895                         kind: TokenKind::Colon,
896                         ..
897                     },
898                     _,
899                 ) if self.is_meta_var => {
900                     self.add_meta_variable(&mut iter)?;
901                 }
902                 TokenTree::Token(ref t, _) => self.update_buffer(t),
903                 TokenTree::Delimited(_delimited_span, delimited, ref tts) => {
904                     if !self.buf.is_empty() {
905                         if next_space(&self.last_tok.kind) == SpaceState::Always {
906                             self.add_separator();
907                         } else {
908                             self.add_other();
909                         }
910                     }
911
912                     // Parse the stuff inside delimiters.
913                     let parser = MacroArgParser::new();
914                     let delimited_arg = parser.parse(tts.clone())?;
915
916                     if self.is_meta_var {
917                         self.add_repeat(delimited_arg, delimited, &mut iter)?;
918                         self.is_meta_var = false;
919                     } else {
920                         self.add_delimited(delimited_arg, delimited);
921                     }
922                 }
923             }
924
925             self.set_last_tok(&tok);
926         }
927
928         // We are left with some stuff in the buffer. Since there is nothing
929         // left to separate, add this as `Other`.
930         if !self.buf.is_empty() {
931             self.add_other();
932         }
933
934         Some(self.result)
935     }
936 }
937
938 fn wrap_macro_args(
939     context: &RewriteContext<'_>,
940     args: &[ParsedMacroArg],
941     shape: Shape,
942 ) -> Option<String> {
943     wrap_macro_args_inner(context, args, shape, false)
944         .or_else(|| wrap_macro_args_inner(context, args, shape, true))
945 }
946
947 fn wrap_macro_args_inner(
948     context: &RewriteContext<'_>,
949     args: &[ParsedMacroArg],
950     shape: Shape,
951     use_multiple_lines: bool,
952 ) -> Option<String> {
953     let mut result = String::with_capacity(128);
954     let mut iter = args.iter().peekable();
955     let indent_str = shape.indent.to_string_with_newline(context.config);
956
957     while let Some(arg) = iter.next() {
958         result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
959
960         if use_multiple_lines
961             && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
962         {
963             if arg.kind.ends_with_space() {
964                 result.pop();
965             }
966             result.push_str(&indent_str);
967         } else if let Some(next_arg) = iter.peek() {
968             let space_before_dollar =
969                 !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
970             let space_before_brace = next_arg.kind.starts_with_brace();
971             if space_before_dollar || space_before_brace {
972                 result.push(' ');
973             }
974         }
975     }
976
977     if !use_multiple_lines && result.len() >= shape.width {
978         None
979     } else {
980         Some(result)
981     }
982 }
983
984 // This is a bit sketchy. The token rules probably need tweaking, but it works
985 // for some common cases. I hope the basic logic is sufficient. Note that the
986 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
987 // and `(`/`)` have special meaning.
988 //
989 // We always try and format on one line.
990 // FIXME: Use multi-line when every thing does not fit on one line.
991 fn format_macro_args(
992     context: &RewriteContext<'_>,
993     token_stream: TokenStream,
994     shape: Shape,
995 ) -> Option<String> {
996     if !context.config.format_macro_matchers() {
997         let span = span_for_token_stream(&token_stream);
998         return Some(match span {
999             Some(span) => context.snippet(span).to_owned(),
1000             None => String::new(),
1001         });
1002     }
1003     let parsed_args = MacroArgParser::new().parse(token_stream)?;
1004     wrap_macro_args(context, &parsed_args, shape)
1005 }
1006
1007 fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
1008     token_stream.trees().next().map(|tt| tt.span())
1009 }
1010
1011 // We should insert a space if the next token is a:
1012 #[derive(Copy, Clone, PartialEq)]
1013 enum SpaceState {
1014     Never,
1015     Punctuation,
1016     Ident, // Or ident/literal-like thing.
1017     Always,
1018 }
1019
1020 fn force_space_before(tok: &TokenKind) -> bool {
1021     debug!("tok: force_space_before {:?}", tok);
1022
1023     match tok {
1024         TokenKind::Eq
1025         | TokenKind::Lt
1026         | TokenKind::Le
1027         | TokenKind::EqEq
1028         | TokenKind::Ne
1029         | TokenKind::Ge
1030         | TokenKind::Gt
1031         | TokenKind::AndAnd
1032         | TokenKind::OrOr
1033         | TokenKind::Not
1034         | TokenKind::Tilde
1035         | TokenKind::BinOpEq(_)
1036         | TokenKind::At
1037         | TokenKind::RArrow
1038         | TokenKind::LArrow
1039         | TokenKind::FatArrow
1040         | TokenKind::BinOp(_)
1041         | TokenKind::Pound
1042         | TokenKind::Dollar => true,
1043         _ => false,
1044     }
1045 }
1046
1047 fn ident_like(tok: &Token) -> bool {
1048     matches!(
1049         tok.kind,
1050         TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(_)
1051     )
1052 }
1053
1054 fn next_space(tok: &TokenKind) -> SpaceState {
1055     debug!("next_space: {:?}", tok);
1056
1057     match tok {
1058         TokenKind::Not
1059         | TokenKind::BinOp(BinOpToken::And)
1060         | TokenKind::Tilde
1061         | TokenKind::At
1062         | TokenKind::Comma
1063         | TokenKind::Dot
1064         | TokenKind::DotDot
1065         | TokenKind::DotDotDot
1066         | TokenKind::DotDotEq
1067         | TokenKind::Question => SpaceState::Punctuation,
1068
1069         TokenKind::ModSep
1070         | TokenKind::Pound
1071         | TokenKind::Dollar
1072         | TokenKind::OpenDelim(_)
1073         | TokenKind::CloseDelim(_) => SpaceState::Never,
1074
1075         TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(_) => SpaceState::Ident,
1076
1077         _ => SpaceState::Always,
1078     }
1079 }
1080
1081 /// Tries to convert a macro use into a short hand try expression. Returns `None`
1082 /// when the macro is not an instance of `try!` (or parsing the inner expression
1083 /// failed).
1084 pub(crate) fn convert_try_mac(
1085     mac: &ast::MacCall,
1086     context: &RewriteContext<'_>,
1087 ) -> Option<ast::Expr> {
1088     let path = &pprust::path_to_string(&mac.path);
1089     if path == "try" || path == "r#try" {
1090         let ts = mac.args.tokens.clone();
1091
1092         Some(ast::Expr {
1093             id: ast::NodeId::root(), // dummy value
1094             kind: ast::ExprKind::Try(parse_expr(context, ts)?),
1095             span: mac.span(), // incorrect span, but shouldn't matter too much
1096             attrs: ast::AttrVec::new(),
1097             tokens: None,
1098         })
1099     } else {
1100         None
1101     }
1102 }
1103
1104 pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
1105     let snippet = context.snippet(mac.span());
1106     let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());
1107     let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::max_value());
1108     let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::max_value());
1109
1110     if paren_pos < bracket_pos && paren_pos < brace_pos {
1111         Delimiter::Parenthesis
1112     } else if bracket_pos < brace_pos {
1113         Delimiter::Bracket
1114     } else {
1115         Delimiter::Brace
1116     }
1117 }
1118
1119 // A very simple parser that just parses a macros 2.0 definition into its branches.
1120 // Currently we do not attempt to parse any further than that.
1121 #[derive(new)]
1122 struct MacroParser {
1123     toks: Cursor,
1124 }
1125
1126 impl MacroParser {
1127     // (`(` ... `)` `=>` `{` ... `}`)*
1128     fn parse(&mut self) -> Option<Macro> {
1129         let mut branches = vec![];
1130         while self.toks.look_ahead(1).is_some() {
1131             branches.push(self.parse_branch()?);
1132         }
1133
1134         Some(Macro { branches })
1135     }
1136
1137     // `(` ... `)` `=>` `{` ... `}`
1138     fn parse_branch(&mut self) -> Option<MacroBranch> {
1139         let tok = self.toks.next()?;
1140         let (lo, args_paren_kind) = match tok {
1141             TokenTree::Token(..) => return None,
1142             TokenTree::Delimited(delimited_span, d, _) => (delimited_span.open.lo(), d),
1143         };
1144         let args = TokenStream::new(vec![tok]);
1145         match self.toks.next()? {
1146             TokenTree::Token(
1147                 Token {
1148                     kind: TokenKind::FatArrow,
1149                     ..
1150                 },
1151                 _,
1152             ) => {}
1153             _ => return None,
1154         }
1155         let (mut hi, body, whole_body) = match self.toks.next()? {
1156             TokenTree::Token(..) => return None,
1157             TokenTree::Delimited(delimited_span, ..) => {
1158                 let data = delimited_span.entire().data();
1159                 (
1160                     data.hi,
1161                     Span::new(
1162                         data.lo + BytePos(1),
1163                         data.hi - BytePos(1),
1164                         data.ctxt,
1165                         data.parent,
1166                     ),
1167                     delimited_span.entire(),
1168                 )
1169             }
1170         };
1171         if let Some(TokenTree::Token(
1172             Token {
1173                 kind: TokenKind::Semi,
1174                 span,
1175             },
1176             _,
1177         )) = self.toks.look_ahead(0)
1178         {
1179             hi = span.hi();
1180             self.toks.next();
1181         }
1182         Some(MacroBranch {
1183             span: mk_sp(lo, hi),
1184             args_paren_kind,
1185             args,
1186             body,
1187             whole_body,
1188         })
1189     }
1190 }
1191
1192 // A parsed macros 2.0 macro definition.
1193 struct Macro {
1194     branches: Vec<MacroBranch>,
1195 }
1196
1197 // FIXME: it would be more efficient to use references to the token streams
1198 // rather than clone them, if we can make the borrowing work out.
1199 struct MacroBranch {
1200     span: Span,
1201     args_paren_kind: Delimiter,
1202     args: TokenStream,
1203     body: Span,
1204     whole_body: Span,
1205 }
1206
1207 impl MacroBranch {
1208     fn rewrite(
1209         &self,
1210         context: &RewriteContext<'_>,
1211         shape: Shape,
1212         multi_branch_style: bool,
1213     ) -> Option<String> {
1214         // Only attempt to format function-like macros.
1215         if self.args_paren_kind != Delimiter::Parenthesis {
1216             // FIXME(#1539): implement for non-sugared macros.
1217             return None;
1218         }
1219
1220         // 5 = " => {"
1221         let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
1222
1223         if multi_branch_style {
1224             result += " =>";
1225         }
1226
1227         if !context.config.format_macro_bodies() {
1228             result += " ";
1229             result += context.snippet(self.whole_body);
1230             return Some(result);
1231         }
1232
1233         // The macro body is the most interesting part. It might end up as various
1234         // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1235         // parsed as regular Rust code (and note that these can be escaped using
1236         // `$$`). We'll try and format like an AST node, but we'll substitute
1237         // variables for new names with the same length first.
1238
1239         let old_body = context.snippet(self.body).trim();
1240         let (body_str, substs) = replace_names(old_body)?;
1241         let has_block_body = old_body.starts_with('{');
1242
1243         let mut config = context.config.clone();
1244         config.set().hide_parse_errors(true);
1245
1246         result += " {";
1247
1248         let body_indent = if has_block_body {
1249             shape.indent
1250         } else {
1251             shape.indent.block_indent(&config)
1252         };
1253         let new_width = config.max_width() - body_indent.width();
1254         config.set().max_width(new_width);
1255
1256         // First try to format as items, then as statements.
1257         let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
1258             Some(new_body) => new_body,
1259             None => {
1260                 let new_width = new_width + config.tab_spaces();
1261                 config.set().max_width(new_width);
1262                 match crate::format_code_block(&body_str, &config, true) {
1263                     Some(new_body) => new_body,
1264                     None => return None,
1265                 }
1266             }
1267         };
1268         let new_body = wrap_str(
1269             new_body_snippet.snippet.to_string(),
1270             config.max_width(),
1271             shape,
1272         )?;
1273
1274         // Indent the body since it is in a block.
1275         let indent_str = body_indent.to_string(&config);
1276         let mut new_body = LineClasses::new(new_body.trim_end())
1277             .enumerate()
1278             .fold(
1279                 (String::new(), true),
1280                 |(mut s, need_indent), (i, (kind, ref l))| {
1281                     if !is_empty_line(l)
1282                         && need_indent
1283                         && !new_body_snippet.is_line_non_formatted(i + 1)
1284                     {
1285                         s += &indent_str;
1286                     }
1287                     (s + l + "\n", indent_next_line(kind, l, &config))
1288                 },
1289             )
1290             .0;
1291
1292         // Undo our replacement of macro variables.
1293         // FIXME: this could be *much* more efficient.
1294         for (old, new) in &substs {
1295             if old_body.contains(new) {
1296                 debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
1297                 return None;
1298             }
1299             new_body = new_body.replace(new, old);
1300         }
1301
1302         if has_block_body {
1303             result += new_body.trim();
1304         } else if !new_body.is_empty() {
1305             result += "\n";
1306             result += &new_body;
1307             result += &shape.indent.to_string(&config);
1308         }
1309
1310         result += "}";
1311
1312         Some(result)
1313     }
1314 }
1315
1316 /// Format `lazy_static!` from <https://crates.io/crates/lazy_static>.
1317 ///
1318 /// # Expected syntax
1319 ///
1320 /// ```text
1321 /// lazy_static! {
1322 ///     [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1323 ///     [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1324 ///     ...
1325 ///     [pub] static ref NAME_N: TYPE_N = EXPR_N;
1326 /// }
1327 /// ```
1328 fn format_lazy_static(
1329     context: &RewriteContext<'_>,
1330     shape: Shape,
1331     ts: TokenStream,
1332 ) -> Option<String> {
1333     let mut result = String::with_capacity(1024);
1334     let nested_shape = shape
1335         .block_indent(context.config.tab_spaces())
1336         .with_max_width(context.config);
1337
1338     result.push_str("lazy_static! {");
1339     result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1340
1341     let parsed_elems = parse_lazy_static(context, ts)?;
1342     let last = parsed_elems.len() - 1;
1343     for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
1344         // Rewrite as a static item.
1345         let vis = crate::utils::format_visibility(context, vis);
1346         let mut stmt = String::with_capacity(128);
1347         stmt.push_str(&format!(
1348             "{}static ref {}: {} =",
1349             vis,
1350             id,
1351             ty.rewrite(context, nested_shape)?
1352         ));
1353         result.push_str(&rewrite_assign_rhs(
1354             context,
1355             stmt,
1356             &*expr,
1357             &RhsAssignKind::Expr(&expr.kind, expr.span),
1358             nested_shape.sub_width(1)?,
1359         )?);
1360         result.push(';');
1361         if i != last {
1362             result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1363         }
1364     }
1365
1366     result.push_str(&shape.indent.to_string_with_newline(context.config));
1367     result.push('}');
1368
1369     Some(result)
1370 }
1371
1372 fn rewrite_macro_with_items(
1373     context: &RewriteContext<'_>,
1374     items: &[MacroArg],
1375     macro_name: &str,
1376     shape: Shape,
1377     style: Delimiter,
1378     position: MacroPosition,
1379     span: Span,
1380 ) -> Option<String> {
1381     let (opener, closer) = match style {
1382         Delimiter::Parenthesis => ("(", ")"),
1383         Delimiter::Bracket => ("[", "]"),
1384         Delimiter::Brace => (" {", "}"),
1385         _ => return None,
1386     };
1387     let trailing_semicolon = match style {
1388         Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
1389         _ => "",
1390     };
1391
1392     let mut visitor = FmtVisitor::from_context(context);
1393     visitor.block_indent = shape.indent.block_indent(context.config);
1394     visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
1395     for item in items {
1396         let item = match item {
1397             MacroArg::Item(item) => item,
1398             _ => return None,
1399         };
1400         visitor.visit_item(item);
1401     }
1402
1403     let mut result = String::with_capacity(256);
1404     result.push_str(macro_name);
1405     result.push_str(opener);
1406     result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1407     result.push_str(visitor.buffer.trim());
1408     result.push_str(&shape.indent.to_string_with_newline(context.config));
1409     result.push_str(closer);
1410     result.push_str(trailing_semicolon);
1411     Some(result)
1412 }