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