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, Delimiter, Token, TokenKind}
;
16 use rustc_ast
::tokenstream
::{Cursor, Spacing, TokenStream, TokenTree}
;
17 use rustc_ast
::{ast, ptr}
;
18 use rustc_ast_pretty
::pprust
;
21 BytePos
, Span
, Symbol
, DUMMY_SP
,
25 contains_comment
, CharClasses
, FindUncommented
, FullCodeCharKind
, LineClasses
,
27 use crate::config
::lists
::*;
28 use crate::expr
::{rewrite_array, rewrite_assign_rhs, RhsAssignKind}
;
29 use crate::lists
::{itemize_list, write_list, ListFormatting}
;
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
;
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 pub(crate) 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 /// Rewrite macro name without using pretty-printer if possible.
94 fn rewrite_macro_name(
95 context
: &RewriteContext
<'_
>,
97 extra_ident
: Option
<symbol
::Ident
>,
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
))
103 format
!("{}!", pprust
::path_to_string(path
))
106 Some(ident
) if ident
.name
!= kw
::Empty
=> format
!("{} {}", name
, ident
),
111 // Use this on failing to format the macro call.
112 fn return_macro_parse_failure_fallback(
113 context
: &RewriteContext
<'_
>,
115 position
: MacroPosition
,
117 ) -> Option
<String
> {
118 // Mark this as a failure however we format it
119 context
.macro_rewrite_failure
.replace(true);
121 // Heuristically determine whether the last line of the macro uses "Block" style
122 // rather than using "Visual" style, or another indentation style.
123 let is_like_block_indent_style
= context
127 .map(|closing_line
| {
131 .all(|ch
| matches
!(ch
, '
}'
| '
)'
| '
]'
))
134 if is_like_block_indent_style
{
135 return trim_left_preserve_layout(context
.snippet(span
), indent
, context
.config
);
138 context
.skipped_range
.borrow_mut().push((
139 context
.parse_sess
.line_of_byte_pos(span
.lo()),
140 context
.parse_sess
.line_of_byte_pos(span
.hi()),
143 // Return the snippet unmodified if the macro is not block-like
144 let mut snippet
= context
.snippet(span
).to_owned();
145 if position
== MacroPosition
::Item
{
151 pub(crate) fn rewrite_macro(
153 extra_ident
: Option
<symbol
::Ident
>,
154 context
: &RewriteContext
<'_
>,
156 position
: MacroPosition
,
157 ) -> Option
<String
> {
158 let should_skip
= context
160 .skip_macro(context
.snippet(mac
.path
.span
));
164 let guard
= context
.enter_macro();
165 let result
= catch_unwind(AssertUnwindSafe(|| {
176 Err(..) | Ok(None
) => {
177 context
.macro_rewrite_failure
.replace(true);
185 fn rewrite_macro_inner(
187 extra_ident
: Option
<symbol
::Ident
>,
188 context
: &RewriteContext
<'_
>,
190 position
: MacroPosition
,
191 is_nested_macro
: bool
,
192 ) -> Option
<String
> {
193 if context
.config
.use_try_shorthand() {
194 if let Some(expr
) = convert_try_mac(mac
, context
) {
195 context
.leave_macro();
196 return expr
.rewrite(context
, shape
);
200 let original_style
= macro_style(mac
, context
);
202 let macro_name
= rewrite_macro_name(context
, &mac
.path
, extra_ident
);
203 let is_forced_bracket
= FORCED_BRACKET_MACROS
.contains(&¯o_name
[..]);
205 let style
= if is_forced_bracket
&& !is_nested_macro
{
211 let ts
= mac
.args
.inner_tokens();
212 let has_comment
= contains_comment(context
.snippet(mac
.span()));
213 if ts
.is_empty() && !has_comment
{
215 Delimiter
::Parenthesis
if position
== MacroPosition
::Item
=> {
216 Some(format
!("{}();", macro_name
))
218 Delimiter
::Bracket
if position
== MacroPosition
::Item
=> {
219 Some(format
!("{}[];", macro_name
))
221 Delimiter
::Parenthesis
=> Some(format
!("{}()", macro_name
)),
222 Delimiter
::Bracket
=> Some(format
!("{}[]", macro_name
)),
223 Delimiter
::Brace
=> Some(format
!("{} {{}}", macro_name
)),
227 // Format well-known macros which cannot be parsed as a valid AST.
228 if macro_name
== "lazy_static!" && !has_comment
{
229 if let success @
Some(..) = format_lazy_static(context
, shape
, ts
.clone()) {
234 let ParsedMacroArgs
{
238 } = match parse_macro_args(context
, ts
, style
, is_forced_bracket
) {
241 return return_macro_parse_failure_fallback(
250 if !arg_vec
.is_empty() && arg_vec
.iter().all(MacroArg
::is_item
) {
251 return rewrite_macro_with_items(
263 Delimiter
::Parenthesis
=> {
264 // Handle special case: `vec!(expr; expr)`
266 handle_vec_semi(context
, shape
, arg_vec
, macro_name
, style
)
268 // Format macro invocation as function call, preserve the trailing
269 // comma because not all macros support them.
270 overflow
::rewrite_with_parens(
276 context
.config
.fn_call_width(),
278 Some(SeparatorTactic
::Always
)
280 Some(SeparatorTactic
::Never
)
283 .map(|rw
| match position
{
284 MacroPosition
::Item
=> format
!("{};", rw
),
289 Delimiter
::Bracket
=> {
290 // Handle special case: `vec![expr; expr]`
292 handle_vec_semi(context
, shape
, arg_vec
, macro_name
, style
)
294 // If we are rewriting `vec!` macro or other special macros,
295 // then we can rewrite this as a usual array literal.
296 // Otherwise, we must preserve the original existence of trailing comma.
297 let macro_name
= ¯o_name
.as_str();
298 let mut force_trailing_comma
= if trailing_comma
{
299 Some(SeparatorTactic
::Always
)
301 Some(SeparatorTactic
::Never
)
303 if FORCED_BRACKET_MACROS
.contains(macro_name
) && !is_nested_macro
{
304 context
.leave_macro();
305 if context
.use_block_indent() {
306 force_trailing_comma
= Some(SeparatorTactic
::Vertical
);
309 let rewrite
= rewrite_array(
315 force_trailing_comma
,
316 Some(original_style
),
318 let comma
= match position
{
319 MacroPosition
::Item
=> ";",
323 Some(format
!("{}{}", rewrite
, comma
))
326 Delimiter
::Brace
=> {
327 // For macro invocations with braces, always put a space between
328 // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
329 // anything in between the braces (for now).
330 let snippet
= context
.snippet(mac
.span()).trim_start_matches(|c
| c
!= '
{'
);
331 match trim_left_preserve_layout(snippet
, shape
.indent
, context
.config
) {
332 Some(macro_body
) => Some(format
!("{} {}", macro_name
, macro_body
)),
333 None
=> Some(format
!("{} {}", macro_name
, snippet
)),
341 context
: &RewriteContext
<'_
>,
343 arg_vec
: Vec
<MacroArg
>,
345 delim_token
: Delimiter
,
346 ) -> Option
<String
> {
347 let (left
, right
) = match delim_token
{
348 Delimiter
::Parenthesis
=> ("(", ")"),
349 Delimiter
::Bracket
=> ("[", "]"),
353 let mac_shape
= shape
.offset_left(macro_name
.len())?
;
354 // 8 = `vec![]` + `; ` or `vec!()` + `; `
355 let total_overhead
= 8;
356 let nested_shape
= mac_shape
.block_indent(context
.config
.tab_spaces());
357 let lhs
= arg_vec
[0].rewrite(context
, nested_shape
)?
;
358 let rhs
= arg_vec
[1].rewrite(context
, nested_shape
)?
;
359 if !lhs
.contains('
\n'
)
360 && !rhs
.contains('
\n'
)
361 && lhs
.len() + rhs
.len() + total_overhead
<= shape
.width
363 // macro_name(lhs; rhs) or macro_name[lhs; rhs]
364 Some(format
!("{}{}{}; {}{}", macro_name
, left
, lhs
, rhs
, right
))
366 // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
371 nested_shape
.indent
.to_string_with_newline(context
.config
),
373 nested_shape
.indent
.to_string_with_newline(context
.config
),
375 shape
.indent
.to_string_with_newline(context
.config
),
381 pub(crate) fn rewrite_macro_def(
382 context
: &RewriteContext
<'_
>,
386 ident
: symbol
::Ident
,
387 vis
: &ast
::Visibility
,
389 ) -> Option
<String
> {
390 let snippet
= Some(remove_trailing_white_spaces(context
.snippet(span
)));
391 if snippet
.as_ref().map_or(true, |s
| s
.ends_with('
;'
)) {
395 let ts
= def
.body
.inner_tokens();
396 let mut parser
= MacroParser
::new(ts
.into_trees());
397 let parsed_def
= match parser
.parse() {
399 None
=> return snippet
,
402 let mut result
= if def
.macro_rules
{
403 String
::from("macro_rules!")
405 format
!("{}macro", format_visibility(context
, vis
))
409 result
+= rewrite_ident(context
, ident
);
411 let multi_branch_style
= def
.macro_rules
|| parsed_def
.branches
.len() != 1;
413 let arm_shape
= if multi_branch_style
{
415 .block_indent(context
.config
.tab_spaces())
416 .with_max_width(context
.config
)
421 let branch_items
= itemize_list(
422 context
.snippet_provider
,
423 parsed_def
.branches
.iter(),
426 |branch
| branch
.span
.lo(),
427 |branch
| branch
.span
.hi(),
428 |branch
| match branch
.rewrite(context
, arm_shape
, multi_branch_style
) {
430 // if the rewrite returned None because a macro could not be rewritten, then return the
432 None
if context
.macro_rewrite_failure
.get() => {
433 Some(context
.snippet(branch
.body
).trim().to_string())
437 context
.snippet_provider
.span_after(span
, "{"),
441 .collect
::<Vec
<_
>>();
443 let fmt
= ListFormatting
::new(arm_shape
, context
.config
)
444 .separator(if def
.macro_rules { ";" }
else { "" }
)
445 .trailing_separator(SeparatorTactic
::Always
)
446 .preserve_newline(true);
448 if multi_branch_style
{
450 result
+= &arm_shape
.indent
.to_string_with_newline(context
.config
);
453 match write_list(&branch_items
, &fmt
) {
454 Some(ref s
) => result
+= s
,
455 None
=> return snippet
,
458 if multi_branch_style
{
459 result
+= &indent
.to_string_with_newline(context
.config
);
466 fn register_metavariable(
467 map
: &mut HashMap
<String
, String
>,
472 let mut new_name
= "$".repeat(dollar_count
- 1);
473 let mut old_name
= "$".repeat(dollar_count
);
476 new_name
.push_str(name
);
477 old_name
.push_str(name
);
479 result
.push_str(&new_name
);
480 map
.insert(old_name
, new_name
);
483 // Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
484 // aren't causing problems.
485 // This should also work for escaped `$` variables, where we leave earlier `$`s.
486 fn replace_names(input
: &str) -> Option
<(String
, HashMap
<String
, String
>)> {
487 // Each substitution will require five or six extra bytes.
488 let mut result
= String
::with_capacity(input
.len() + 64);
489 let mut substs
= HashMap
::new();
490 let mut dollar_count
= 0;
491 let mut cur_name
= String
::new();
493 for (kind
, c
) in CharClasses
::new(input
.chars()) {
494 if kind
!= FullCodeCharKind
::Normal
{
498 } else if dollar_count
== 0 {
500 } else if !c
.is_alphanumeric() && !cur_name
.is_empty() {
501 // Terminates a name following one or more dollars.
502 register_metavariable(&mut substs
, &mut result
, &cur_name
, dollar_count
);
507 } else if c
== '
('
&& cur_name
.is_empty() {
508 // FIXME: Support macro def with repeat.
510 } else if c
.is_alphanumeric() || c
== '_'
{
515 if !cur_name
.is_empty() {
516 register_metavariable(&mut substs
, &mut result
, &cur_name
, dollar_count
);
519 debug
!("replace_names `{}` {:?}", result
, substs
);
521 Some((result
, substs
))
524 #[derive(Debug, Clone)]
526 /// e.g., `$x: expr`.
527 MetaVariable(Symbol
, String
),
528 /// e.g., `$($foo: expr),*`
530 /// `()`, `[]` or `{}`.
532 /// Inner arguments inside delimiters.
534 /// Something after the closing delimiter and the repeat token, if available.
535 Option
<Box
<ParsedMacroArg
>>,
536 /// The repeat token. This could be one of `*`, `+` or `?`.
539 /// e.g., `[derive(Debug)]`
540 Delimited(Delimiter
, Vec
<ParsedMacroArg
>),
541 /// A possible separator. e.g., `,` or `;`.
542 Separator(String
, String
),
543 /// Other random stuff that does not fit to other kinds.
544 /// e.g., `== foo` in `($x: expr == foo)`.
545 Other(String
, String
),
548 fn delim_token_to_str(
549 context
: &RewriteContext
<'_
>,
550 delim_token
: Delimiter
,
552 use_multiple_lines
: bool
,
553 inner_is_empty
: bool
,
554 ) -> (String
, String
) {
555 let (lhs
, rhs
) = match delim_token
{
556 Delimiter
::Parenthesis
=> ("(", ")"),
557 Delimiter
::Bracket
=> ("[", "]"),
558 Delimiter
::Brace
=> {
559 if inner_is_empty
|| use_multiple_lines
{
565 Delimiter
::Invisible
=> unreachable
!(),
567 if use_multiple_lines
{
568 let indent_str
= shape
.indent
.to_string_with_newline(context
.config
);
569 let nested_indent_str
= shape
571 .block_indent(context
.config
)
572 .to_string_with_newline(context
.config
);
574 format
!("{}{}", lhs
, nested_indent_str
),
575 format
!("{}{}", indent_str
, rhs
),
578 (lhs
.to_owned(), rhs
.to_owned())
583 fn starts_with_brace(&self) -> bool
{
586 MacroArgKind
::Repeat(Delimiter
::Brace
, _
, _
, _
)
587 | MacroArgKind
::Delimited(Delimiter
::Brace
, _
)
591 fn starts_with_dollar(&self) -> bool
{
594 MacroArgKind
::Repeat(..) | MacroArgKind
::MetaVariable(..)
598 fn ends_with_space(&self) -> bool
{
599 matches
!(*self, MacroArgKind
::Separator(..))
602 fn has_meta_var(&self) -> bool
{
604 MacroArgKind
::MetaVariable(..) => true,
605 MacroArgKind
::Repeat(_
, ref args
, _
, _
) => args
.iter().any(|a
| a
.kind
.has_meta_var()),
612 context
: &RewriteContext
<'_
>,
614 use_multiple_lines
: bool
,
615 ) -> Option
<String
> {
616 let rewrite_delimited_inner
= |delim_tok
, args
| -> Option
<(String
, String
, String
)> {
617 let inner
= wrap_macro_args(context
, args
, shape
)?
;
618 let (lhs
, rhs
) = delim_token_to_str(context
, delim_tok
, shape
, false, inner
.is_empty());
619 if lhs
.len() + inner
.len() + rhs
.len() <= shape
.width
{
620 return Some((lhs
, inner
, rhs
));
623 let (lhs
, rhs
) = delim_token_to_str(context
, delim_tok
, shape
, true, false);
624 let nested_shape
= shape
625 .block_indent(context
.config
.tab_spaces())
626 .with_max_width(context
.config
);
627 let inner
= wrap_macro_args(context
, args
, nested_shape
)?
;
628 Some((lhs
, inner
, rhs
))
632 MacroArgKind
::MetaVariable(ty
, ref name
) => Some(format
!("${}:{}", name
, ty
)),
633 MacroArgKind
::Repeat(delim_tok
, ref args
, ref another
, ref tok
) => {
634 let (lhs
, inner
, rhs
) = rewrite_delimited_inner(delim_tok
, args
)?
;
635 let another
= another
637 .and_then(|a
| a
.rewrite(context
, shape
, use_multiple_lines
))
638 .unwrap_or_else(|| "".to_owned());
639 let repeat_tok
= pprust
::token_to_string(tok
);
641 Some(format
!("${}{}{}{}{}", lhs
, inner
, rhs
, another
, repeat_tok
))
643 MacroArgKind
::Delimited(delim_tok
, ref args
) => {
644 rewrite_delimited_inner(delim_tok
, args
)
645 .map(|(lhs
, inner
, rhs
)| format
!("{}{}{}", lhs
, inner
, rhs
))
647 MacroArgKind
::Separator(ref sep
, ref prefix
) => Some(format
!("{}{} ", prefix
, sep
)),
648 MacroArgKind
::Other(ref inner
, ref prefix
) => Some(format
!("{}{}", prefix
, inner
)),
653 #[derive(Debug, Clone)]
654 struct ParsedMacroArg
{
658 impl ParsedMacroArg
{
661 context
: &RewriteContext
<'_
>,
663 use_multiple_lines
: bool
,
664 ) -> Option
<String
> {
665 self.kind
.rewrite(context
, shape
, use_multiple_lines
)
669 /// Parses macro arguments on macro def.
670 struct MacroArgParser
{
671 /// Either a name of the next metavariable, a separator, or junk.
673 /// The first token of the current buffer.
675 /// `true` if we are parsing a metavariable or a repeat.
677 /// The last token parsed.
679 /// Holds the parsed arguments.
680 result
: Vec
<ParsedMacroArg
>,
683 fn last_tok(tt
: &TokenTree
) -> Token
{
685 TokenTree
::Token(ref t
) => t
.clone(),
686 TokenTree
::Delimited(delim_span
, delim
, _
) => Token
{
687 kind
: TokenKind
::CloseDelim(delim
),
688 span
: delim_span
.close
,
693 impl MacroArgParser
{
694 fn new() -> MacroArgParser
{
699 kind
: TokenKind
::Eof
,
703 kind
: TokenKind
::Eof
,
710 fn set_last_tok(&mut self, tok
: &TokenTree
) {
711 self.last_tok
= last_tok(tok
);
714 fn add_separator(&mut self) {
715 let prefix
= if self.need_space_prefix() {
720 self.result
.push(ParsedMacroArg
{
721 kind
: MacroArgKind
::Separator(self.buf
.clone(), prefix
),
726 fn add_other(&mut self) {
727 let prefix
= if self.need_space_prefix() {
732 self.result
.push(ParsedMacroArg
{
733 kind
: MacroArgKind
::Other(self.buf
.clone(), prefix
),
738 fn add_meta_variable(&mut self, iter
: &mut Cursor
) -> Option
<()> {
740 Some(TokenTree
::Token(Token
{
741 kind
: TokenKind
::Ident(name
, _
),
744 self.result
.push(ParsedMacroArg
{
745 kind
: MacroArgKind
::MetaVariable(name
, self.buf
.clone()),
749 self.is_meta_var
= false;
756 fn add_delimited(&mut self, inner
: Vec
<ParsedMacroArg
>, delim
: Delimiter
) {
757 self.result
.push(ParsedMacroArg
{
758 kind
: MacroArgKind
::Delimited(delim
, inner
),
765 inner
: Vec
<ParsedMacroArg
>,
769 let mut buffer
= String
::new();
770 let mut first
= true;
772 // Parse '*', '+' or '?.
774 self.set_last_tok(&tok
);
780 TokenTree
::Token(Token
{
781 kind
: TokenKind
::BinOp(BinOpToken
::Plus
),
784 | TokenTree
::Token(Token
{
785 kind
: TokenKind
::Question
,
788 | TokenTree
::Token(Token
{
789 kind
: TokenKind
::BinOp(BinOpToken
::Star
),
794 TokenTree
::Token(ref t
) => {
795 buffer
.push_str(&pprust
::token_to_string(t
));
801 // There could be some random stuff between ')' and '*', '+' or '?'.
802 let another
= if buffer
.trim().is_empty() {
805 Some(Box
::new(ParsedMacroArg
{
806 kind
: MacroArgKind
::Other(buffer
, "".to_owned()),
810 self.result
.push(ParsedMacroArg
{
811 kind
: MacroArgKind
::Repeat(delim
, inner
, another
, self.last_tok
.clone()),
816 fn update_buffer(&mut self, t
: &Token
) {
817 if self.buf
.is_empty() {
818 self.start_tok
= t
.clone();
820 let needs_space
= match next_space(&self.last_tok
.kind
) {
821 SpaceState
::Ident
=> ident_like(t
),
822 SpaceState
::Punctuation
=> !ident_like(t
),
823 SpaceState
::Always
=> true,
824 SpaceState
::Never
=> false,
826 if force_space_before(&t
.kind
) || needs_space
{
831 self.buf
.push_str(&pprust
::token_to_string(t
));
834 fn need_space_prefix(&self) -> bool
{
835 if self.result
.is_empty() {
839 let last_arg
= self.result
.last().unwrap();
840 if let MacroArgKind
::MetaVariable(..) = last_arg
.kind
{
841 if ident_like(&self.start_tok
) {
844 if self.start_tok
.kind
== TokenKind
::Colon
{
849 if force_space_before(&self.start_tok
.kind
) {
856 /// Returns a collection of parsed macro def's arguments.
857 fn parse(mut self, tokens
: TokenStream
) -> Option
<Vec
<ParsedMacroArg
>> {
858 let mut iter
= tokens
.into_trees();
860 while let Some(tok
) = iter
.next() {
862 TokenTree
::Token(Token
{
863 kind
: TokenKind
::Dollar
,
866 // We always want to add a separator before meta variables.
867 if !self.buf
.is_empty() {
868 self.add_separator();
871 // Start keeping the name of this metavariable in the buffer.
872 self.is_meta_var
= true;
873 self.start_tok
= Token
{
874 kind
: TokenKind
::Dollar
,
878 TokenTree
::Token(Token
{
879 kind
: TokenKind
::Colon
,
881 }) if self.is_meta_var
=> {
882 self.add_meta_variable(&mut iter
)?
;
884 TokenTree
::Token(ref t
) => self.update_buffer(t
),
885 TokenTree
::Delimited(_delimited_span
, delimited
, ref tts
) => {
886 if !self.buf
.is_empty() {
887 if next_space(&self.last_tok
.kind
) == SpaceState
::Always
{
888 self.add_separator();
894 // Parse the stuff inside delimiters.
895 let parser
= MacroArgParser
::new();
896 let delimited_arg
= parser
.parse(tts
.clone())?
;
898 if self.is_meta_var
{
899 self.add_repeat(delimited_arg
, delimited
, &mut iter
)?
;
900 self.is_meta_var
= false;
902 self.add_delimited(delimited_arg
, delimited
);
907 self.set_last_tok(&tok
);
910 // We are left with some stuff in the buffer. Since there is nothing
911 // left to separate, add this as `Other`.
912 if !self.buf
.is_empty() {
921 context
: &RewriteContext
<'_
>,
922 args
: &[ParsedMacroArg
],
924 ) -> Option
<String
> {
925 wrap_macro_args_inner(context
, args
, shape
, false)
926 .or_else(|| wrap_macro_args_inner(context
, args
, shape
, true))
929 fn wrap_macro_args_inner(
930 context
: &RewriteContext
<'_
>,
931 args
: &[ParsedMacroArg
],
933 use_multiple_lines
: bool
,
934 ) -> Option
<String
> {
935 let mut result
= String
::with_capacity(128);
936 let mut iter
= args
.iter().peekable();
937 let indent_str
= shape
.indent
.to_string_with_newline(context
.config
);
939 while let Some(arg
) = iter
.next() {
940 result
.push_str(&arg
.rewrite(context
, shape
, use_multiple_lines
)?
);
942 if use_multiple_lines
943 && (arg
.kind
.ends_with_space() || iter
.peek().map_or(false, |a
| a
.kind
.has_meta_var()))
945 if arg
.kind
.ends_with_space() {
948 result
.push_str(&indent_str
);
949 } else if let Some(next_arg
) = iter
.peek() {
950 let space_before_dollar
=
951 !arg
.kind
.ends_with_space() && next_arg
.kind
.starts_with_dollar();
952 let space_before_brace
= next_arg
.kind
.starts_with_brace();
953 if space_before_dollar
|| space_before_brace
{
959 if !use_multiple_lines
&& result
.len() >= shape
.width
{
966 // This is a bit sketchy. The token rules probably need tweaking, but it works
967 // for some common cases. I hope the basic logic is sufficient. Note that the
968 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
969 // and `(`/`)` have special meaning.
971 // We always try and format on one line.
972 // FIXME: Use multi-line when every thing does not fit on one line.
973 fn format_macro_args(
974 context
: &RewriteContext
<'_
>,
975 token_stream
: TokenStream
,
977 ) -> Option
<String
> {
978 if !context
.config
.format_macro_matchers() {
979 let span
= span_for_token_stream(&token_stream
);
980 return Some(match span
{
981 Some(span
) => context
.snippet(span
).to_owned(),
982 None
=> String
::new(),
985 let parsed_args
= MacroArgParser
::new().parse(token_stream
)?
;
986 wrap_macro_args(context
, &parsed_args
, shape
)
989 fn span_for_token_stream(token_stream
: &TokenStream
) -> Option
<Span
> {
990 token_stream
.trees().next().map(|tt
| tt
.span())
993 // We should insert a space if the next token is a:
994 #[derive(Copy, Clone, PartialEq)]
998 Ident
, // Or ident/literal-like thing.
1002 fn force_space_before(tok
: &TokenKind
) -> bool
{
1003 debug
!("tok: force_space_before {:?}", tok
);
1017 | TokenKind
::BinOpEq(_
)
1021 | TokenKind
::FatArrow
1022 | TokenKind
::BinOp(_
)
1024 | TokenKind
::Dollar
=> true,
1029 fn ident_like(tok
: &Token
) -> bool
{
1032 TokenKind
::Ident(..) | TokenKind
::Literal(..) | TokenKind
::Lifetime(_
)
1036 fn next_space(tok
: &TokenKind
) -> SpaceState
{
1037 debug
!("next_space: {:?}", tok
);
1041 | TokenKind
::BinOp(BinOpToken
::And
)
1047 | TokenKind
::DotDotDot
1048 | TokenKind
::DotDotEq
1049 | TokenKind
::Question
=> SpaceState
::Punctuation
,
1054 | TokenKind
::OpenDelim(_
)
1055 | TokenKind
::CloseDelim(_
) => SpaceState
::Never
,
1057 TokenKind
::Literal(..) | TokenKind
::Ident(..) | TokenKind
::Lifetime(_
) => SpaceState
::Ident
,
1059 _
=> SpaceState
::Always
,
1063 /// Tries to convert a macro use into a short hand try expression. Returns `None`
1064 /// when the macro is not an instance of `try!` (or parsing the inner expression
1066 pub(crate) fn convert_try_mac(
1068 context
: &RewriteContext
<'_
>,
1069 ) -> Option
<ast
::Expr
> {
1070 let path
= &pprust
::path_to_string(&mac
.path
);
1071 if path
== "try" || path
== "r#try" {
1072 let ts
= mac
.args
.inner_tokens();
1075 id
: ast
::NodeId
::root(), // dummy value
1076 kind
: ast
::ExprKind
::Try(parse_expr(context
, ts
)?
),
1077 span
: mac
.span(), // incorrect span, but shouldn't matter too much
1078 attrs
: ast
::AttrVec
::new(),
1086 pub(crate) fn macro_style(mac
: &ast
::MacCall
, context
: &RewriteContext
<'_
>) -> Delimiter
{
1087 let snippet
= context
.snippet(mac
.span());
1088 let paren_pos
= snippet
.find_uncommented("(").unwrap_or(usize::max_value());
1089 let bracket_pos
= snippet
.find_uncommented("[").unwrap_or(usize::max_value());
1090 let brace_pos
= snippet
.find_uncommented("{").unwrap_or(usize::max_value());
1092 if paren_pos
< bracket_pos
&& paren_pos
< brace_pos
{
1093 Delimiter
::Parenthesis
1094 } else if bracket_pos
< brace_pos
{
1101 // A very simple parser that just parses a macros 2.0 definition into its branches.
1102 // Currently we do not attempt to parse any further than that.
1104 struct MacroParser
{
1109 // (`(` ... `)` `=>` `{` ... `}`)*
1110 fn parse(&mut self) -> Option
<Macro
> {
1111 let mut branches
= vec
![];
1112 while self.toks
.look_ahead(1).is_some() {
1113 branches
.push(self.parse_branch()?
);
1116 Some(Macro { branches }
)
1119 // `(` ... `)` `=>` `{` ... `}`
1120 fn parse_branch(&mut self) -> Option
<MacroBranch
> {
1121 let tok
= self.toks
.next()?
;
1122 let (lo
, args_paren_kind
) = match tok
{
1123 TokenTree
::Token(..) => return None
,
1124 TokenTree
::Delimited(delimited_span
, d
, _
) => (delimited_span
.open
.lo(), d
),
1126 let args
= TokenStream
::new(vec
![(tok
, Spacing
::Joint
)]);
1127 match self.toks
.next()?
{
1128 TokenTree
::Token(Token
{
1129 kind
: TokenKind
::FatArrow
,
1134 let (mut hi
, body
, whole_body
) = match self.toks
.next()?
{
1135 TokenTree
::Token(..) => return None
,
1136 TokenTree
::Delimited(delimited_span
, ..) => {
1137 let data
= delimited_span
.entire().data();
1141 data
.lo
+ BytePos(1),
1142 data
.hi
- BytePos(1),
1146 delimited_span
.entire(),
1150 if let Some(TokenTree
::Token(Token
{
1151 kind
: TokenKind
::Semi
,
1153 })) = self.toks
.look_ahead(0)
1159 span
: mk_sp(lo
, hi
),
1168 // A parsed macros 2.0 macro definition.
1170 branches
: Vec
<MacroBranch
>,
1173 // FIXME: it would be more efficient to use references to the token streams
1174 // rather than clone them, if we can make the borrowing work out.
1175 struct MacroBranch
{
1177 args_paren_kind
: Delimiter
,
1186 context
: &RewriteContext
<'_
>,
1188 multi_branch_style
: bool
,
1189 ) -> Option
<String
> {
1190 // Only attempt to format function-like macros.
1191 if self.args_paren_kind
!= Delimiter
::Parenthesis
{
1192 // FIXME(#1539): implement for non-sugared macros.
1197 let mut result
= format_macro_args(context
, self.args
.clone(), shape
.sub_width(5)?
)?
;
1199 if multi_branch_style
{
1203 if !context
.config
.format_macro_bodies() {
1205 result
+= context
.snippet(self.whole_body
);
1206 return Some(result
);
1209 // The macro body is the most interesting part. It might end up as various
1210 // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1211 // parsed as regular Rust code (and note that these can be escaped using
1212 // `$$`). We'll try and format like an AST node, but we'll substitute
1213 // variables for new names with the same length first.
1215 let old_body
= context
.snippet(self.body
).trim();
1216 let (body_str
, substs
) = replace_names(old_body
)?
;
1217 let has_block_body
= old_body
.starts_with('
{'
);
1219 let mut config
= context
.config
.clone();
1220 config
.set().hide_parse_errors(true);
1224 let body_indent
= if has_block_body
{
1227 shape
.indent
.block_indent(&config
)
1229 let new_width
= config
.max_width() - body_indent
.width();
1230 config
.set().max_width(new_width
);
1232 // First try to format as items, then as statements.
1233 let new_body_snippet
= match crate::format_snippet(&body_str
, &config
, true) {
1234 Some(new_body
) => new_body
,
1236 let new_width
= new_width
+ config
.tab_spaces();
1237 config
.set().max_width(new_width
);
1238 match crate::format_code_block(&body_str
, &config
, true) {
1239 Some(new_body
) => new_body
,
1240 None
=> return None
,
1244 let new_body
= wrap_str(
1245 new_body_snippet
.snippet
.to_string(),
1250 // Indent the body since it is in a block.
1251 let indent_str
= body_indent
.to_string(&config
);
1252 let mut new_body
= LineClasses
::new(new_body
.trim_end())
1255 (String
::new(), true),
1256 |(mut s
, need_indent
), (i
, (kind
, ref l
))| {
1257 if !is_empty_line(l
)
1259 && !new_body_snippet
.is_line_non_formatted(i
+ 1)
1263 (s
+ l
+ "\n", indent_next_line(kind
, l
, &config
))
1268 // Undo our replacement of macro variables.
1269 // FIXME: this could be *much* more efficient.
1270 for (old
, new
) in &substs
{
1271 if old_body
.contains(new
) {
1272 debug
!("rewrite_macro_def: bailing matching variable: `{}`", new
);
1275 new_body
= new_body
.replace(new
, old
);
1279 result
+= new_body
.trim();
1280 } else if !new_body
.is_empty() {
1282 result
+= &new_body
;
1283 result
+= &shape
.indent
.to_string(&config
);
1292 /// Format `lazy_static!` from <https://crates.io/crates/lazy_static>.
1294 /// # Expected syntax
1298 /// [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1299 /// [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1301 /// [pub] static ref NAME_N: TYPE_N = EXPR_N;
1304 fn format_lazy_static(
1305 context
: &RewriteContext
<'_
>,
1308 ) -> Option
<String
> {
1309 let mut result
= String
::with_capacity(1024);
1310 let nested_shape
= shape
1311 .block_indent(context
.config
.tab_spaces())
1312 .with_max_width(context
.config
);
1314 result
.push_str("lazy_static! {");
1315 result
.push_str(&nested_shape
.indent
.to_string_with_newline(context
.config
));
1317 let parsed_elems
= parse_lazy_static(context
, ts
)?
;
1318 let last
= parsed_elems
.len() - 1;
1319 for (i
, (vis
, id
, ty
, expr
)) in parsed_elems
.iter().enumerate() {
1320 // Rewrite as a static item.
1321 let vis
= crate::utils
::format_visibility(context
, vis
);
1322 let mut stmt
= String
::with_capacity(128);
1323 stmt
.push_str(&format
!(
1324 "{}static ref {}: {} =",
1327 ty
.rewrite(context
, nested_shape
)?
1329 result
.push_str(&rewrite_assign_rhs(
1333 &RhsAssignKind
::Expr(&expr
.kind
, expr
.span
),
1334 nested_shape
.sub_width(1)?
,
1338 result
.push_str(&nested_shape
.indent
.to_string_with_newline(context
.config
));
1342 result
.push_str(&shape
.indent
.to_string_with_newline(context
.config
));
1348 fn rewrite_macro_with_items(
1349 context
: &RewriteContext
<'_
>,
1354 position
: MacroPosition
,
1356 ) -> Option
<String
> {
1357 let (opener
, closer
) = match style
{
1358 Delimiter
::Parenthesis
=> ("(", ")"),
1359 Delimiter
::Bracket
=> ("[", "]"),
1360 Delimiter
::Brace
=> (" {", "}"),
1363 let trailing_semicolon
= match style
{
1364 Delimiter
::Parenthesis
| Delimiter
::Bracket
if position
== MacroPosition
::Item
=> ";",
1368 let mut visitor
= FmtVisitor
::from_context(context
);
1369 visitor
.block_indent
= shape
.indent
.block_indent(context
.config
);
1370 visitor
.last_pos
= context
.snippet_provider
.span_after(span
, opener
.trim());
1372 let item
= match item
{
1373 MacroArg
::Item(item
) => item
,
1376 visitor
.visit_item(item
);
1379 let mut result
= String
::with_capacity(256);
1380 result
.push_str(macro_name
);
1381 result
.push_str(opener
);
1382 result
.push_str(&visitor
.block_indent
.to_string_with_newline(context
.config
));
1383 result
.push_str(visitor
.buffer
.trim());
1384 result
.push_str(&shape
.indent
.to_string_with_newline(context
.config
));
1385 result
.push_str(closer
);
1386 result
.push_str(trailing_semicolon
);