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
9 // List-like invocations with parentheses will be formatted as function calls,
10 // and those with brackets will be formatted as array literals.
12 use std::collections::HashMap;
13 use std::panic::{catch_unwind, AssertUnwindSafe};
15 use syntax::parse::new_parser_from_tts;
16 use syntax::parse::parser::Parser;
17 use syntax::parse::token::{BinOpToken, DelimToken, Token};
18 use syntax::print::pprust;
19 use syntax::source_map::{BytePos, Span};
20 use syntax::symbol::keywords;
21 use syntax::tokenstream::{Cursor, TokenStream, TokenTree};
23 use syntax::{ast, parse, ptr};
26 contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
28 use crate::config::lists::*;
29 use crate::expr::rewrite_array;
30 use crate::lists::{itemize_list, write_list, ListFormatting};
32 use crate::rewrite::{Rewrite, RewriteContext};
33 use crate::shape::{Indent, Shape};
34 use crate::source_map::SpanUtils;
35 use crate::spanned::Spanned;
37 format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces,
38 rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt,
40 use crate::visitor::FmtVisitor;
42 const FORCED_BRACKET_MACROS: &[&str] = &["vec!"];
44 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
45 pub(crate) enum MacroPosition {
53 pub(crate) enum MacroArg {
54 Expr(ptr::P<ast::Expr>),
56 Pat(ptr::P<ast::Pat>),
57 Item(ptr::P<ast::Item>),
58 Keyword(ast::Ident, Span),
62 fn is_item(&self) -> bool {
64 MacroArg::Item(..) => true,
70 impl Rewrite for ast::Item {
71 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
72 let mut visitor = crate::visitor::FmtVisitor::from_context(context);
73 visitor.block_indent = shape.indent;
74 visitor.last_pos = self.span().lo();
75 visitor.visit_item(self);
76 Some(visitor.buffer.to_owned())
80 impl Rewrite for MacroArg {
81 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
83 MacroArg::Expr(ref expr) => expr.rewrite(context, shape),
84 MacroArg::Ty(ref ty) => ty.rewrite(context, shape),
85 MacroArg::Pat(ref pat) => pat.rewrite(context, shape),
86 MacroArg::Item(ref item) => item.rewrite(context, shape),
87 MacroArg::Keyword(ident, _) => Some(ident.to_string()),
92 fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
93 macro_rules! parse_macro_arg {
94 ($macro_arg:ident, $parser:expr, $f:expr) => {
95 let mut cloned_parser = (*parser).clone();
96 match $parser(&mut cloned_parser) {
98 if parser.sess.span_diagnostic.has_errors() {
99 parser.sess.span_diagnostic.reset_err_count();
101 // Parsing succeeded.
102 *parser = cloned_parser;
103 return Some(MacroArg::$macro_arg($f(x)?));
108 parser.sess.span_diagnostic.reset_err_count();
116 |parser: &mut parse::parser::Parser<'b>| parser.parse_expr(),
117 |x: ptr::P<ast::Expr>| Some(x)
121 |parser: &mut parse::parser::Parser<'b>| parser.parse_ty(),
122 |x: ptr::P<ast::Ty>| Some(x)
126 |parser: &mut parse::parser::Parser<'b>| parser.parse_pat(None),
127 |x: ptr::P<ast::Pat>| Some(x)
129 // `parse_item` returns `Option<ptr::P<ast::Item>>`.
132 |parser: &mut parse::parser::Parser<'b>| parser.parse_item(),
133 |x: Option<ptr::P<ast::Item>>| x
139 /// Rewrite macro name without using pretty-printer if possible.
140 fn rewrite_macro_name(
141 context: &RewriteContext<'_>,
143 extra_ident: Option<ast::Ident>,
145 let name = if path.segments.len() == 1 {
146 // Avoid using pretty-printer in the common case.
147 format!("{}!", rewrite_ident(context, path.segments[0].ident))
152 Some(ident) if ident != keywords::Invalid.ident() => format!("{} {}", name, ident),
157 // Use this on failing to format the macro call.
158 fn return_macro_parse_failure_fallback(
159 context: &RewriteContext<'_>,
162 ) -> Option<String> {
163 // Mark this as a failure however we format it
164 context.macro_rewrite_failure.replace(true);
166 // Heuristically determine whether the last line of the macro uses "Block" style
167 // rather than using "Visual" style, or another indentation style.
168 let is_like_block_indent_style = context
172 .map(|closing_line| {
173 closing_line.trim().chars().all(|ch| match ch {
174 '}' | ')' | ']' => true,
179 if is_like_block_indent_style {
180 return trim_left_preserve_layout(context.snippet(span), indent, &context.config);
183 // Return the snippet unmodified if the macro is not block-like
184 Some(context.snippet(span).to_owned())
187 struct InsideMacroGuard<'a> {
188 context: &'a RewriteContext<'a>,
192 impl<'a> InsideMacroGuard<'a> {
193 fn inside_macro_context(context: &'a RewriteContext<'_>) -> InsideMacroGuard<'a> {
194 let is_nested = context.inside_macro.replace(true);
195 InsideMacroGuard { context, is_nested }
199 impl<'a> Drop for InsideMacroGuard<'a> {
201 self.context.inside_macro.replace(self.is_nested);
205 pub(crate) fn rewrite_macro(
207 extra_ident: Option<ast::Ident>,
208 context: &RewriteContext<'_>,
210 position: MacroPosition,
211 ) -> Option<String> {
212 catch_unwind(AssertUnwindSafe(|| {
213 let should_skip = context
216 .contains(&context.snippet(mac.node.path.span).to_owned());
220 let guard = InsideMacroGuard::inside_macro_context(context);
222 rewrite_macro_inner(mac, extra_ident, context, shape, position, guard.is_nested);
223 if result.is_none() {
224 context.macro_rewrite_failure.replace(true);
232 fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
233 for &keyword in RUST_KEYWORDS.iter() {
234 if parser.token.is_keyword(keyword)
235 && parser.look_ahead(1, |t| {
237 || *t == Token::Comma
238 || *t == Token::CloseDelim(DelimToken::NoDelim)
241 let macro_arg = MacroArg::Keyword(keyword.ident(), parser.span);
243 return Some(macro_arg);
249 fn rewrite_macro_inner(
251 extra_ident: Option<ast::Ident>,
252 context: &RewriteContext<'_>,
254 position: MacroPosition,
255 is_nested_macro: bool,
256 ) -> Option<String> {
257 if context.config.use_try_shorthand() {
258 if let Some(expr) = convert_try_mac(mac, context) {
259 context.inside_macro.replace(false);
260 return expr.rewrite(context, shape);
264 let original_style = macro_style(mac, context);
266 let macro_name = rewrite_macro_name(context, &mac.node.path, extra_ident);
268 let style = if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) && !is_nested_macro {
274 let ts: TokenStream = mac.node.stream();
275 let has_comment = contains_comment(context.snippet(mac.span));
276 if ts.is_empty() && !has_comment {
278 DelimToken::Paren if position == MacroPosition::Item => {
279 Some(format!("{}();", macro_name))
281 DelimToken::Bracket if position == MacroPosition::Item => {
282 Some(format!("{}[];", macro_name))
284 DelimToken::Paren => Some(format!("{}()", macro_name)),
285 DelimToken::Bracket => Some(format!("{}[]", macro_name)),
286 DelimToken::Brace => Some(format!("{} {{}}", macro_name)),
290 // Format well-known macros which cannot be parsed as a valid AST.
291 if macro_name == "lazy_static!" && !has_comment {
292 if let success @ Some(..) = format_lazy_static(context, shape, &ts) {
297 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
298 let mut arg_vec = Vec::new();
299 let mut vec_with_semi = false;
300 let mut trailing_comma = false;
302 if DelimToken::Brace != style {
304 if let Some(arg) = parse_macro_arg(&mut parser) {
306 } else if let Some(arg) = check_keyword(&mut parser) {
309 return return_macro_parse_failure_fallback(context, shape.indent, mac.span);
316 // Try to parse `vec![expr; expr]`
317 if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) {
319 if parser.token != Token::Eof {
320 match parse_macro_arg(&mut parser) {
324 if parser.token == Token::Eof && arg_vec.len() == 2 {
325 vec_with_semi = true;
330 return return_macro_parse_failure_fallback(
339 return return_macro_parse_failure_fallback(context, shape.indent, mac.span);
341 _ if arg_vec.last().map_or(false, MacroArg::is_item) => continue,
342 _ => return return_macro_parse_failure_fallback(context, shape.indent, mac.span),
347 if parser.token == Token::Eof {
348 trailing_comma = true;
354 if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) {
355 return rewrite_macro_with_items(
367 DelimToken::Paren => {
368 // Handle special case: `vec!(expr; expr)`
370 handle_vec_semi(context, shape, arg_vec, macro_name, style)
372 // Format macro invocation as function call, preserve the trailing
373 // comma because not all macros support them.
374 overflow::rewrite_with_parens(
380 context.config.width_heuristics().fn_call_width,
382 Some(SeparatorTactic::Always)
384 Some(SeparatorTactic::Never)
387 .map(|rw| match position {
388 MacroPosition::Item => format!("{};", rw),
393 DelimToken::Bracket => {
394 // Handle special case: `vec![expr; expr]`
396 handle_vec_semi(context, shape, arg_vec, macro_name, style)
398 // If we are rewriting `vec!` macro or other special macros,
399 // then we can rewrite this as an usual array literal.
400 // Otherwise, we must preserve the original existence of trailing comma.
401 let macro_name = ¯o_name.as_str();
402 let mut force_trailing_comma = if trailing_comma {
403 Some(SeparatorTactic::Always)
405 Some(SeparatorTactic::Never)
407 if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
408 context.inside_macro.replace(false);
409 if context.use_block_indent() {
410 force_trailing_comma = Some(SeparatorTactic::Vertical);
413 let rewrite = rewrite_array(
419 force_trailing_comma,
420 Some(original_style),
422 let comma = match position {
423 MacroPosition::Item => ";",
427 Some(format!("{}{}", rewrite, comma))
430 DelimToken::Brace => {
431 // For macro invocations with braces, always put a space between
432 // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
433 // anything in between the braces (for now).
434 let snippet = context.snippet(mac.span).trim_start_matches(|c| c != '{');
435 match trim_left_preserve_layout(snippet, shape.indent, &context.config) {
436 Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
437 None => Some(format!("{} {}", macro_name, snippet)),
445 context: &RewriteContext<'_>,
447 arg_vec: Vec<MacroArg>,
449 delim_token: DelimToken,
450 ) -> Option<String> {
451 let (left, right) = match delim_token {
452 DelimToken::Paren => ("(", ")"),
453 DelimToken::Bracket => ("[", "]"),
457 let mac_shape = shape.offset_left(macro_name.len())?;
458 // 8 = `vec![]` + `; ` or `vec!()` + `; `
459 let total_overhead = 8;
460 let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
461 let lhs = arg_vec[0].rewrite(context, nested_shape)?;
462 let rhs = arg_vec[1].rewrite(context, nested_shape)?;
463 if !lhs.contains('\n')
464 && !rhs.contains('\n')
465 && lhs.len() + rhs.len() + total_overhead <= shape.width
467 // macro_name(lhs; rhs) or macro_name[lhs; rhs]
468 Some(format!("{}{}{}; {}{}", macro_name, left, lhs, rhs, right))
470 // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
475 nested_shape.indent.to_string_with_newline(context.config),
477 nested_shape.indent.to_string_with_newline(context.config),
479 shape.indent.to_string_with_newline(context.config),
485 pub(crate) fn rewrite_macro_def(
486 context: &RewriteContext<'_>,
491 vis: &ast::Visibility,
493 ) -> Option<String> {
494 let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
495 if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
499 let mut parser = MacroParser::new(def.stream().into_trees());
500 let parsed_def = match parser.parse() {
502 None => return snippet,
505 let mut result = if def.legacy {
506 String::from("macro_rules!")
508 format!("{}macro", format_visibility(context, vis))
512 result += rewrite_ident(context, ident);
514 let multi_branch_style = def.legacy || parsed_def.branches.len() != 1;
516 let arm_shape = if multi_branch_style {
518 .block_indent(context.config.tab_spaces())
519 .with_max_width(context.config)
524 let branch_items = itemize_list(
525 context.snippet_provider,
526 parsed_def.branches.iter(),
529 |branch| branch.span.lo(),
530 |branch| branch.span.hi(),
531 |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
533 // if the rewrite returned None because a macro could not be rewritten, then return the
535 None if *context.macro_rewrite_failure.borrow() => {
536 Some(context.snippet(branch.body).trim().to_string())
540 context.snippet_provider.span_after(span, "{"),
544 .collect::<Vec<_>>();
546 let fmt = ListFormatting::new(arm_shape, context.config)
547 .separator(if def.legacy { ";" } else { "" })
548 .trailing_separator(SeparatorTactic::Always)
549 .preserve_newline(true);
551 if multi_branch_style {
553 result += &arm_shape.indent.to_string_with_newline(context.config);
556 match write_list(&branch_items, &fmt) {
557 Some(ref s) => result += s,
558 None => return snippet,
561 if multi_branch_style {
562 result += &indent.to_string_with_newline(context.config);
569 fn register_metavariable(
570 map: &mut HashMap<String, String>,
575 let mut new_name = "$".repeat(dollar_count - 1);
576 let mut old_name = "$".repeat(dollar_count);
579 new_name.push_str(name);
580 old_name.push_str(name);
582 result.push_str(&new_name);
583 map.insert(old_name, new_name);
586 // Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
587 // aren't causing problems.
588 // This should also work for escaped `$` variables, where we leave earlier `$`s.
589 fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
590 // Each substitution will require five or six extra bytes.
591 let mut result = String::with_capacity(input.len() + 64);
592 let mut substs = HashMap::new();
593 let mut dollar_count = 0;
594 let mut cur_name = String::new();
596 for (kind, c) in CharClasses::new(input.chars()) {
597 if kind != FullCodeCharKind::Normal {
601 } else if dollar_count == 0 {
603 } else if !c.is_alphanumeric() && !cur_name.is_empty() {
604 // Terminates a name following one or more dollars.
605 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
610 } else if c == '(' && cur_name.is_empty() {
611 // FIXME: Support macro def with repeat.
613 } else if c.is_alphanumeric() || c == '_' {
618 if !cur_name.is_empty() {
619 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
622 debug!("replace_names `{}` {:?}", result, substs);
624 Some((result, substs))
627 #[derive(Debug, Clone)]
629 /// e.g., `$x: expr`.
630 MetaVariable(ast::Ident, String),
631 /// e.g., `$($foo: expr),*`
633 /// `()`, `[]` or `{}`.
635 /// Inner arguments inside delimiters.
637 /// Something after the closing delimiter and the repeat token, if available.
638 Option<Box<ParsedMacroArg>>,
639 /// The repeat token. This could be one of `*`, `+` or `?`.
642 /// e.g., `[derive(Debug)]`
643 Delimited(DelimToken, Vec<ParsedMacroArg>),
644 /// A possible separator. e.g., `,` or `;`.
645 Separator(String, String),
646 /// Other random stuff that does not fit to other kinds.
647 /// e.g., `== foo` in `($x: expr == foo)`.
648 Other(String, String),
651 fn delim_token_to_str(
652 context: &RewriteContext<'_>,
653 delim_token: DelimToken,
655 use_multiple_lines: bool,
656 inner_is_empty: bool,
657 ) -> (String, String) {
658 let (lhs, rhs) = match delim_token {
659 DelimToken::Paren => ("(", ")"),
660 DelimToken::Bracket => ("[", "]"),
661 DelimToken::Brace => {
662 if inner_is_empty || use_multiple_lines {
668 DelimToken::NoDelim => ("", ""),
670 if use_multiple_lines {
671 let indent_str = shape.indent.to_string_with_newline(context.config);
672 let nested_indent_str = shape
674 .block_indent(context.config)
675 .to_string_with_newline(context.config);
677 format!("{}{}", lhs, nested_indent_str),
678 format!("{}{}", indent_str, rhs),
681 (lhs.to_owned(), rhs.to_owned())
686 fn starts_with_brace(&self) -> bool {
688 MacroArgKind::Repeat(DelimToken::Brace, _, _, _)
689 | MacroArgKind::Delimited(DelimToken::Brace, _) => true,
694 fn starts_with_dollar(&self) -> bool {
696 MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..) => true,
701 fn ends_with_space(&self) -> bool {
703 MacroArgKind::Separator(..) => true,
708 fn has_meta_var(&self) -> bool {
710 MacroArgKind::MetaVariable(..) => true,
711 MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
718 context: &RewriteContext<'_>,
720 use_multiple_lines: bool,
721 ) -> Option<String> {
722 let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
723 let inner = wrap_macro_args(context, args, shape)?;
724 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
725 if lhs.len() + inner.len() + rhs.len() <= shape.width {
726 return Some((lhs, inner, rhs));
729 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
730 let nested_shape = shape
731 .block_indent(context.config.tab_spaces())
732 .with_max_width(context.config);
733 let inner = wrap_macro_args(context, args, nested_shape)?;
734 Some((lhs, inner, rhs))
738 MacroArgKind::MetaVariable(ty, ref name) => {
739 Some(format!("${}:{}", name, ty.name.as_str()))
741 MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
742 let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
743 let another = another
745 .and_then(|a| a.rewrite(context, shape, use_multiple_lines))
746 .unwrap_or_else(|| "".to_owned());
747 let repeat_tok = pprust::token_to_string(tok);
749 Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
751 MacroArgKind::Delimited(delim_tok, ref args) => {
752 rewrite_delimited_inner(delim_tok, args)
753 .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
755 MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
756 MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
761 #[derive(Debug, Clone)]
762 struct ParsedMacroArg {
767 impl ParsedMacroArg {
770 context: &RewriteContext<'_>,
772 use_multiple_lines: bool,
773 ) -> Option<String> {
774 self.kind.rewrite(context, shape, use_multiple_lines)
778 /// Parses macro arguments on macro def.
779 struct MacroArgParser {
780 /// Either a name of the next metavariable, a separator, or junk.
782 /// The start position on the current buffer.
784 /// The first token of the current buffer.
786 /// `true` if we are parsing a metavariable or a repeat.
788 /// The position of the last token.
790 /// The last token parsed.
792 /// Holds the parsed arguments.
793 result: Vec<ParsedMacroArg>,
796 fn last_tok(tt: &TokenTree) -> Token {
798 TokenTree::Token(_, ref t) => t.clone(),
799 TokenTree::Delimited(_, delim, _) => Token::CloseDelim(delim),
803 impl MacroArgParser {
804 fn new() -> MacroArgParser {
810 last_tok: Token::Eof,
811 start_tok: Token::Eof,
816 fn set_last_tok(&mut self, tok: &TokenTree) {
817 self.hi = tok.span().hi();
818 self.last_tok = last_tok(tok);
821 fn add_separator(&mut self) {
822 let prefix = if self.need_space_prefix() {
827 self.result.push(ParsedMacroArg {
828 kind: MacroArgKind::Separator(self.buf.clone(), prefix),
829 span: mk_sp(self.lo, self.hi),
834 fn add_other(&mut self) {
835 let prefix = if self.need_space_prefix() {
840 self.result.push(ParsedMacroArg {
841 kind: MacroArgKind::Other(self.buf.clone(), prefix),
842 span: mk_sp(self.lo, self.hi),
847 fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
849 Some(TokenTree::Token(sp, Token::Ident(ref ident, _))) => {
850 self.result.push(ParsedMacroArg {
851 kind: MacroArgKind::MetaVariable(*ident, self.buf.clone()),
852 span: mk_sp(self.lo, sp.hi()),
856 self.is_meta_var = false;
863 fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken, span: Span) {
864 self.result.push(ParsedMacroArg {
865 kind: MacroArgKind::Delimited(delim, inner),
873 inner: Vec<ParsedMacroArg>,
878 let mut buffer = String::new();
879 let mut first = true;
880 let mut lo = span.lo();
881 let mut hi = span.hi();
883 // Parse '*', '+' or '?.
885 self.set_last_tok(&tok);
888 lo = tok.span().lo();
892 TokenTree::Token(_, Token::BinOp(BinOpToken::Plus))
893 | TokenTree::Token(_, Token::Question)
894 | TokenTree::Token(_, Token::BinOp(BinOpToken::Star)) => {
897 TokenTree::Token(sp, ref t) => {
898 buffer.push_str(&pprust::token_to_string(t));
905 // There could be some random stuff between ')' and '*', '+' or '?'.
906 let another = if buffer.trim().is_empty() {
909 Some(Box::new(ParsedMacroArg {
910 kind: MacroArgKind::Other(buffer, "".to_owned()),
915 self.result.push(ParsedMacroArg {
916 kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
917 span: mk_sp(self.lo, self.hi),
922 fn update_buffer(&mut self, lo: BytePos, t: &Token) {
923 if self.buf.is_empty() {
925 self.start_tok = t.clone();
927 let needs_space = match next_space(&self.last_tok) {
928 SpaceState::Ident => ident_like(t),
929 SpaceState::Punctuation => !ident_like(t),
930 SpaceState::Always => true,
931 SpaceState::Never => false,
933 if force_space_before(t) || needs_space {
938 self.buf.push_str(&pprust::token_to_string(t));
941 fn need_space_prefix(&self) -> bool {
942 if self.result.is_empty() {
946 let last_arg = self.result.last().unwrap();
947 if let MacroArgKind::MetaVariable(..) = last_arg.kind {
948 if ident_like(&self.start_tok) {
951 if self.start_tok == Token::Colon {
956 if force_space_before(&self.start_tok) {
963 /// Returns a collection of parsed macro def's arguments.
964 fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
965 let mut iter = tokens.trees();
967 while let Some(tok) = iter.next() {
969 TokenTree::Token(sp, Token::Dollar) => {
970 // We always want to add a separator before meta variables.
971 if !self.buf.is_empty() {
972 self.add_separator();
975 // Start keeping the name of this metavariable in the buffer.
976 self.is_meta_var = true;
978 self.start_tok = Token::Dollar;
980 TokenTree::Token(_, Token::Colon) if self.is_meta_var => {
981 self.add_meta_variable(&mut iter)?;
983 TokenTree::Token(sp, ref t) => self.update_buffer(sp.lo(), t),
984 TokenTree::Delimited(delimited_span, delimited, ref tts) => {
985 if !self.buf.is_empty() {
986 if next_space(&self.last_tok) == SpaceState::Always {
987 self.add_separator();
993 // Parse the stuff inside delimiters.
994 let mut parser = MacroArgParser::new();
995 parser.lo = delimited_span.open.lo();
996 let delimited_arg = parser.parse(tts.clone())?;
998 let span = delimited_span.entire();
999 if self.is_meta_var {
1000 self.add_repeat(delimited_arg, delimited, &mut iter, span)?;
1001 self.is_meta_var = false;
1003 self.add_delimited(delimited_arg, delimited, span);
1008 self.set_last_tok(&tok);
1011 // We are left with some stuff in the buffer. Since there is nothing
1012 // left to separate, add this as `Other`.
1013 if !self.buf.is_empty() {
1022 context: &RewriteContext<'_>,
1023 args: &[ParsedMacroArg],
1025 ) -> Option<String> {
1026 wrap_macro_args_inner(context, args, shape, false)
1027 .or_else(|| wrap_macro_args_inner(context, args, shape, true))
1030 fn wrap_macro_args_inner(
1031 context: &RewriteContext<'_>,
1032 args: &[ParsedMacroArg],
1034 use_multiple_lines: bool,
1035 ) -> Option<String> {
1036 let mut result = String::with_capacity(128);
1037 let mut iter = args.iter().peekable();
1038 let indent_str = shape.indent.to_string_with_newline(context.config);
1040 while let Some(ref arg) = iter.next() {
1041 result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
1043 if use_multiple_lines
1044 && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
1046 if arg.kind.ends_with_space() {
1049 result.push_str(&indent_str);
1050 } else if let Some(ref next_arg) = iter.peek() {
1051 let space_before_dollar =
1052 !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
1053 let space_before_brace = next_arg.kind.starts_with_brace();
1054 if space_before_dollar || space_before_brace {
1060 if !use_multiple_lines && result.len() >= shape.width {
1067 // This is a bit sketchy. The token rules probably need tweaking, but it works
1068 // for some common cases. I hope the basic logic is sufficient. Note that the
1069 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
1070 // and `(`/`)` have special meaning.
1072 // We always try and format on one line.
1073 // FIXME: Use multi-line when every thing does not fit on one line.
1074 fn format_macro_args(
1075 context: &RewriteContext<'_>,
1076 token_stream: TokenStream,
1078 ) -> Option<String> {
1079 if !context.config.format_macro_matchers() {
1080 let span = span_for_token_stream(&token_stream);
1081 return Some(match span {
1082 Some(span) => context.snippet(span).to_owned(),
1083 None => String::new(),
1086 let parsed_args = MacroArgParser::new().parse(token_stream)?;
1087 wrap_macro_args(context, &parsed_args, shape)
1090 fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
1091 token_stream.trees().next().map(|tt| tt.span())
1094 // We should insert a space if the next token is a:
1095 #[derive(Copy, Clone, PartialEq)]
1099 Ident, // Or ident/literal-like thing.
1103 fn force_space_before(tok: &Token) -> bool {
1104 debug!("tok: force_space_before {:?}", tok);
1125 | Token::Dollar => true,
1130 fn ident_like(tok: &Token) -> bool {
1132 Token::Ident(..) | Token::Literal(..) | Token::Lifetime(_) => true,
1137 fn next_space(tok: &Token) -> SpaceState {
1138 debug!("next_space: {:?}", tok);
1142 | Token::BinOp(BinOpToken::And)
1150 | Token::Question => SpaceState::Punctuation,
1155 | Token::OpenDelim(_)
1156 | Token::CloseDelim(_)
1157 | Token::Whitespace => SpaceState::Never,
1159 Token::Literal(..) | Token::Ident(..) | Token::Lifetime(_) => SpaceState::Ident,
1161 _ => SpaceState::Always,
1165 /// Tries to convert a macro use into a short hand try expression. Returns `None`
1166 /// when the macro is not an instance of `try!` (or parsing the inner expression
1168 pub(crate) fn convert_try_mac(mac: &ast::Mac, context: &RewriteContext<'_>) -> Option<ast::Expr> {
1169 if &mac.node.path.to_string() == "try" {
1170 let ts: TokenStream = mac.node.tts.clone();
1171 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
1174 id: ast::NodeId::root(), // dummy value
1175 node: ast::ExprKind::Try(parser.parse_expr().ok()?),
1176 span: mac.span, // incorrect span, but shouldn't matter too much
1177 attrs: ThinVec::new(),
1184 fn macro_style(mac: &ast::Mac, context: &RewriteContext<'_>) -> DelimToken {
1185 let snippet = context.snippet(mac.span);
1186 let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());
1187 let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::max_value());
1188 let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::max_value());
1190 if paren_pos < bracket_pos && paren_pos < brace_pos {
1192 } else if bracket_pos < brace_pos {
1199 // A very simple parser that just parses a macros 2.0 definition into its branches.
1200 // Currently we do not attempt to parse any further than that.
1202 struct MacroParser {
1207 // (`(` ... `)` `=>` `{` ... `}`)*
1208 fn parse(&mut self) -> Option<Macro> {
1209 let mut branches = vec![];
1210 while self.toks.look_ahead(1).is_some() {
1211 branches.push(self.parse_branch()?);
1214 Some(Macro { branches })
1217 // `(` ... `)` `=>` `{` ... `}`
1218 fn parse_branch(&mut self) -> Option<MacroBranch> {
1219 let tok = self.toks.next()?;
1220 let (lo, args_paren_kind) = match tok {
1221 TokenTree::Token(..) => return None,
1222 TokenTree::Delimited(delimited_span, d, _) => (delimited_span.open.lo(), d),
1224 let args = tok.joint();
1225 match self.toks.next()? {
1226 TokenTree::Token(_, Token::FatArrow) => {}
1229 let (mut hi, body, whole_body) = match self.toks.next()? {
1230 TokenTree::Token(..) => return None,
1231 TokenTree::Delimited(delimited_span, ..) => {
1232 let data = delimited_span.entire().data();
1235 Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt),
1236 delimited_span.entire(),
1240 if let Some(TokenTree::Token(sp, Token::Semi)) = self.toks.look_ahead(0) {
1245 span: mk_sp(lo, hi),
1254 // A parsed macros 2.0 macro definition.
1256 branches: Vec<MacroBranch>,
1259 // FIXME: it would be more efficient to use references to the token streams
1260 // rather than clone them, if we can make the borrowing work out.
1261 struct MacroBranch {
1263 args_paren_kind: DelimToken,
1272 context: &RewriteContext<'_>,
1274 multi_branch_style: bool,
1275 ) -> Option<String> {
1276 // Only attempt to format function-like macros.
1277 if self.args_paren_kind != DelimToken::Paren {
1278 // FIXME(#1539): implement for non-sugared macros.
1283 let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
1285 if multi_branch_style {
1289 if !context.config.format_macro_bodies() {
1291 result += context.snippet(self.whole_body);
1292 return Some(result);
1295 // The macro body is the most interesting part. It might end up as various
1296 // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1297 // parsed as regular Rust code (and note that these can be escaped using
1298 // `$$`). We'll try and format like an AST node, but we'll substitute
1299 // variables for new names with the same length first.
1301 let old_body = context.snippet(self.body).trim();
1302 let (body_str, substs) = replace_names(old_body)?;
1303 let has_block_body = old_body.starts_with('{');
1305 let mut config = context.config.clone();
1306 config.set().hide_parse_errors(true);
1310 let body_indent = if has_block_body {
1313 shape.indent.block_indent(&config)
1315 let new_width = config.max_width() - body_indent.width();
1316 config.set().max_width(new_width);
1318 // First try to format as items, then as statements.
1319 let new_body_snippet = match crate::format_snippet(&body_str, &config) {
1320 Some(new_body) => new_body,
1322 let new_width = new_width + config.tab_spaces();
1323 config.set().max_width(new_width);
1324 match crate::format_code_block(&body_str, &config) {
1325 Some(new_body) => new_body,
1326 None => return None,
1330 let new_body = wrap_str(
1331 new_body_snippet.snippet.to_string(),
1336 // Indent the body since it is in a block.
1337 let indent_str = body_indent.to_string(&config);
1338 let mut new_body = LineClasses::new(new_body.trim_end())
1341 (String::new(), true),
1342 |(mut s, need_indent), (i, (kind, ref l))| {
1343 if !is_empty_line(l)
1345 && !new_body_snippet.is_line_non_formatted(i + 1)
1349 (s + l + "\n", indent_next_line(kind, &l, &config))
1354 // Undo our replacement of macro variables.
1355 // FIXME: this could be *much* more efficient.
1356 for (old, new) in &substs {
1357 if old_body.find(new).is_some() {
1358 debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
1361 new_body = new_body.replace(new, old);
1365 result += new_body.trim();
1366 } else if !new_body.is_empty() {
1368 result += &new_body;
1369 result += &shape.indent.to_string(&config);
1378 /// Format `lazy_static!` from https://crates.io/crates/lazy_static.
1380 /// # Expected syntax
1384 /// [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1385 /// [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1387 /// [pub] static ref NAME_N: TYPE_N = EXPR_N;
1390 fn format_lazy_static(
1391 context: &RewriteContext<'_>,
1394 ) -> Option<String> {
1395 let mut result = String::with_capacity(1024);
1396 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
1397 let nested_shape = shape
1398 .block_indent(context.config.tab_spaces())
1399 .with_max_width(context.config);
1401 result.push_str("lazy_static! {");
1402 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1404 macro_rules! parse_or {
1405 ($method:ident $(,)* $($arg:expr),* $(,)*) => {
1406 match parser.$method($($arg,)*) {
1408 if parser.sess.span_diagnostic.has_errors() {
1409 parser.sess.span_diagnostic.reset_err_count();
1417 parser.sess.span_diagnostic.reset_err_count();
1424 while parser.token != Token::Eof {
1425 // Parse a `lazy_static!` item.
1426 let vis = crate::utils::format_visibility(context, &parse_or!(parse_visibility, false));
1427 parser.eat_keyword(keywords::Static);
1428 parser.eat_keyword(keywords::Ref);
1429 let id = parse_or!(parse_ident);
1430 parser.eat(&Token::Colon);
1431 let ty = parse_or!(parse_ty);
1432 parser.eat(&Token::Eq);
1433 let expr = parse_or!(parse_expr);
1434 parser.eat(&Token::Semi);
1436 // Rewrite as a static item.
1437 let mut stmt = String::with_capacity(128);
1438 stmt.push_str(&format!(
1439 "{}static ref {}: {} =",
1442 ty.rewrite(context, nested_shape)?
1444 result.push_str(&crate::expr::rewrite_assign_rhs(
1448 nested_shape.sub_width(1)?,
1451 if parser.token != Token::Eof {
1452 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1456 result.push_str(&shape.indent.to_string_with_newline(context.config));
1462 fn rewrite_macro_with_items(
1463 context: &RewriteContext<'_>,
1468 position: MacroPosition,
1470 ) -> Option<String> {
1471 let (opener, closer) = match style {
1472 DelimToken::Paren => ("(", ")"),
1473 DelimToken::Bracket => ("[", "]"),
1474 DelimToken::Brace => (" {", "}"),
1477 let trailing_semicolon = match style {
1478 DelimToken::Paren | DelimToken::Bracket if position == MacroPosition::Item => ";",
1482 let mut visitor = FmtVisitor::from_context(context);
1483 visitor.block_indent = shape.indent.block_indent(context.config);
1484 visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
1486 let item = match item {
1487 MacroArg::Item(item) => item,
1490 visitor.visit_item(&item);
1493 let mut result = String::with_capacity(256);
1494 result.push_str(¯o_name);
1495 result.push_str(opener);
1496 result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1497 result.push_str(visitor.buffer.trim());
1498 result.push_str(&shape.indent.to_string_with_newline(context.config));
1499 result.push_str(closer);
1500 result.push_str(trailing_semicolon);
1504 const RUST_KEYWORDS: [keywords::Keyword; 60] = [
1506 keywords::DollarCrate,
1507 keywords::Underscore,
1532 keywords::SelfLower,
1533 keywords::SelfUpper,
1558 keywords::UnderscoreLifetime,
1559 keywords::StaticLifetime,
1563 keywords::Existential,