diff --git a/src/expr.rs b/src/expr.rs index 85a2e658ef2..b4968d12a0a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3051,6 +3051,7 @@ impl<'a> ToExpr for MacroArg { MacroArg::Expr(ref expr) => can_be_overflowed_expr(context, expr, len), MacroArg::Ty(ref ty) => can_be_overflowed_type(context, ty, len), MacroArg::Pat(..) => false, + MacroArg::Item(..) => len == 1, } } } diff --git a/src/lib.rs b/src/lib.rs index fe08b68c782..310cce4bbec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -596,14 +596,23 @@ pub fn format_snippet(snippet: &str, config: &Config) -> Option { } } +const FN_MAIN_PREFIX: &str = "fn main() {\n"; + +fn enclose_in_main_block(s: &str, config: &Config) -> String { + let indent = Indent::from_width(config, config.tab_spaces()); + FN_MAIN_PREFIX.to_owned() + &indent.to_string(config) + + &s.lines() + .collect::>() + .join(&indent.to_string_with_newline(config)) + "\n}" +} + /// Format the given code block. Mainly targeted for code block in comment. /// The code block may be incomplete (i.e. parser may be unable to parse it). /// To avoid panic in parser, we wrap the code block with a dummy function. /// The returned code block does *not* end with newline. pub fn format_code_block(code_snippet: &str, config: &Config) -> Option { // Wrap the given code block with `fn main()` if it does not have one. - let fn_main_prefix = "fn main() {\n"; - let snippet = fn_main_prefix.to_owned() + code_snippet + "\n}"; + let snippet = enclose_in_main_block(code_snippet, config); let mut result = String::with_capacity(snippet.len()); let mut is_first = true; @@ -612,7 +621,7 @@ pub fn format_code_block(code_snippet: &str, config: &Config) -> Option let formatted = format_snippet(&snippet, config)?; // 2 = "}\n" let block_len = formatted.len().checked_sub(2).unwrap_or(0); - for line in formatted[fn_main_prefix.len()..block_len].lines() { + for line in formatted[FN_MAIN_PREFIX.len()..block_len].lines() { if !is_first { result.push('\n'); } else { diff --git a/src/macros.rs b/src/macros.rs index 6be6a1f2664..ac4b0db7266 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -22,7 +22,7 @@ use std::collections::HashMap; use config::lists::*; -use syntax::ast; +use syntax::{ast, ptr}; use syntax::codemap::{BytePos, Span}; use syntax::parse::new_parser_from_tts; use syntax::parse::parser::Parser; @@ -38,6 +38,7 @@ use expr::{rewrite_array, rewrite_call_inner}; use lists::{itemize_list, write_list, ListFormatting}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; +use spanned::Spanned; use utils::{format_visibility, mk_sp, wrap_str}; const FORCED_BRACKET_MACROS: &[&str] = &["vec!"]; @@ -70,9 +71,21 @@ impl MacroStyle { #[derive(Debug)] pub enum MacroArg { - Expr(ast::Expr), - Ty(ast::Ty), - Pat(ast::Pat), + Expr(ptr::P), + Ty(ptr::P), + Pat(ptr::P), + // `parse_item` returns `Option>`. + Item(Option>), +} + +impl Rewrite for ast::Item { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + let mut visitor = ::visitor::FmtVisitor::from_context(context); + visitor.block_indent = shape.indent; + visitor.last_pos = self.span().lo(); + visitor.visit_item(self); + Some(visitor.buffer) + } } impl Rewrite for MacroArg { @@ -81,6 +94,7 @@ impl Rewrite for MacroArg { MacroArg::Expr(ref expr) => expr.rewrite(context, shape), MacroArg::Ty(ref ty) => ty.rewrite(context, shape), MacroArg::Pat(ref pat) => pat.rewrite(context, shape), + MacroArg::Item(ref item) => item.as_ref().and_then(|item| item.rewrite(context, shape)), } } } @@ -96,7 +110,7 @@ fn parse_macro_arg(parser: &mut Parser) -> Option { } else { // Parsing succeeded. *parser = cloned_parser; - return Some(MacroArg::$macro_arg((*x).clone())); + return Some(MacroArg::$macro_arg(x.clone())); } } Err(mut e) => { @@ -110,6 +124,7 @@ fn parse_macro_arg(parser: &mut Parser) -> Option { parse_macro_arg!(Expr, parse_expr); parse_macro_arg!(Ty, parse_ty); parse_macro_arg!(Pat, parse_pat); + parse_macro_arg!(Item, parse_item); None } diff --git a/src/spanned.rs b/src/spanned.rs index d1f4865dead..6f5a4b1721f 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -187,6 +187,7 @@ impl Spanned for MacroArg { MacroArg::Expr(ref expr) => expr.span(), MacroArg::Ty(ref ty) => ty.span(), MacroArg::Pat(ref pat) => pat.span(), + MacroArg::Item(ref item) => item.as_ref().unwrap().span(), } } } diff --git a/tests/source/issue-2523.rs b/tests/source/issue-2523.rs new file mode 100644 index 00000000000..693d06e131a --- /dev/null +++ b/tests/source/issue-2523.rs @@ -0,0 +1,17 @@ +// rustfmt-normalize_comments: true + +// Do not unindent macro calls in comment with unformattable syntax. +//! ```rust +//! let x = 3 ; +//! some_macro!(pub fn fn foo() ( +//! println!("Don't unindent me!"); +//! )); +//! ``` + +// Format items that appear as arguments of macro call. +//! ```rust +//! let x = 3 ; +//! some_macro!(pub fn foo() { +//! println!("Don't unindent me!"); +//! }); +//! ``` diff --git a/tests/target/issue-2523.rs b/tests/target/issue-2523.rs new file mode 100644 index 00000000000..6805f7ec2ca --- /dev/null +++ b/tests/target/issue-2523.rs @@ -0,0 +1,17 @@ +// rustfmt-normalize_comments: true + +// Do not unindent macro calls in comment with unformattable syntax. +//! ```rust +//! let x = 3; +//! some_macro!(pub fn fn foo() ( +//! println!("Don't unindent me!"); +//! )); +//! ``` + +// Format items that appear as arguments of macro call. +//! ```rust +//! let x = 3; +//! some_macro!(pub fn foo() { +//! println!("Don't unindent me!"); +//! }); +//! ```