Improve code suggestion for incorrect macro_rules! usage
This commit is contained in:
parent
605f49b274
commit
caf7cdf558
6 changed files with 89 additions and 27 deletions
|
|
@ -534,7 +534,7 @@ impl<'a> Parser<'a> {
|
|||
match self.parse_delim_args() {
|
||||
// `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
|
||||
Ok(args) => {
|
||||
self.eat_semi_for_macro_if_needed(&args);
|
||||
self.eat_semi_for_macro_if_needed(&args, Some(&path));
|
||||
self.complain_if_pub_macro(vis, false);
|
||||
Ok(MacCall { path, args })
|
||||
}
|
||||
|
|
@ -2392,7 +2392,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let body = self.parse_delim_args()?;
|
||||
self.eat_semi_for_macro_if_needed(&body);
|
||||
self.eat_semi_for_macro_if_needed(&body, None);
|
||||
self.complain_if_pub_macro(vis, true);
|
||||
|
||||
Ok(ItemKind::MacroDef(
|
||||
|
|
@ -2417,13 +2417,13 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eat_semi_for_macro_if_needed(&mut self, args: &DelimArgs) {
|
||||
fn eat_semi_for_macro_if_needed(&mut self, args: &DelimArgs, path: Option<&Path>) {
|
||||
if args.need_semicolon() && !self.eat(exp!(Semi)) {
|
||||
self.report_invalid_macro_expansion_item(args);
|
||||
self.report_invalid_macro_expansion_item(args, path);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_invalid_macro_expansion_item(&self, args: &DelimArgs) {
|
||||
fn report_invalid_macro_expansion_item(&self, args: &DelimArgs, path: Option<&Path>) {
|
||||
let span = args.dspan.entire();
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
|
|
@ -2433,17 +2433,32 @@ impl<'a> Parser<'a> {
|
|||
// macros within the same crate (that we can fix), which is sad.
|
||||
if !span.from_expansion() {
|
||||
let DelimSpan { open, close } = args.dspan;
|
||||
err.multipart_suggestion(
|
||||
"change the delimiters to curly braces",
|
||||
vec![(open, "{".to_string()), (close, '}'.to_string())],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_suggestion(
|
||||
span.with_neighbor(self.token.span).shrink_to_hi(),
|
||||
"add a semicolon",
|
||||
';',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
// Check if this looks like `macro_rules!(name) { ... }`
|
||||
// a common mistake when trying to define a macro.
|
||||
if let Some(path) = path
|
||||
&& path.segments.first().is_some_and(|seg| seg.ident.name == sym::macro_rules)
|
||||
&& args.delim == Delimiter::Parenthesis
|
||||
{
|
||||
let replace =
|
||||
if path.span.hi() + rustc_span::BytePos(1) < open.lo() { "" } else { " " };
|
||||
err.multipart_suggestion(
|
||||
"to define a macro, remove the parentheses around the macro name",
|
||||
vec![(open, replace.to_string()), (close, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.multipart_suggestion(
|
||||
"change the delimiters to curly braces",
|
||||
vec![(open, "{".to_string()), (close, '}'.to_string())],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_suggestion(
|
||||
span.with_neighbor(self.token.span).shrink_to_hi(),
|
||||
"add a semicolon",
|
||||
';',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
|
|
|||
20
tests/ui/macros/issue-118786.fixed
Normal file
20
tests/ui/macros/issue-118786.fixed
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#![allow(unused_macros)]
|
||||
//@ compile-flags: --crate-type lib
|
||||
//@ dont-require-annotations: NOTE
|
||||
//@ run-rustfix
|
||||
|
||||
// Regression test for issue 118786
|
||||
|
||||
macro_rules! make_macro {
|
||||
($macro_name:tt) => {
|
||||
macro_rules! $macro_name {
|
||||
//~^ ERROR macro expansion ignores `{` and any tokens following
|
||||
//~| ERROR cannot find macro `macro_rules` in this scope
|
||||
//~| NOTE put a macro name here
|
||||
() => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_macro!(meow);
|
||||
//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
//@ compile-flags: --crate-type lib -O -C debug-assertions=yes
|
||||
#![allow(unused_macros)]
|
||||
//@ compile-flags: --crate-type lib
|
||||
//@ dont-require-annotations: NOTE
|
||||
//@ run-rustfix
|
||||
|
||||
// Regression test for issue 118786
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
error: macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
--> $DIR/issue-118786.rs:17:13
|
||||
--> $DIR/issue-118786.rs:19:13
|
||||
|
|
||||
LL | make_macro!((meow));
|
||||
| ^^^^^^
|
||||
|
|
||||
help: change the delimiters to curly braces
|
||||
help: to define a macro, remove the parentheses around the macro name
|
||||
|
|
||||
LL - make_macro!((meow));
|
||||
LL + make_macro!({meow});
|
||||
LL + make_macro!(meow);
|
||||
|
|
||||
help: add a semicolon
|
||||
|
|
||||
LL | macro_rules! $macro_name; {
|
||||
| +
|
||||
|
||||
error: macro expansion ignores `{` and any tokens following
|
||||
--> $DIR/issue-118786.rs:8:34
|
||||
--> $DIR/issue-118786.rs:10:34
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^
|
||||
|
|
@ -26,7 +22,7 @@ LL | make_macro!((meow));
|
|||
= note: the usage of `make_macro!` is likely invalid in item context
|
||||
|
||||
error: cannot find macro `macro_rules` in this scope
|
||||
--> $DIR/issue-118786.rs:8:9
|
||||
--> $DIR/issue-118786.rs:10:9
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
@ -35,7 +31,7 @@ LL | make_macro!((meow));
|
|||
| ------------------- in this macro invocation
|
||||
|
|
||||
note: maybe you have forgotten to define a name for this `macro_rules!`
|
||||
--> $DIR/issue-118786.rs:8:20
|
||||
--> $DIR/issue-118786.rs:10:20
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^ put a macro name here
|
||||
|
|
|
|||
7
tests/ui/parser/macro-rules-paren-name-issue-150899.rs
Normal file
7
tests/ui/parser/macro-rules-paren-name-issue-150899.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
macro_rules!(i_think_the_name_should_go_here) {
|
||||
//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
//~| ERROR expected item, found `{`
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
22
tests/ui/parser/macro-rules-paren-name-issue-150899.stderr
Normal file
22
tests/ui/parser/macro-rules-paren-name-issue-150899.stderr
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
error: macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
--> $DIR/macro-rules-paren-name-issue-150899.rs:1:13
|
||||
|
|
||||
LL | macro_rules!(i_think_the_name_should_go_here) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to define a macro, remove the parentheses around the macro name
|
||||
|
|
||||
LL - macro_rules!(i_think_the_name_should_go_here) {
|
||||
LL + macro_rules! i_think_the_name_should_go_here {
|
||||
|
|
||||
|
||||
error: expected item, found `{`
|
||||
--> $DIR/macro-rules-paren-name-issue-150899.rs:1:47
|
||||
|
|
||||
LL | macro_rules!(i_think_the_name_should_go_here) {
|
||||
| ^ expected item
|
||||
|
|
||||
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue