Migrate "expected identifier" diagnostics to diagnostic structs

This commit is contained in:
Xiretza 2022-09-04 10:14:00 +02:00
parent 21b5194a3a
commit 7507ee29fc
4 changed files with 170 additions and 43 deletions

View File

@ -290,3 +290,19 @@ parser_inner_doc_comment_not_permitted = expected outer doc comment
.suggestion = you might have meant to write a regular comment .suggestion = you might have meant to write a regular comment
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item} .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
parser_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token_str}`
parser_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token_str}`
parser_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token_str}`
parser_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token_str}`
parser_expected_identifier_found_str = expected identifier, found `{$token_str}`
parser_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
parser_expected_identifier_found_keyword = expected identifier, found keyword
parser_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
parser_expected_identifier_found_doc_comment = expected identifier, found doc comment
parser_expected_identifier = expected identifier
parser_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier
parser_sugg_remove_comma = remove this comma

View File

@ -1,9 +1,11 @@
use rustc_errors::Applicability; use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
use crate::parser::{TokenDescription, TokenDescriptionKind};
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parser::maybe_report_ambiguous_plus)] #[diag(parser::maybe_report_ambiguous_plus)]
pub(crate) struct AmbiguousPlus { pub(crate) struct AmbiguousPlus {
@ -870,3 +872,94 @@ pub(crate) struct InvalidMetaItem {
pub span: Span, pub span: Span,
pub token: String, pub token: String,
} }
#[derive(Subdiagnostic)]
#[suggestion_verbose(
parser::sugg_escape_to_use_as_identifier,
applicability = "maybe-incorrect",
code = "r#"
)]
pub(crate) struct SuggEscapeToUseAsIdentifier {
#[primary_span]
pub span: Span,
pub ident_name: String,
}
#[derive(Subdiagnostic)]
#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")]
pub(crate) struct SuggRemoveComma {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
pub(crate) enum ExpectedIdentifierFound {
#[label(parser::expected_identifier_found_reserved_identifier)]
ReservedIdentifier(#[primary_span] Span),
#[label(parser::expected_identifier_found_keyword)]
Keyword(#[primary_span] Span),
#[label(parser::expected_identifier_found_reserved_keyword)]
ReservedKeyword(#[primary_span] Span),
#[label(parser::expected_identifier_found_doc_comment)]
DocComment(#[primary_span] Span),
#[label(parser::expected_identifier)]
Other(#[primary_span] Span),
}
impl ExpectedIdentifierFound {
pub fn new(token_descr_kind: Option<TokenDescriptionKind>, span: Span) -> Self {
(match token_descr_kind {
Some(TokenDescriptionKind::ReservedIdentifier) => {
ExpectedIdentifierFound::ReservedIdentifier
}
Some(TokenDescriptionKind::Keyword) => ExpectedIdentifierFound::Keyword,
Some(TokenDescriptionKind::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
Some(TokenDescriptionKind::DocComment) => ExpectedIdentifierFound::DocComment,
None => ExpectedIdentifierFound::Other,
})(span)
}
}
pub(crate) struct ExpectedIdentifier {
pub span: Span,
pub token_descr: TokenDescription,
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
pub suggest_remove_comma: Option<SuggRemoveComma>,
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, G> {
let mut diag = handler.struct_diagnostic(match self.token_descr.kind {
Some(TokenDescriptionKind::ReservedIdentifier) => {
fluent::parser::expected_identifier_found_reserved_identifier_str
}
Some(TokenDescriptionKind::Keyword) => {
fluent::parser::expected_identifier_found_keyword_str
}
Some(TokenDescriptionKind::ReservedKeyword) => {
fluent::parser::expected_identifier_found_reserved_keyword_str
}
Some(TokenDescriptionKind::DocComment) => {
fluent::parser::expected_identifier_found_doc_comment_str
}
None => fluent::parser::expected_identifier_found_str,
});
diag.set_span(self.span);
diag.set_arg("token_str", self.token_descr.name);
if let Some(sugg) = self.suggest_raw {
sugg.add_to_diagnostic(&mut diag);
}
ExpectedIdentifierFound::new(self.token_descr.kind, self.span).add_to_diagnostic(&mut diag);
if let Some(sugg) = self.suggest_remove_comma {
sugg.add_to_diagnostic(&mut diag);
}
diag
}
}

View File

@ -4,8 +4,9 @@ use super::{
TokenExpectType, TokenType, TokenExpectType, TokenType,
}; };
use crate::errors::{ use crate::errors::{
AmbiguousPlus, BadQPathStage2, BadTypePlus, BadTypePlusSub, InInTypo, IncorrectAwait, AmbiguousPlus, BadQPathStage2, BadTypePlus, BadTypePlusSub, ExpectedIdentifier, InInTypo,
IncorrectSemicolon, IncorrectUseOfAwait, UseEqInstead, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, SuggEscapeToUseAsIdentifier,
SuggRemoveComma, UseEqInstead,
}; };
use crate::lexer::UnmatchedBrace; use crate::lexer::UnmatchedBrace;
@ -23,7 +24,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{ use rustc_errors::{
fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
}; };
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@ -285,10 +286,6 @@ impl<'a> Parser<'a> {
} }
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = self.struct_span_err(
self.token.span,
&format!("expected identifier, found {}", super::token_descr(&self.token)),
);
let valid_follow = &[ let valid_follow = &[
TokenKind::Eq, TokenKind::Eq,
TokenKind::Colon, TokenKind::Colon,
@ -300,34 +297,33 @@ impl<'a> Parser<'a> {
TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Brace),
TokenKind::CloseDelim(Delimiter::Parenthesis), TokenKind::CloseDelim(Delimiter::Parenthesis),
]; ];
match self.token.ident() { let suggest_raw = match self.token.ident() {
Some((ident, false)) Some((ident, false))
if ident.is_raw_guess() if ident.is_raw_guess()
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
{ {
err.span_suggestion_verbose( Some(SuggEscapeToUseAsIdentifier {
ident.span.shrink_to_lo(), span: ident.span.shrink_to_lo(),
&format!("escape `{}` to use it as an identifier", ident.name), ident_name: ident.name.to_string(),
"r#", })
Applicability::MaybeIncorrect,
);
} }
_ => {} _ => None,
} };
if let Some(token_descr) = super::token_descr_opt(&self.token) {
err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); let suggest_remove_comma =
} else {
err.span_label(self.token.span, "expected identifier");
if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
err.span_suggestion( Some(SuggRemoveComma { span: self.token.span })
self.token.span, } else {
"remove this comma", None
"", };
Applicability::MachineApplicable,
); let err = ExpectedIdentifier {
} span: self.token.span,
} token_descr: super::token_descr_struct(&self.token),
err suggest_raw,
suggest_remove_comma,
};
err.into_diagnostic(&self.sess.span_diagnostic)
} }
pub(super) fn expected_one_of_not_found( pub(super) fn expected_one_of_not_found(

View File

@ -410,22 +410,44 @@ pub enum FollowedByType {
No, No,
} }
fn token_descr_opt(token: &Token) -> Option<&'static str> { #[derive(Clone, Copy, PartialEq, Eq)]
Some(match token.kind { pub enum TokenDescriptionKind {
_ if token.is_special_ident() => "reserved identifier", ReservedIdentifier,
_ if token.is_used_keyword() => "keyword", Keyword,
_ if token.is_unused_keyword() => "reserved keyword", ReservedKeyword,
token::DocComment(..) => "doc comment", DocComment,
_ => return None, }
})
#[derive(Clone, PartialEq, Eq)]
pub struct TokenDescription {
pub kind: Option<TokenDescriptionKind>,
pub name: String,
}
pub(super) fn token_descr_struct(token: &Token) -> TokenDescription {
let kind = match token.kind {
_ if token.is_special_ident() => Some(TokenDescriptionKind::ReservedIdentifier),
_ if token.is_used_keyword() => Some(TokenDescriptionKind::Keyword),
_ if token.is_unused_keyword() => Some(TokenDescriptionKind::ReservedKeyword),
token::DocComment(..) => Some(TokenDescriptionKind::DocComment),
_ => None,
};
let name = pprust::token_to_string(token).to_string();
TokenDescription { kind, name }
} }
pub(super) fn token_descr(token: &Token) -> String { pub(super) fn token_descr(token: &Token) -> String {
let token_str = pprust::token_to_string(token); let TokenDescription { kind, name } = token_descr_struct(token);
match token_descr_opt(token) {
Some(prefix) => format!("{} `{}`", prefix, token_str), let kind = kind.map(|kind| match kind {
_ => format!("`{}`", token_str), TokenDescriptionKind::ReservedIdentifier => "reserved identifier",
} TokenDescriptionKind::Keyword => "keyword",
TokenDescriptionKind::ReservedKeyword => "reserved keyword",
TokenDescriptionKind::DocComment => "doc comment",
});
if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) }
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {