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 rustc_ast
::token
::{BinOpToken, DelimToken, Token, TokenKind}
;
16 use rustc_ast
::tokenstream
::{Cursor, LazyTokenStream, TokenStream, TokenTree}
;
17 use rustc_ast
::{ast, ptr}
;
18 use rustc_ast_pretty
::pprust
;
19 use rustc_parse
::parser
::{ForceCollect, Parser}
;
20 use rustc_parse
::{stream_to_parser, MACRO_ARGUMENTS}
;
23 BytePos
, Span
, Symbol
, DUMMY_SP
,
27 contains_comment
, CharClasses
, FindUncommented
, FullCodeCharKind
, LineClasses
,
29 use crate::config
::lists
::*;
30 use crate::expr
::rewrite_array
;
31 use crate::lists
::{itemize_list, write_list, ListFormatting}
;
33 use crate::rewrite
::{Rewrite, RewriteContext}
;
34 use crate::shape
::{Indent, Shape}
;
35 use crate::source_map
::SpanUtils
;
36 use crate::spanned
::Spanned
;
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
,
41 use crate::visitor
::FmtVisitor
;
43 const FORCED_BRACKET_MACROS
: &[&str] = &["vec!"];
45 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
46 pub(crate) enum MacroPosition
{
54 pub(crate) enum MacroArg
{
55 Expr(ptr
::P
<ast
::Expr
>),
57 Pat(ptr
::P
<ast
::Pat
>),
58 Item(ptr
::P
<ast
::Item
>),
59 Keyword(symbol
::Ident
, Span
),
63 fn is_item(&self) -> bool
{
65 MacroArg
::Item(..) => true,
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())
81 impl Rewrite
for MacroArg
{
82 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
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()),
93 fn build_parser
<'a
>(context
: &RewriteContext
<'a
>, cursor
: Cursor
) -> Parser
<'a
> {
95 context
.parse_sess
.inner(),
101 fn parse_macro_arg
<'a
, 'b
: 'a
>(parser
: &'a
mut Parser
<'b
>) -> Option
<MacroArg
> {
102 macro_rules
! parse_macro_arg
{
103 ($macro_arg
:ident
, $parser
:expr
, $f
:expr
) => {
104 let mut cloned_parser
= (*parser
).clone();
105 match $
parser(&mut cloned_parser
) {
107 if parser
.sess
.span_diagnostic
.has_errors() {
108 parser
.sess
.span_diagnostic
.reset_err_count();
110 // Parsing succeeded.
111 *parser
= cloned_parser
;
112 return Some(MacroArg
::$
macro_arg($
f(x
)?
));
117 parser
.sess
.span_diagnostic
.reset_err_count();
125 |parser
: &mut rustc_parse
::parser
::Parser
<'b
>| parser
.parse_expr(),
126 |x
: ptr
::P
<ast
::Expr
>| Some(x
)
130 |parser
: &mut rustc_parse
::parser
::Parser
<'b
>| parser
.parse_ty(),
131 |x
: ptr
::P
<ast
::Ty
>| Some(x
)
135 |parser
: &mut rustc_parse
::parser
::Parser
<'b
>| parser
.parse_pat(None
),
136 |x
: ptr
::P
<ast
::Pat
>| Some(x
)
138 // `parse_item` returns `Option<ptr::P<ast::Item>>`.
141 |parser
: &mut rustc_parse
::parser
::Parser
<'b
>| parser
.parse_item(ForceCollect
::No
),
142 |x
: Option
<ptr
::P
<ast
::Item
>>| x
148 /// Rewrite macro name without using pretty-printer if possible.
149 fn rewrite_macro_name(
150 context
: &RewriteContext
<'_
>,
152 extra_ident
: Option
<symbol
::Ident
>,
154 let name
= if path
.segments
.len() == 1 {
155 // Avoid using pretty-printer in the common case.
156 format
!("{}!", rewrite_ident(context
, path
.segments
[0].ident
))
158 format
!("{}!", pprust
::path_to_string(path
))
161 Some(ident
) if ident
.name
!= kw
::Empty
=> format
!("{} {}", name
, ident
),
166 // Use this on failing to format the macro call.
167 fn return_macro_parse_failure_fallback(
168 context
: &RewriteContext
<'_
>,
171 ) -> Option
<String
> {
172 // Mark this as a failure however we format it
173 context
.macro_rewrite_failure
.replace(true);
175 // Heuristically determine whether the last line of the macro uses "Block" style
176 // rather than using "Visual" style, or another indentation style.
177 let is_like_block_indent_style
= context
181 .map(|closing_line
| {
182 closing_line
.trim().chars().all(|ch
| match ch
{
183 '
}'
| '
)'
| '
]'
=> true,
188 if is_like_block_indent_style
{
189 return trim_left_preserve_layout(context
.snippet(span
), indent
, &context
.config
);
192 context
.skipped_range
.borrow_mut().push((
193 context
.parse_sess
.line_of_byte_pos(span
.lo()),
194 context
.parse_sess
.line_of_byte_pos(span
.hi()),
197 // Return the snippet unmodified if the macro is not block-like
198 Some(context
.snippet(span
).to_owned())
201 pub(crate) fn rewrite_macro(
203 extra_ident
: Option
<symbol
::Ident
>,
204 context
: &RewriteContext
<'_
>,
206 position
: MacroPosition
,
207 ) -> Option
<String
> {
208 let should_skip
= context
210 .skip_macro(&context
.snippet(mac
.path
.span
).to_owned());
214 let guard
= context
.enter_macro();
215 let result
= catch_unwind(AssertUnwindSafe(|| {
226 Err(..) | Ok(None
) => {
227 context
.macro_rewrite_failure
.replace(true);
235 fn check_keyword
<'a
, 'b
: 'a
>(parser
: &'a
mut Parser
<'b
>) -> Option
<MacroArg
> {
236 for &keyword
in RUST_KW
.iter() {
237 if parser
.token
.is_keyword(keyword
)
238 && parser
.look_ahead(1, |t
| {
239 t
.kind
== TokenKind
::Eof
240 || t
.kind
== TokenKind
::Comma
241 || t
.kind
== TokenKind
::CloseDelim(DelimToken
::NoDelim
)
245 return Some(MacroArg
::Keyword(
246 symbol
::Ident
::with_dummy_span(keyword
),
247 parser
.prev_token
.span
,
254 fn rewrite_macro_inner(
256 extra_ident
: Option
<symbol
::Ident
>,
257 context
: &RewriteContext
<'_
>,
259 position
: MacroPosition
,
260 is_nested_macro
: bool
,
261 ) -> Option
<String
> {
262 if context
.config
.use_try_shorthand() {
263 if let Some(expr
) = convert_try_mac(mac
, context
) {
264 context
.leave_macro();
265 return expr
.rewrite(context
, shape
);
269 let original_style
= macro_style(mac
, context
);
271 let macro_name
= rewrite_macro_name(context
, &mac
.path
, extra_ident
);
273 let style
= if FORCED_BRACKET_MACROS
.contains(&¯o_name
[..]) && !is_nested_macro
{
279 let ts
= mac
.args
.inner_tokens();
280 let has_comment
= contains_comment(context
.snippet(mac
.span()));
281 if ts
.is_empty() && !has_comment
{
283 DelimToken
::Paren
if position
== MacroPosition
::Item
=> {
284 Some(format
!("{}();", macro_name
))
286 DelimToken
::Bracket
if position
== MacroPosition
::Item
=> {
287 Some(format
!("{}[];", macro_name
))
289 DelimToken
::Paren
=> Some(format
!("{}()", macro_name
)),
290 DelimToken
::Bracket
=> Some(format
!("{}[]", macro_name
)),
291 DelimToken
::Brace
=> Some(format
!("{} {{}}", macro_name
)),
295 // Format well-known macros which cannot be parsed as a valid AST.
296 if macro_name
== "lazy_static!" && !has_comment
{
297 if let success @
Some(..) = format_lazy_static(context
, shape
, &ts
) {
302 let mut parser
= build_parser(context
, ts
.trees());
303 let mut arg_vec
= Vec
::new();
304 let mut vec_with_semi
= false;
305 let mut trailing_comma
= false;
307 if DelimToken
::Brace
!= style
{
309 if let Some(arg
) = check_keyword(&mut parser
) {
311 } else if let Some(arg
) = parse_macro_arg(&mut parser
) {
314 return return_macro_parse_failure_fallback(context
, shape
.indent
, mac
.span());
317 match parser
.token
.kind
{
318 TokenKind
::Eof
=> break,
319 TokenKind
::Comma
=> (),
321 // Try to parse `vec![expr; expr]`
322 if FORCED_BRACKET_MACROS
.contains(&¯o_name
[..]) {
324 if parser
.token
.kind
!= TokenKind
::Eof
{
325 match parse_macro_arg(&mut parser
) {
329 if parser
.token
.kind
== TokenKind
::Eof
&& arg_vec
.len() == 2 {
330 vec_with_semi
= true;
335 return return_macro_parse_failure_fallback(
344 return return_macro_parse_failure_fallback(context
, shape
.indent
, mac
.span());
346 _
if arg_vec
.last().map_or(false, MacroArg
::is_item
) => continue,
347 _
=> return return_macro_parse_failure_fallback(context
, shape
.indent
, mac
.span()),
352 if parser
.token
.kind
== TokenKind
::Eof
{
353 trailing_comma
= true;
359 if !arg_vec
.is_empty() && arg_vec
.iter().all(MacroArg
::is_item
) {
360 return rewrite_macro_with_items(
372 DelimToken
::Paren
=> {
373 // Handle special case: `vec!(expr; expr)`
375 handle_vec_semi(context
, shape
, arg_vec
, macro_name
, style
)
377 // Format macro invocation as function call, preserve the trailing
378 // comma because not all macros support them.
379 overflow
::rewrite_with_parens(
385 context
.config
.width_heuristics().fn_call_width
,
387 Some(SeparatorTactic
::Always
)
389 Some(SeparatorTactic
::Never
)
392 .map(|rw
| match position
{
393 MacroPosition
::Item
=> format
!("{};", rw
),
398 DelimToken
::Bracket
=> {
399 // Handle special case: `vec![expr; expr]`
401 handle_vec_semi(context
, shape
, arg_vec
, macro_name
, style
)
403 // If we are rewriting `vec!` macro or other special macros,
404 // then we can rewrite this as an usual array literal.
405 // Otherwise, we must preserve the original existence of trailing comma.
406 let macro_name
= ¯o_name
.as_str();
407 let mut force_trailing_comma
= if trailing_comma
{
408 Some(SeparatorTactic
::Always
)
410 Some(SeparatorTactic
::Never
)
412 if FORCED_BRACKET_MACROS
.contains(macro_name
) && !is_nested_macro
{
413 context
.leave_macro();
414 if context
.use_block_indent() {
415 force_trailing_comma
= Some(SeparatorTactic
::Vertical
);
418 let rewrite
= rewrite_array(
424 force_trailing_comma
,
425 Some(original_style
),
427 let comma
= match position
{
428 MacroPosition
::Item
=> ";",
432 Some(format
!("{}{}", rewrite
, comma
))
435 DelimToken
::Brace
=> {
436 // For macro invocations with braces, always put a space between
437 // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
438 // anything in between the braces (for now).
439 let snippet
= context
.snippet(mac
.span()).trim_start_matches(|c
| c
!= '
{'
);
440 match trim_left_preserve_layout(snippet
, shape
.indent
, &context
.config
) {
441 Some(macro_body
) => Some(format
!("{} {}", macro_name
, macro_body
)),
442 None
=> Some(format
!("{} {}", macro_name
, snippet
)),
450 context
: &RewriteContext
<'_
>,
452 arg_vec
: Vec
<MacroArg
>,
454 delim_token
: DelimToken
,
455 ) -> Option
<String
> {
456 let (left
, right
) = match delim_token
{
457 DelimToken
::Paren
=> ("(", ")"),
458 DelimToken
::Bracket
=> ("[", "]"),
462 let mac_shape
= shape
.offset_left(macro_name
.len())?
;
463 // 8 = `vec![]` + `; ` or `vec!()` + `; `
464 let total_overhead
= 8;
465 let nested_shape
= mac_shape
.block_indent(context
.config
.tab_spaces());
466 let lhs
= arg_vec
[0].rewrite(context
, nested_shape
)?
;
467 let rhs
= arg_vec
[1].rewrite(context
, nested_shape
)?
;
468 if !lhs
.contains('
\n'
)
469 && !rhs
.contains('
\n'
)
470 && lhs
.len() + rhs
.len() + total_overhead
<= shape
.width
472 // macro_name(lhs; rhs) or macro_name[lhs; rhs]
473 Some(format
!("{}{}{}; {}{}", macro_name
, left
, lhs
, rhs
, right
))
475 // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
480 nested_shape
.indent
.to_string_with_newline(context
.config
),
482 nested_shape
.indent
.to_string_with_newline(context
.config
),
484 shape
.indent
.to_string_with_newline(context
.config
),
490 pub(crate) fn rewrite_macro_def(
491 context
: &RewriteContext
<'_
>,
495 ident
: symbol
::Ident
,
496 vis
: &ast
::Visibility
,
498 ) -> Option
<String
> {
499 let snippet
= Some(remove_trailing_white_spaces(context
.snippet(span
)));
500 if snippet
.as_ref().map_or(true, |s
| s
.ends_with('
;'
)) {
504 let ts
= def
.body
.inner_tokens();
505 let mut parser
= MacroParser
::new(ts
.into_trees());
506 let parsed_def
= match parser
.parse() {
508 None
=> return snippet
,
511 let mut result
= if def
.macro_rules
{
512 String
::from("macro_rules!")
514 format
!("{}macro", format_visibility(context
, vis
))
518 result
+= rewrite_ident(context
, ident
);
520 let multi_branch_style
= def
.macro_rules
|| parsed_def
.branches
.len() != 1;
522 let arm_shape
= if multi_branch_style
{
524 .block_indent(context
.config
.tab_spaces())
525 .with_max_width(context
.config
)
530 let branch_items
= itemize_list(
531 context
.snippet_provider
,
532 parsed_def
.branches
.iter(),
535 |branch
| branch
.span
.lo(),
536 |branch
| branch
.span
.hi(),
537 |branch
| match branch
.rewrite(context
, arm_shape
, multi_branch_style
) {
539 // if the rewrite returned None because a macro could not be rewritten, then return the
541 None
if context
.macro_rewrite_failure
.get() => {
542 Some(context
.snippet(branch
.body
).trim().to_string())
546 context
.snippet_provider
.span_after(span
, "{"),
550 .collect
::<Vec
<_
>>();
552 let fmt
= ListFormatting
::new(arm_shape
, context
.config
)
553 .separator(if def
.macro_rules { ";" }
else { "" }
)
554 .trailing_separator(SeparatorTactic
::Always
)
555 .preserve_newline(true);
557 if multi_branch_style
{
559 result
+= &arm_shape
.indent
.to_string_with_newline(context
.config
);
562 match write_list(&branch_items
, &fmt
) {
563 Some(ref s
) => result
+= s
,
564 None
=> return snippet
,
567 if multi_branch_style
{
568 result
+= &indent
.to_string_with_newline(context
.config
);
575 fn register_metavariable(
576 map
: &mut HashMap
<String
, String
>,
581 let mut new_name
= "$".repeat(dollar_count
- 1);
582 let mut old_name
= "$".repeat(dollar_count
);
585 new_name
.push_str(name
);
586 old_name
.push_str(name
);
588 result
.push_str(&new_name
);
589 map
.insert(old_name
, new_name
);
592 // Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
593 // aren't causing problems.
594 // This should also work for escaped `$` variables, where we leave earlier `$`s.
595 fn replace_names(input
: &str) -> Option
<(String
, HashMap
<String
, String
>)> {
596 // Each substitution will require five or six extra bytes.
597 let mut result
= String
::with_capacity(input
.len() + 64);
598 let mut substs
= HashMap
::new();
599 let mut dollar_count
= 0;
600 let mut cur_name
= String
::new();
602 for (kind
, c
) in CharClasses
::new(input
.chars()) {
603 if kind
!= FullCodeCharKind
::Normal
{
607 } else if dollar_count
== 0 {
609 } else if !c
.is_alphanumeric() && !cur_name
.is_empty() {
610 // Terminates a name following one or more dollars.
611 register_metavariable(&mut substs
, &mut result
, &cur_name
, dollar_count
);
616 } else if c
== '
('
&& cur_name
.is_empty() {
617 // FIXME: Support macro def with repeat.
619 } else if c
.is_alphanumeric() || c
== '_'
{
624 if !cur_name
.is_empty() {
625 register_metavariable(&mut substs
, &mut result
, &cur_name
, dollar_count
);
628 debug
!("replace_names `{}` {:?}", result
, substs
);
630 Some((result
, substs
))
633 #[derive(Debug, Clone)]
635 /// e.g., `$x: expr`.
636 MetaVariable(Symbol
, String
),
637 /// e.g., `$($foo: expr),*`
639 /// `()`, `[]` or `{}`.
641 /// Inner arguments inside delimiters.
643 /// Something after the closing delimiter and the repeat token, if available.
644 Option
<Box
<ParsedMacroArg
>>,
645 /// The repeat token. This could be one of `*`, `+` or `?`.
648 /// e.g., `[derive(Debug)]`
649 Delimited(DelimToken
, Vec
<ParsedMacroArg
>),
650 /// A possible separator. e.g., `,` or `;`.
651 Separator(String
, String
),
652 /// Other random stuff that does not fit to other kinds.
653 /// e.g., `== foo` in `($x: expr == foo)`.
654 Other(String
, String
),
657 fn delim_token_to_str(
658 context
: &RewriteContext
<'_
>,
659 delim_token
: DelimToken
,
661 use_multiple_lines
: bool
,
662 inner_is_empty
: bool
,
663 ) -> (String
, String
) {
664 let (lhs
, rhs
) = match delim_token
{
665 DelimToken
::Paren
=> ("(", ")"),
666 DelimToken
::Bracket
=> ("[", "]"),
667 DelimToken
::Brace
=> {
668 if inner_is_empty
|| use_multiple_lines
{
674 DelimToken
::NoDelim
=> ("", ""),
676 if use_multiple_lines
{
677 let indent_str
= shape
.indent
.to_string_with_newline(context
.config
);
678 let nested_indent_str
= shape
680 .block_indent(context
.config
)
681 .to_string_with_newline(context
.config
);
683 format
!("{}{}", lhs
, nested_indent_str
),
684 format
!("{}{}", indent_str
, rhs
),
687 (lhs
.to_owned(), rhs
.to_owned())
692 fn starts_with_brace(&self) -> bool
{
694 MacroArgKind
::Repeat(DelimToken
::Brace
, _
, _
, _
)
695 | MacroArgKind
::Delimited(DelimToken
::Brace
, _
) => true,
700 fn starts_with_dollar(&self) -> bool
{
702 MacroArgKind
::Repeat(..) | MacroArgKind
::MetaVariable(..) => true,
707 fn ends_with_space(&self) -> bool
{
709 MacroArgKind
::Separator(..) => true,
714 fn has_meta_var(&self) -> bool
{
716 MacroArgKind
::MetaVariable(..) => true,
717 MacroArgKind
::Repeat(_
, ref args
, _
, _
) => args
.iter().any(|a
| a
.kind
.has_meta_var()),
724 context
: &RewriteContext
<'_
>,
726 use_multiple_lines
: bool
,
727 ) -> Option
<String
> {
728 let rewrite_delimited_inner
= |delim_tok
, args
| -> Option
<(String
, String
, String
)> {
729 let inner
= wrap_macro_args(context
, args
, shape
)?
;
730 let (lhs
, rhs
) = delim_token_to_str(context
, delim_tok
, shape
, false, inner
.is_empty());
731 if lhs
.len() + inner
.len() + rhs
.len() <= shape
.width
{
732 return Some((lhs
, inner
, rhs
));
735 let (lhs
, rhs
) = delim_token_to_str(context
, delim_tok
, shape
, true, false);
736 let nested_shape
= shape
737 .block_indent(context
.config
.tab_spaces())
738 .with_max_width(context
.config
);
739 let inner
= wrap_macro_args(context
, args
, nested_shape
)?
;
740 Some((lhs
, inner
, rhs
))
744 MacroArgKind
::MetaVariable(ty
, ref name
) => Some(format
!("${}:{}", name
, ty
)),
745 MacroArgKind
::Repeat(delim_tok
, ref args
, ref another
, ref tok
) => {
746 let (lhs
, inner
, rhs
) = rewrite_delimited_inner(delim_tok
, args
)?
;
747 let another
= another
749 .and_then(|a
| a
.rewrite(context
, shape
, use_multiple_lines
))
750 .unwrap_or_else(|| "".to_owned());
751 let repeat_tok
= pprust
::token_to_string(tok
);
753 Some(format
!("${}{}{}{}{}", lhs
, inner
, rhs
, another
, repeat_tok
))
755 MacroArgKind
::Delimited(delim_tok
, ref args
) => {
756 rewrite_delimited_inner(delim_tok
, args
)
757 .map(|(lhs
, inner
, rhs
)| format
!("{}{}{}", lhs
, inner
, rhs
))
759 MacroArgKind
::Separator(ref sep
, ref prefix
) => Some(format
!("{}{} ", prefix
, sep
)),
760 MacroArgKind
::Other(ref inner
, ref prefix
) => Some(format
!("{}{}", prefix
, inner
)),
765 #[derive(Debug, Clone)]
766 struct ParsedMacroArg
{
771 impl ParsedMacroArg
{
774 context
: &RewriteContext
<'_
>,
776 use_multiple_lines
: bool
,
777 ) -> Option
<String
> {
778 self.kind
.rewrite(context
, shape
, use_multiple_lines
)
782 /// Parses macro arguments on macro def.
783 struct MacroArgParser
{
784 /// Either a name of the next metavariable, a separator, or junk.
786 /// The start position on the current buffer.
788 /// The first token of the current buffer.
790 /// `true` if we are parsing a metavariable or a repeat.
792 /// The position of the last token.
794 /// The last token parsed.
796 /// Holds the parsed arguments.
797 result
: Vec
<ParsedMacroArg
>,
800 fn last_tok(tt
: &TokenTree
) -> Token
{
802 TokenTree
::Token(ref t
) => t
.clone(),
803 TokenTree
::Delimited(delim_span
, delim
, _
) => Token
{
804 kind
: TokenKind
::CloseDelim(delim
),
805 span
: delim_span
.close
,
810 impl MacroArgParser
{
811 fn new() -> MacroArgParser
{
818 kind
: TokenKind
::Eof
,
822 kind
: TokenKind
::Eof
,
829 fn set_last_tok(&mut self, tok
: &TokenTree
) {
830 self.hi
= tok
.span().hi();
831 self.last_tok
= last_tok(tok
);
834 fn add_separator(&mut self) {
835 let prefix
= if self.need_space_prefix() {
840 self.result
.push(ParsedMacroArg
{
841 kind
: MacroArgKind
::Separator(self.buf
.clone(), prefix
),
842 span
: mk_sp(self.lo
, self.hi
),
847 fn add_other(&mut self) {
848 let prefix
= if self.need_space_prefix() {
853 self.result
.push(ParsedMacroArg
{
854 kind
: MacroArgKind
::Other(self.buf
.clone(), prefix
),
855 span
: mk_sp(self.lo
, self.hi
),
860 fn add_meta_variable(&mut self, iter
: &mut Cursor
) -> Option
<()> {
862 Some(TokenTree
::Token(Token
{
863 kind
: TokenKind
::Ident(name
, _
),
866 self.result
.push(ParsedMacroArg
{
867 kind
: MacroArgKind
::MetaVariable(name
, self.buf
.clone()),
868 span
: mk_sp(self.lo
, span
.hi()),
872 self.is_meta_var
= false;
879 fn add_delimited(&mut self, inner
: Vec
<ParsedMacroArg
>, delim
: DelimToken
, span
: Span
) {
880 self.result
.push(ParsedMacroArg
{
881 kind
: MacroArgKind
::Delimited(delim
, inner
),
889 inner
: Vec
<ParsedMacroArg
>,
894 let mut buffer
= String
::new();
895 let mut first
= true;
896 let mut lo
= span
.lo();
897 let mut hi
= span
.hi();
899 // Parse '*', '+' or '?.
901 self.set_last_tok(&tok
);
904 lo
= tok
.span().lo();
908 TokenTree
::Token(Token
{
909 kind
: TokenKind
::BinOp(BinOpToken
::Plus
),
912 | TokenTree
::Token(Token
{
913 kind
: TokenKind
::Question
,
916 | TokenTree
::Token(Token
{
917 kind
: TokenKind
::BinOp(BinOpToken
::Star
),
922 TokenTree
::Token(ref t
) => {
923 buffer
.push_str(&pprust
::token_to_string(&t
));
930 // There could be some random stuff between ')' and '*', '+' or '?'.
931 let another
= if buffer
.trim().is_empty() {
934 Some(Box
::new(ParsedMacroArg
{
935 kind
: MacroArgKind
::Other(buffer
, "".to_owned()),
940 self.result
.push(ParsedMacroArg
{
941 kind
: MacroArgKind
::Repeat(delim
, inner
, another
, self.last_tok
.clone()),
942 span
: mk_sp(self.lo
, self.hi
),
947 fn update_buffer(&mut self, t
: &Token
) {
948 if self.buf
.is_empty() {
949 self.lo
= t
.span
.lo();
950 self.start_tok
= t
.clone();
952 let needs_space
= match next_space(&self.last_tok
.kind
) {
953 SpaceState
::Ident
=> ident_like(t
),
954 SpaceState
::Punctuation
=> !ident_like(t
),
955 SpaceState
::Always
=> true,
956 SpaceState
::Never
=> false,
958 if force_space_before(&t
.kind
) || needs_space
{
963 self.buf
.push_str(&pprust
::token_to_string(t
));
966 fn need_space_prefix(&self) -> bool
{
967 if self.result
.is_empty() {
971 let last_arg
= self.result
.last().unwrap();
972 if let MacroArgKind
::MetaVariable(..) = last_arg
.kind
{
973 if ident_like(&self.start_tok
) {
976 if self.start_tok
.kind
== TokenKind
::Colon
{
981 if force_space_before(&self.start_tok
.kind
) {
988 /// Returns a collection of parsed macro def's arguments.
989 fn parse(mut self, tokens
: TokenStream
) -> Option
<Vec
<ParsedMacroArg
>> {
990 let mut iter
= tokens
.trees();
992 while let Some(tok
) = iter
.next() {
994 TokenTree
::Token(Token
{
995 kind
: TokenKind
::Dollar
,
998 // We always want to add a separator before meta variables.
999 if !self.buf
.is_empty() {
1000 self.add_separator();
1003 // Start keeping the name of this metavariable in the buffer.
1004 self.is_meta_var
= true;
1005 self.lo
= span
.lo();
1006 self.start_tok
= Token
{
1007 kind
: TokenKind
::Dollar
,
1011 TokenTree
::Token(Token
{
1012 kind
: TokenKind
::Colon
,
1014 }) if self.is_meta_var
=> {
1015 self.add_meta_variable(&mut iter
)?
;
1017 TokenTree
::Token(ref t
) => self.update_buffer(t
),
1018 TokenTree
::Delimited(delimited_span
, delimited
, ref tts
) => {
1019 if !self.buf
.is_empty() {
1020 if next_space(&self.last_tok
.kind
) == SpaceState
::Always
{
1021 self.add_separator();
1027 // Parse the stuff inside delimiters.
1028 let mut parser
= MacroArgParser
::new();
1029 parser
.lo
= delimited_span
.open
.lo();
1030 let delimited_arg
= parser
.parse(tts
.clone())?
;
1032 let span
= delimited_span
.entire();
1033 if self.is_meta_var
{
1034 self.add_repeat(delimited_arg
, delimited
, &mut iter
, span
)?
;
1035 self.is_meta_var
= false;
1037 self.add_delimited(delimited_arg
, delimited
, span
);
1042 self.set_last_tok(&tok
);
1045 // We are left with some stuff in the buffer. Since there is nothing
1046 // left to separate, add this as `Other`.
1047 if !self.buf
.is_empty() {
1056 context
: &RewriteContext
<'_
>,
1057 args
: &[ParsedMacroArg
],
1059 ) -> Option
<String
> {
1060 wrap_macro_args_inner(context
, args
, shape
, false)
1061 .or_else(|| wrap_macro_args_inner(context
, args
, shape
, true))
1064 fn wrap_macro_args_inner(
1065 context
: &RewriteContext
<'_
>,
1066 args
: &[ParsedMacroArg
],
1068 use_multiple_lines
: bool
,
1069 ) -> Option
<String
> {
1070 let mut result
= String
::with_capacity(128);
1071 let mut iter
= args
.iter().peekable();
1072 let indent_str
= shape
.indent
.to_string_with_newline(context
.config
);
1074 while let Some(ref arg
) = iter
.next() {
1075 result
.push_str(&arg
.rewrite(context
, shape
, use_multiple_lines
)?
);
1077 if use_multiple_lines
1078 && (arg
.kind
.ends_with_space() || iter
.peek().map_or(false, |a
| a
.kind
.has_meta_var()))
1080 if arg
.kind
.ends_with_space() {
1083 result
.push_str(&indent_str
);
1084 } else if let Some(ref next_arg
) = iter
.peek() {
1085 let space_before_dollar
=
1086 !arg
.kind
.ends_with_space() && next_arg
.kind
.starts_with_dollar();
1087 let space_before_brace
= next_arg
.kind
.starts_with_brace();
1088 if space_before_dollar
|| space_before_brace
{
1094 if !use_multiple_lines
&& result
.len() >= shape
.width
{
1101 // This is a bit sketchy. The token rules probably need tweaking, but it works
1102 // for some common cases. I hope the basic logic is sufficient. Note that the
1103 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
1104 // and `(`/`)` have special meaning.
1106 // We always try and format on one line.
1107 // FIXME: Use multi-line when every thing does not fit on one line.
1108 fn format_macro_args(
1109 context
: &RewriteContext
<'_
>,
1110 token_stream
: TokenStream
,
1112 ) -> Option
<String
> {
1113 if !context
.config
.format_macro_matchers() {
1114 let span
= span_for_token_stream(&token_stream
);
1115 return Some(match span
{
1116 Some(span
) => context
.snippet(span
).to_owned(),
1117 None
=> String
::new(),
1120 let parsed_args
= MacroArgParser
::new().parse(token_stream
)?
;
1121 wrap_macro_args(context
, &parsed_args
, shape
)
1124 fn span_for_token_stream(token_stream
: &TokenStream
) -> Option
<Span
> {
1125 token_stream
.trees().next().map(|tt
| tt
.span())
1128 // We should insert a space if the next token is a:
1129 #[derive(Copy, Clone, PartialEq)]
1133 Ident
, // Or ident/literal-like thing.
1137 fn force_space_before(tok
: &TokenKind
) -> bool
{
1138 debug
!("tok: force_space_before {:?}", tok
);
1152 | TokenKind
::BinOpEq(_
)
1156 | TokenKind
::FatArrow
1157 | TokenKind
::BinOp(_
)
1159 | TokenKind
::Dollar
=> true,
1164 fn ident_like(tok
: &Token
) -> bool
{
1166 TokenKind
::Ident(..) | TokenKind
::Literal(..) | TokenKind
::Lifetime(_
) => true,
1171 fn next_space(tok
: &TokenKind
) -> SpaceState
{
1172 debug
!("next_space: {:?}", tok
);
1176 | TokenKind
::BinOp(BinOpToken
::And
)
1182 | TokenKind
::DotDotDot
1183 | TokenKind
::DotDotEq
1184 | TokenKind
::Question
=> SpaceState
::Punctuation
,
1189 | TokenKind
::OpenDelim(_
)
1190 | TokenKind
::CloseDelim(_
) => SpaceState
::Never
,
1192 TokenKind
::Literal(..) | TokenKind
::Ident(..) | TokenKind
::Lifetime(_
) => SpaceState
::Ident
,
1194 _
=> SpaceState
::Always
,
1198 /// Tries to convert a macro use into a short hand try expression. Returns `None`
1199 /// when the macro is not an instance of `try!` (or parsing the inner expression
1201 pub(crate) fn convert_try_mac(
1203 context
: &RewriteContext
<'_
>,
1204 ) -> Option
<ast
::Expr
> {
1205 let path
= &pprust
::path_to_string(&mac
.path
);
1206 if path
== "try" || path
== "r#try" {
1207 let ts
= mac
.args
.inner_tokens();
1208 let mut parser
= build_parser(context
, ts
.trees());
1211 id
: ast
::NodeId
::root(), // dummy value
1212 kind
: ast
::ExprKind
::Try(parser
.parse_expr().ok()?
),
1213 span
: mac
.span(), // incorrect span, but shouldn't matter too much
1214 attrs
: ast
::AttrVec
::new(),
1215 tokens
: Some(LazyTokenStream
::new(ts
)),
1222 pub(crate) fn macro_style(mac
: &ast
::MacCall
, context
: &RewriteContext
<'_
>) -> DelimToken
{
1223 let snippet
= context
.snippet(mac
.span());
1224 let paren_pos
= snippet
.find_uncommented("(").unwrap_or(usize::max_value());
1225 let bracket_pos
= snippet
.find_uncommented("[").unwrap_or(usize::max_value());
1226 let brace_pos
= snippet
.find_uncommented("{").unwrap_or(usize::max_value());
1228 if paren_pos
< bracket_pos
&& paren_pos
< brace_pos
{
1230 } else if bracket_pos
< brace_pos
{
1237 // A very simple parser that just parses a macros 2.0 definition into its branches.
1238 // Currently we do not attempt to parse any further than that.
1240 struct MacroParser
{
1245 // (`(` ... `)` `=>` `{` ... `}`)*
1246 fn parse(&mut self) -> Option
<Macro
> {
1247 let mut branches
= vec
![];
1248 while self.toks
.look_ahead(1).is_some() {
1249 branches
.push(self.parse_branch()?
);
1252 Some(Macro { branches }
)
1255 // `(` ... `)` `=>` `{` ... `}`
1256 fn parse_branch(&mut self) -> Option
<MacroBranch
> {
1257 let tok
= self.toks
.next()?
;
1258 let (lo
, args_paren_kind
) = match tok
{
1259 TokenTree
::Token(..) => return None
,
1260 TokenTree
::Delimited(delimited_span
, d
, _
) => (delimited_span
.open
.lo(), d
),
1262 let args
= tok
.joint();
1263 match self.toks
.next()?
{
1264 TokenTree
::Token(Token
{
1265 kind
: TokenKind
::FatArrow
,
1270 let (mut hi
, body
, whole_body
) = match self.toks
.next()?
{
1271 TokenTree
::Token(..) => return None
,
1272 TokenTree
::Delimited(delimited_span
, ..) => {
1273 let data
= delimited_span
.entire().data();
1276 Span
::new(data
.lo
+ BytePos(1), data
.hi
- BytePos(1), data
.ctxt
),
1277 delimited_span
.entire(),
1281 if let Some(TokenTree
::Token(Token
{
1282 kind
: TokenKind
::Semi
,
1284 })) = self.toks
.look_ahead(0)
1290 span
: mk_sp(lo
, hi
),
1299 // A parsed macros 2.0 macro definition.
1301 branches
: Vec
<MacroBranch
>,
1304 // FIXME: it would be more efficient to use references to the token streams
1305 // rather than clone them, if we can make the borrowing work out.
1306 struct MacroBranch
{
1308 args_paren_kind
: DelimToken
,
1317 context
: &RewriteContext
<'_
>,
1319 multi_branch_style
: bool
,
1320 ) -> Option
<String
> {
1321 // Only attempt to format function-like macros.
1322 if self.args_paren_kind
!= DelimToken
::Paren
{
1323 // FIXME(#1539): implement for non-sugared macros.
1328 let mut result
= format_macro_args(context
, self.args
.clone(), shape
.sub_width(5)?
)?
;
1330 if multi_branch_style
{
1334 if !context
.config
.format_macro_bodies() {
1336 result
+= context
.snippet(self.whole_body
);
1337 return Some(result
);
1340 // The macro body is the most interesting part. It might end up as various
1341 // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1342 // parsed as regular Rust code (and note that these can be escaped using
1343 // `$$`). We'll try and format like an AST node, but we'll substitute
1344 // variables for new names with the same length first.
1346 let old_body
= context
.snippet(self.body
).trim();
1347 let (body_str
, substs
) = replace_names(old_body
)?
;
1348 let has_block_body
= old_body
.starts_with('
{'
);
1350 let mut config
= context
.config
.clone();
1351 config
.set().hide_parse_errors(true);
1355 let body_indent
= if has_block_body
{
1358 shape
.indent
.block_indent(&config
)
1360 let new_width
= config
.max_width() - body_indent
.width();
1361 config
.set().max_width(new_width
);
1363 // First try to format as items, then as statements.
1364 let new_body_snippet
= match crate::format_snippet(&body_str
, &config
, true) {
1365 Some(new_body
) => new_body
,
1367 let new_width
= new_width
+ config
.tab_spaces();
1368 config
.set().max_width(new_width
);
1369 match crate::format_code_block(&body_str
, &config
, true) {
1370 Some(new_body
) => new_body
,
1371 None
=> return None
,
1375 let new_body
= wrap_str(
1376 new_body_snippet
.snippet
.to_string(),
1381 // Indent the body since it is in a block.
1382 let indent_str
= body_indent
.to_string(&config
);
1383 let mut new_body
= LineClasses
::new(new_body
.trim_end())
1386 (String
::new(), true),
1387 |(mut s
, need_indent
), (i
, (kind
, ref l
))| {
1388 if !is_empty_line(l
)
1390 && !new_body_snippet
.is_line_non_formatted(i
+ 1)
1394 (s
+ l
+ "\n", indent_next_line(kind
, &l
, &config
))
1399 // Undo our replacement of macro variables.
1400 // FIXME: this could be *much* more efficient.
1401 for (old
, new
) in &substs
{
1402 if old_body
.find(new
).is_some() {
1403 debug
!("rewrite_macro_def: bailing matching variable: `{}`", new
);
1406 new_body
= new_body
.replace(new
, old
);
1410 result
+= new_body
.trim();
1411 } else if !new_body
.is_empty() {
1413 result
+= &new_body
;
1414 result
+= &shape
.indent
.to_string(&config
);
1423 /// Format `lazy_static!` from https://crates.io/crates/lazy_static.
1425 /// # Expected syntax
1429 /// [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1430 /// [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1432 /// [pub] static ref NAME_N: TYPE_N = EXPR_N;
1435 fn format_lazy_static(
1436 context
: &RewriteContext
<'_
>,
1439 ) -> Option
<String
> {
1440 let mut result
= String
::with_capacity(1024);
1441 let mut parser
= build_parser(context
, ts
.trees());
1442 let nested_shape
= shape
1443 .block_indent(context
.config
.tab_spaces())
1444 .with_max_width(context
.config
);
1446 result
.push_str("lazy_static! {");
1447 result
.push_str(&nested_shape
.indent
.to_string_with_newline(context
.config
));
1449 macro_rules
! parse_or
{
1450 ($method
:ident $
(,)* $
($arg
:expr
),* $
(,)*) => {
1451 match parser
.$
method($
($arg
,)*) {
1453 if parser
.sess
.span_diagnostic
.has_errors() {
1454 parser
.sess
.span_diagnostic
.reset_err_count();
1462 parser
.sess
.span_diagnostic
.reset_err_count();
1469 while parser
.token
.kind
!= TokenKind
::Eof
{
1470 // Parse a `lazy_static!` item.
1471 let vis
= crate::utils
::format_visibility(
1473 &parse_or
!(parse_visibility
, rustc_parse
::parser
::FollowedByType
::No
),
1475 parser
.eat_keyword(kw
::Static
);
1476 parser
.eat_keyword(kw
::Ref
);
1477 let id
= parse_or
!(parse_ident
);
1478 parser
.eat(&TokenKind
::Colon
);
1479 let ty
= parse_or
!(parse_ty
);
1480 parser
.eat(&TokenKind
::Eq
);
1481 let expr
= parse_or
!(parse_expr
);
1482 parser
.eat(&TokenKind
::Semi
);
1484 // Rewrite as a static item.
1485 let mut stmt
= String
::with_capacity(128);
1486 stmt
.push_str(&format
!(
1487 "{}static ref {}: {} =",
1490 ty
.rewrite(context
, nested_shape
)?
1492 result
.push_str(&crate::expr
::rewrite_assign_rhs(
1496 nested_shape
.sub_width(1)?
,
1499 if parser
.token
.kind
!= TokenKind
::Eof
{
1500 result
.push_str(&nested_shape
.indent
.to_string_with_newline(context
.config
));
1504 result
.push_str(&shape
.indent
.to_string_with_newline(context
.config
));
1510 fn rewrite_macro_with_items(
1511 context
: &RewriteContext
<'_
>,
1516 position
: MacroPosition
,
1518 ) -> Option
<String
> {
1519 let (opener
, closer
) = match style
{
1520 DelimToken
::Paren
=> ("(", ")"),
1521 DelimToken
::Bracket
=> ("[", "]"),
1522 DelimToken
::Brace
=> (" {", "}"),
1525 let trailing_semicolon
= match style
{
1526 DelimToken
::Paren
| DelimToken
::Bracket
if position
== MacroPosition
::Item
=> ";",
1530 let mut visitor
= FmtVisitor
::from_context(context
);
1531 visitor
.block_indent
= shape
.indent
.block_indent(context
.config
);
1532 visitor
.last_pos
= context
.snippet_provider
.span_after(span
, opener
.trim());
1534 let item
= match item
{
1535 MacroArg
::Item(item
) => item
,
1538 visitor
.visit_item(&item
);
1541 let mut result
= String
::with_capacity(256);
1542 result
.push_str(¯o_name
);
1543 result
.push_str(opener
);
1544 result
.push_str(&visitor
.block_indent
.to_string_with_newline(context
.config
));
1545 result
.push_str(visitor
.buffer
.trim());
1546 result
.push_str(&shape
.indent
.to_string_with_newline(context
.config
));
1547 result
.push_str(closer
);
1548 result
.push_str(trailing_semicolon
);
1552 const RUST_KW
: [Symbol
; 59] = [
1606 kw
::UnderscoreLifetime
,