feat: don't insert semi in macro_rules arm body

This commit is contained in:
Caleb Cartwright 2020-11-10 20:07:42 -06:00 committed by Caleb Cartwright
parent eb894d5370
commit a613c57521
8 changed files with 65 additions and 18 deletions

View File

@ -659,7 +659,7 @@ impl<'a> CommentRewrite<'a> {
config.set().wrap_comments(false);
if config.format_code_in_doc_comments() {
if let Some(s) =
crate::format_code_block(&self.code_block_buffer, &config)
crate::format_code_block(&self.code_block_buffer, &config, false)
{
trim_custom_comment_prefix(&s.snippet)
} else {

View File

@ -25,7 +25,11 @@ pub(crate) type SourceFile = Vec<FileRecord>;
pub(crate) type FileRecord = (FileName, String);
impl<'b, T: Write + 'b> Session<'b, T> {
pub(crate) fn format_input_inner(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
pub(crate) fn format_input_inner(
&mut self,
input: Input,
is_macro_def: bool,
) -> Result<FormatReport, ErrorKind> {
if !self.config.version_meets_requirement() {
return Err(ErrorKind::VersionMismatch);
}
@ -42,7 +46,7 @@ impl<'b, T: Write + 'b> Session<'b, T> {
}
let config = &self.config.clone();
let format_result = format_project(input, config, self);
let format_result = format_project(input, config, self, is_macro_def);
format_result.map(|report| {
self.errors.add(&report.internal.borrow().1);
@ -57,6 +61,7 @@ fn format_project<T: FormatHandler>(
input: Input,
config: &Config,
handler: &mut T,
is_macro_def: bool,
) -> Result<FormatReport, ErrorKind> {
let mut timer = Timer::start();
@ -103,7 +108,7 @@ fn format_project<T: FormatHandler>(
continue;
}
should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path));
context.format_file(path, &module)?;
context.format_file(path, &module, is_macro_def)?;
}
timer = timer.done_formatting();
@ -134,7 +139,12 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
}
// Formats a single file/module.
fn format_file(&mut self, path: FileName, module: &Module<'_>) -> Result<(), ErrorKind> {
fn format_file(
&mut self,
path: FileName,
module: &Module<'_>,
is_macro_def: bool,
) -> Result<(), ErrorKind> {
let snippet_provider = self.parse_session.snippet_provider(module.as_ref().inner);
let mut visitor = FmtVisitor::from_parse_sess(
&self.parse_session,
@ -143,7 +153,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
self.report.clone(),
);
visitor.skip_context.update_with_attrs(&self.krate.attrs);
visitor.is_macro_def = is_macro_def;
visitor.last_pos = snippet_provider.start_pos();
visitor.skip_empty_lines(snippet_provider.end_pos());
visitor.format_separate_mod(module, snippet_provider.end_pos());

View File

@ -286,7 +286,7 @@ impl fmt::Display for FormatReport {
/// Format the given snippet. The snippet is expected to be *complete* code.
/// When we cannot parse the given snippet, this function returns `None`.
fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option<FormattedSnippet> {
let mut config = config.clone();
panic::catch_unwind(|| {
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
@ -297,7 +297,7 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
let (formatting_error, result) = {
let input = Input::Text(snippet.into());
let mut session = Session::new(config, Some(&mut out));
let result = session.format(input);
let result = session.format_input_inner(input, is_macro_def);
(
session.errors.has_macro_format_failure
|| session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
@ -323,7 +323,11 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
/// 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.
fn format_code_block(code_snippet: &str, config: &Config) -> Option<FormattedSnippet> {
fn format_code_block(
code_snippet: &str,
config: &Config,
is_macro_def: bool,
) -> Option<FormattedSnippet> {
const FN_MAIN_PREFIX: &str = "fn main() {\n";
fn enclose_in_main_block(s: &str, config: &Config) -> String {
@ -356,7 +360,7 @@ fn format_code_block(code_snippet: &str, config: &Config) -> Option<FormattedSni
config_with_unix_newline
.set()
.newline_style(NewlineStyle::Unix);
let mut formatted = format_snippet(&snippet, &config_with_unix_newline)?;
let mut formatted = format_snippet(&snippet, &config_with_unix_newline, is_macro_def)?;
// Remove wrapping main block
formatted.unwrap_code_block();
@ -435,7 +439,7 @@ impl<'b, T: Write + 'b> Session<'b, T> {
/// The main entry point for Rustfmt. Formats the given input according to the
/// given config. `out` is only necessary if required by the configuration.
pub fn format(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
self.format_input_inner(input)
self.format_input_inner(input, false)
}
pub fn override_config<F, U>(&mut self, mut config: Config, f: F) -> U
@ -550,15 +554,15 @@ mod unit_tests {
// `format_snippet()` and `format_code_block()` should not panic
// even when we cannot parse the given snippet.
let snippet = "let";
assert!(format_snippet(snippet, &Config::default()).is_none());
assert!(format_code_block(snippet, &Config::default()).is_none());
assert!(format_snippet(snippet, &Config::default(), false).is_none());
assert!(format_code_block(snippet, &Config::default(), false).is_none());
}
fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
where
F: Fn(&str, &Config) -> Option<FormattedSnippet>,
F: Fn(&str, &Config, bool) -> Option<FormattedSnippet>,
{
let output = formatter(input, &Config::default());
let output = formatter(input, &Config::default(), false);
output.is_some() && output.unwrap().snippet == expected
}
@ -580,7 +584,7 @@ mod unit_tests {
fn test_format_code_block_fail() {
#[rustfmt::skip]
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
assert!(format_code_block(code_block, &Config::default()).is_none());
assert!(format_code_block(code_block, &Config::default(), false).is_none());
}
#[test]

View File

@ -1363,12 +1363,12 @@ impl MacroBranch {
config.set().max_width(new_width);
// First try to format as items, then as statements.
let new_body_snippet = match crate::format_snippet(&body_str, &config) {
let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
Some(new_body) => new_body,
None => {
let new_width = new_width + config.tab_spaces();
config.set().max_width(new_width);
match crate::format_code_block(&body_str, &config) {
match crate::format_code_block(&body_str, &config, true) {
Some(new_body) => new_body,
None => return None,
}

View File

@ -39,6 +39,7 @@ pub(crate) struct RewriteContext<'a> {
pub(crate) snippet_provider: &'a SnippetProvider,
// Used for `format_snippet`
pub(crate) macro_rewrite_failure: Cell<bool>,
pub(crate) is_macro_def: bool,
pub(crate) report: FormatReport,
pub(crate) skip_context: SkipContext,
pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,

View File

@ -279,6 +279,13 @@ pub(crate) fn contains_skip(attrs: &[Attribute]) -> bool {
#[inline]
pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool {
// Never try to insert semicolons on expressions when we're inside
// a macro definition - this can prevent the macro from compiling
// when used in expression position
if context.is_macro_def {
return false;
}
match expr.kind {
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
context.config.trailing_semicolon()

View File

@ -86,6 +86,7 @@ pub(crate) struct FmtVisitor<'a> {
pub(crate) macro_rewrite_failure: bool,
pub(crate) report: FormatReport,
pub(crate) skip_context: SkipContext,
pub(crate) is_macro_def: bool,
}
impl<'a> Drop for FmtVisitor<'a> {
@ -811,6 +812,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
snippet_provider,
line_number: 0,
skipped_range: Rc::new(RefCell::new(vec![])),
is_macro_def: false,
macro_rewrite_failure: false,
report,
skip_context: Default::default(),
@ -1003,6 +1005,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
force_one_line_chain: Cell::new(false),
snippet_provider: self.snippet_provider,
macro_rewrite_failure: Cell::new(false),
is_macro_def: self.is_macro_def,
report: self.report.clone(),
skip_context: self.skip_context.clone(),
skipped_range: self.skipped_range.clone(),

View File

@ -0,0 +1,22 @@
macro_rules! expr {
(no_semi) => {
return true
};
(semi) => {
return true;
};
}
fn foo() -> bool {
match true {
true => expr!(no_semi),
false if false => {
expr!(semi)
}
false => {
expr!(semi);
}
}
}
fn main() {}