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