Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest quoting unquoted idents in attrs #119341

Merged
merged 1 commit into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator

parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`

parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}`
.suggestion = surround the identifier with quotation marks to parse it as a string

parse_invalid_offset_of = offset_of expects dot-separated field and variant names

parse_invalid_unicode_escape = invalid unicode character escape
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,25 @@ pub(crate) struct InvalidMetaItem {
pub token: Token,
}

#[derive(Diagnostic)]
#[diag(parse_invalid_meta_item_unquoted_ident)]
pub(crate) struct InvalidMetaItemUnquotedIdent {
#[primary_span]
pub span: Span,
pub token: Token,
#[subdiagnostic]
pub sugg: InvalidMetaItemSuggQuoteIdent,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
pub(crate) struct InvalidMetaItemSuggQuoteIdent {
#[suggestion_part(code = "\"")]
pub before: Span,
#[suggestion_part(code = "\"")]
pub after: Span,
}

#[derive(Subdiagnostic)]
#[suggestion(
parse_sugg_escape_identifier,
Expand Down
28 changes: 24 additions & 4 deletions compiler/rustc_parse/src/parser/attr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
use crate::errors::{
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
SuffixedLiteralInAttribute,
};
use crate::fluent_generated as fluent;

use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
Expand Down Expand Up @@ -417,9 +420,26 @@ impl<'a> Parser<'a> {
Err(err) => err.cancel(),
}

Err(self
.dcx()
.create_err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }))
let token = self.token.clone();

// Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)]
// `from_expansion()` ensures we don't suggest for cases such as
// `#[cfg(feature = $expr)]` in macros
if self.prev_token == token::Eq && !self.token.span.from_expansion() {
let before = self.token.span.shrink_to_lo();
while matches!(self.token.kind, token::Ident(..)) {
self.bump();
}
let after = self.prev_token.span.shrink_to_hi();
let sugg = InvalidMetaItemSuggQuoteIdent { before, after };
return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent {
span: token.span,
token,
sugg,
}));
}

Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token }))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ fn main() {
}

#[deprecated(note = test)]
//~^ ERROR expected unsuffixed literal or identifier, found `test`
//~^ ERROR expected unsuffixed literal, found `test`
fn foo() {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error: expected unsuffixed literal or identifier, found `test`
error: expected unsuffixed literal, found `test`
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
|
LL | #[deprecated(note = test)]
| ^^^^
|
help: surround the identifier with quotation marks to parse it as a string
|
LL | #[deprecated(note = "test")]
| + +

error: aborting due to 1 previous error

15 changes: 15 additions & 0 deletions tests/ui/parser/attribute/attr-unquoted-ident.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// compile-flags: -Zdeduplicate-diagnostics=yes
// run-rustfix

fn main() {
#[cfg(key="foo")]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
#[cfg(key="bar")]
println!();
#[cfg(key="foo bar baz")]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
}
15 changes: 15 additions & 0 deletions tests/ui/parser/attribute/attr-unquoted-ident.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// compile-flags: -Zdeduplicate-diagnostics=yes
// run-rustfix

fn main() {
#[cfg(key=foo)]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
#[cfg(key="bar")]
println!();
#[cfg(key=foo bar baz)]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
}
24 changes: 24 additions & 0 deletions tests/ui/parser/attribute/attr-unquoted-ident.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: expected unsuffixed literal, found `foo`
--> $DIR/attr-unquoted-ident.rs:5:15
|
LL | #[cfg(key=foo)]
| ^^^
|
help: surround the identifier with quotation marks to parse it as a string
|
LL | #[cfg(key="foo")]
| + +

error: expected unsuffixed literal, found `foo`
--> $DIR/attr-unquoted-ident.rs:11:15
|
LL | #[cfg(key=foo bar baz)]
| ^^^
|
help: surround the identifier with quotation marks to parse it as a string
|
LL | #[cfg(key="foo bar baz")]
| + +

error: aborting due to 2 previous errors

Loading