feat: don't insert semi in macro_rules arm body
This commit is contained in:
parent
eb894d5370
commit
a613c57521
@ -659,7 +659,7 @@ impl<'a> CommentRewrite<'a> {
|
|||||||
config.set().wrap_comments(false);
|
config.set().wrap_comments(false);
|
||||||
if config.format_code_in_doc_comments() {
|
if config.format_code_in_doc_comments() {
|
||||||
if let Some(s) =
|
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)
|
trim_custom_comment_prefix(&s.snippet)
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,7 +25,11 @@ pub(crate) type SourceFile = Vec<FileRecord>;
|
|||||||
pub(crate) type FileRecord = (FileName, String);
|
pub(crate) type FileRecord = (FileName, String);
|
||||||
|
|
||||||
impl<'b, T: Write + 'b> Session<'b, T> {
|
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() {
|
if !self.config.version_meets_requirement() {
|
||||||
return Err(ErrorKind::VersionMismatch);
|
return Err(ErrorKind::VersionMismatch);
|
||||||
}
|
}
|
||||||
@ -42,7 +46,7 @@ impl<'b, T: Write + 'b> Session<'b, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let config = &self.config.clone();
|
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| {
|
format_result.map(|report| {
|
||||||
self.errors.add(&report.internal.borrow().1);
|
self.errors.add(&report.internal.borrow().1);
|
||||||
@ -57,6 +61,7 @@ fn format_project<T: FormatHandler>(
|
|||||||
input: Input,
|
input: Input,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
handler: &mut T,
|
handler: &mut T,
|
||||||
|
is_macro_def: bool,
|
||||||
) -> Result<FormatReport, ErrorKind> {
|
) -> Result<FormatReport, ErrorKind> {
|
||||||
let mut timer = Timer::start();
|
let mut timer = Timer::start();
|
||||||
|
|
||||||
@ -103,7 +108,7 @@ fn format_project<T: FormatHandler>(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path));
|
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();
|
timer = timer.done_formatting();
|
||||||
|
|
||||||
@ -134,7 +139,12 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Formats a single file/module.
|
// 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 snippet_provider = self.parse_session.snippet_provider(module.as_ref().inner);
|
||||||
let mut visitor = FmtVisitor::from_parse_sess(
|
let mut visitor = FmtVisitor::from_parse_sess(
|
||||||
&self.parse_session,
|
&self.parse_session,
|
||||||
@ -143,7 +153,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
|
|||||||
self.report.clone(),
|
self.report.clone(),
|
||||||
);
|
);
|
||||||
visitor.skip_context.update_with_attrs(&self.krate.attrs);
|
visitor.skip_context.update_with_attrs(&self.krate.attrs);
|
||||||
|
visitor.is_macro_def = is_macro_def;
|
||||||
visitor.last_pos = snippet_provider.start_pos();
|
visitor.last_pos = snippet_provider.start_pos();
|
||||||
visitor.skip_empty_lines(snippet_provider.end_pos());
|
visitor.skip_empty_lines(snippet_provider.end_pos());
|
||||||
visitor.format_separate_mod(module, snippet_provider.end_pos());
|
visitor.format_separate_mod(module, snippet_provider.end_pos());
|
||||||
|
24
src/lib.rs
24
src/lib.rs
@ -286,7 +286,7 @@ impl fmt::Display for FormatReport {
|
|||||||
|
|
||||||
/// Format the given snippet. The snippet is expected to be *complete* code.
|
/// Format the given snippet. The snippet is expected to be *complete* code.
|
||||||
/// When we cannot parse the given snippet, this function returns `None`.
|
/// 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();
|
let mut config = config.clone();
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
|
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 (formatting_error, result) = {
|
||||||
let input = Input::Text(snippet.into());
|
let input = Input::Text(snippet.into());
|
||||||
let mut session = Session::new(config, Some(&mut out));
|
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.errors.has_macro_format_failure
|
||||||
|| session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
|
|| 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).
|
/// 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.
|
/// To avoid panic in parser, we wrap the code block with a dummy function.
|
||||||
/// The returned code block does **not** end with newline.
|
/// 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";
|
const FN_MAIN_PREFIX: &str = "fn main() {\n";
|
||||||
|
|
||||||
fn enclose_in_main_block(s: &str, config: &Config) -> String {
|
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
|
config_with_unix_newline
|
||||||
.set()
|
.set()
|
||||||
.newline_style(NewlineStyle::Unix);
|
.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
|
// Remove wrapping main block
|
||||||
formatted.unwrap_code_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
|
/// The main entry point for Rustfmt. Formats the given input according to the
|
||||||
/// given config. `out` is only necessary if required by the configuration.
|
/// given config. `out` is only necessary if required by the configuration.
|
||||||
pub fn format(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
|
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
|
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
|
// `format_snippet()` and `format_code_block()` should not panic
|
||||||
// even when we cannot parse the given snippet.
|
// even when we cannot parse the given snippet.
|
||||||
let snippet = "let";
|
let snippet = "let";
|
||||||
assert!(format_snippet(snippet, &Config::default()).is_none());
|
assert!(format_snippet(snippet, &Config::default(), false).is_none());
|
||||||
assert!(format_code_block(snippet, &Config::default()).is_none());
|
assert!(format_code_block(snippet, &Config::default(), false).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
|
fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
|
||||||
where
|
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
|
output.is_some() && output.unwrap().snippet == expected
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +584,7 @@ mod unit_tests {
|
|||||||
fn test_format_code_block_fail() {
|
fn test_format_code_block_fail() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
|
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]
|
#[test]
|
||||||
|
@ -1363,12 +1363,12 @@ impl MacroBranch {
|
|||||||
config.set().max_width(new_width);
|
config.set().max_width(new_width);
|
||||||
|
|
||||||
// First try to format as items, then as statements.
|
// 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,
|
Some(new_body) => new_body,
|
||||||
None => {
|
None => {
|
||||||
let new_width = new_width + config.tab_spaces();
|
let new_width = new_width + config.tab_spaces();
|
||||||
config.set().max_width(new_width);
|
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,
|
Some(new_body) => new_body,
|
||||||
None => return None,
|
None => return None,
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ pub(crate) struct RewriteContext<'a> {
|
|||||||
pub(crate) snippet_provider: &'a SnippetProvider,
|
pub(crate) snippet_provider: &'a SnippetProvider,
|
||||||
// Used for `format_snippet`
|
// Used for `format_snippet`
|
||||||
pub(crate) macro_rewrite_failure: Cell<bool>,
|
pub(crate) macro_rewrite_failure: Cell<bool>,
|
||||||
|
pub(crate) is_macro_def: bool,
|
||||||
pub(crate) report: FormatReport,
|
pub(crate) report: FormatReport,
|
||||||
pub(crate) skip_context: SkipContext,
|
pub(crate) skip_context: SkipContext,
|
||||||
pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,
|
pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,
|
||||||
|
@ -279,6 +279,13 @@ pub(crate) fn contains_skip(attrs: &[Attribute]) -> bool {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool {
|
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 {
|
match expr.kind {
|
||||||
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
|
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
|
||||||
context.config.trailing_semicolon()
|
context.config.trailing_semicolon()
|
||||||
|
@ -86,6 +86,7 @@ pub(crate) struct FmtVisitor<'a> {
|
|||||||
pub(crate) macro_rewrite_failure: bool,
|
pub(crate) macro_rewrite_failure: bool,
|
||||||
pub(crate) report: FormatReport,
|
pub(crate) report: FormatReport,
|
||||||
pub(crate) skip_context: SkipContext,
|
pub(crate) skip_context: SkipContext,
|
||||||
|
pub(crate) is_macro_def: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for FmtVisitor<'a> {
|
impl<'a> Drop for FmtVisitor<'a> {
|
||||||
@ -811,6 +812,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||||||
snippet_provider,
|
snippet_provider,
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
skipped_range: Rc::new(RefCell::new(vec![])),
|
skipped_range: Rc::new(RefCell::new(vec![])),
|
||||||
|
is_macro_def: false,
|
||||||
macro_rewrite_failure: false,
|
macro_rewrite_failure: false,
|
||||||
report,
|
report,
|
||||||
skip_context: Default::default(),
|
skip_context: Default::default(),
|
||||||
@ -1003,6 +1005,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||||||
force_one_line_chain: Cell::new(false),
|
force_one_line_chain: Cell::new(false),
|
||||||
snippet_provider: self.snippet_provider,
|
snippet_provider: self.snippet_provider,
|
||||||
macro_rewrite_failure: Cell::new(false),
|
macro_rewrite_failure: Cell::new(false),
|
||||||
|
is_macro_def: self.is_macro_def,
|
||||||
report: self.report.clone(),
|
report: self.report.clone(),
|
||||||
skip_context: self.skip_context.clone(),
|
skip_context: self.skip_context.clone(),
|
||||||
skipped_range: self.skipped_range.clone(),
|
skipped_range: self.skipped_range.clone(),
|
||||||
|
22
tests/target/macro_rules_semi.rs
Normal file
22
tests/target/macro_rules_semi.rs
Normal 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() {}
|
Loading…
x
Reference in New Issue
Block a user