Only have one source of truth for keywords.
`rustc_symbol` is the source of truth for keywords. rustdoc has its own implicit definition of keywords, via the `is_doc_keyword`. It (presumably) intends to include all keywords, but it omits `yeet`. rustfmt has its own explicit list of Rust keywords. It also (presumably) intends to include all keywords, but it omits `await`, `builtin`, `gen`, `macro_rules`, `raw`, `reuse`, `safe`, and `yeet`. Also, it does linear searches through this list, which is inefficient. This commit fixes all of the above problems by introducing a new predicate `is_any_keyword` in rustc and using it in rustdoc and rustfmt. It documents that it's not the right predicate in most cases.
This commit is contained in:
parent
64abe8be33
commit
1564318482
4 changed files with 31 additions and 78 deletions
|
@ -903,7 +903,8 @@ impl Token {
|
||||||
self.is_non_raw_ident_where(|id| id.name == kw)
|
self.is_non_raw_ident_where(|id| id.name == kw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
|
/// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this
|
||||||
|
/// token is an identifier equal to `kw` ignoring the case.
|
||||||
pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
|
pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
|
||||||
self.is_keyword(kw)
|
self.is_keyword(kw)
|
||||||
|| (case == Case::Insensitive
|
|| (case == Case::Insensitive
|
||||||
|
@ -916,6 +917,11 @@ impl Token {
|
||||||
self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
|
self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||||
|
pub fn is_any_keyword(&self) -> bool {
|
||||||
|
self.is_non_raw_ident_where(Ident::is_any_keyword)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true for reserved identifiers used internally for elided lifetimes,
|
/// Returns true for reserved identifiers used internally for elided lifetimes,
|
||||||
/// unnamed method parameters, crate root module, error recovery etc.
|
/// unnamed method parameters, crate root module, error recovery etc.
|
||||||
pub fn is_special_ident(&self) -> bool {
|
pub fn is_special_ident(&self) -> bool {
|
||||||
|
|
|
@ -815,8 +815,8 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Otherwise, check the previous token with all the keywords as possible candidates.
|
// Otherwise, check the previous token with all the keywords as possible candidates.
|
||||||
// This handles code like `Struct Human;` and `While a < b {}`.
|
// This handles code like `Struct Human;` and `While a < b {}`.
|
||||||
// We check the previous token only when the current token is an identifier to avoid false
|
// We check the previous token only when the current token is an identifier to avoid
|
||||||
// positives like suggesting keyword `for` for `extern crate foo {}`.
|
// false positives like suggesting keyword `for` for `extern crate foo {}`.
|
||||||
if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
|
if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
|
||||||
err.subdiagnostic(misspelled_kw);
|
err.subdiagnostic(misspelled_kw);
|
||||||
// We don't want other suggestions to be added as they are most likely meaningless
|
// We don't want other suggestions to be added as they are most likely meaningless
|
||||||
|
|
|
@ -2589,6 +2589,11 @@ pub mod sym {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
|
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||||
|
pub fn is_any_keyword(self) -> bool {
|
||||||
|
self >= kw::As && self <= kw::Yeet
|
||||||
|
}
|
||||||
|
|
||||||
fn is_special(self) -> bool {
|
fn is_special(self) -> bool {
|
||||||
self <= kw::Underscore
|
self <= kw::Underscore
|
||||||
}
|
}
|
||||||
|
@ -2645,6 +2650,11 @@ impl Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ident {
|
impl Ident {
|
||||||
|
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||||
|
pub fn is_any_keyword(self) -> bool {
|
||||||
|
self.name.is_any_keyword()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` for reserved identifiers used internally for elided lifetimes,
|
/// Returns `true` for reserved identifiers used internally for elided lifetimes,
|
||||||
/// unnamed method parameters, crate root module, error recovery etc.
|
/// unnamed method parameters, crate root module, error recovery etc.
|
||||||
pub fn is_special(self) -> bool {
|
pub fn is_special(self) -> bool {
|
||||||
|
|
|
@ -4,8 +4,7 @@ use rustc_ast::{ast, ptr};
|
||||||
use rustc_parse::MACRO_ARGUMENTS;
|
use rustc_parse::MACRO_ARGUMENTS;
|
||||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::symbol;
|
||||||
use rustc_span::symbol::{self, kw};
|
|
||||||
|
|
||||||
use crate::macros::MacroArg;
|
use crate::macros::MacroArg;
|
||||||
use crate::rewrite::RewriteContext;
|
use crate::rewrite::RewriteContext;
|
||||||
|
@ -82,18 +81,18 @@ pub(crate) struct ParsedMacroArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
||||||
for &keyword in RUST_KW.iter() {
|
if parser.token.is_any_keyword()
|
||||||
if parser.token.is_keyword(keyword)
|
&& parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
|
||||||
&& parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
|
{
|
||||||
{
|
let keyword = parser.token.ident().unwrap().0.name;
|
||||||
parser.bump();
|
parser.bump();
|
||||||
return Some(MacroArg::Keyword(
|
Some(MacroArg::Keyword(
|
||||||
symbol::Ident::with_dummy_span(keyword),
|
symbol::Ident::with_dummy_span(keyword),
|
||||||
parser.prev_token.span,
|
parser.prev_token.span,
|
||||||
));
|
))
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_macro_args(
|
pub(crate) fn parse_macro_args(
|
||||||
|
@ -169,65 +168,3 @@ pub(crate) fn parse_expr(
|
||||||
let mut parser = build_parser(context, tokens);
|
let mut parser = build_parser(context, tokens);
|
||||||
parser.parse_expr().ok()
|
parser.parse_expr().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
const RUST_KW: [Symbol; 59] = [
|
|
||||||
kw::PathRoot,
|
|
||||||
kw::DollarCrate,
|
|
||||||
kw::Underscore,
|
|
||||||
kw::As,
|
|
||||||
kw::Box,
|
|
||||||
kw::Break,
|
|
||||||
kw::Const,
|
|
||||||
kw::Continue,
|
|
||||||
kw::Crate,
|
|
||||||
kw::Else,
|
|
||||||
kw::Enum,
|
|
||||||
kw::Extern,
|
|
||||||
kw::False,
|
|
||||||
kw::Fn,
|
|
||||||
kw::For,
|
|
||||||
kw::If,
|
|
||||||
kw::Impl,
|
|
||||||
kw::In,
|
|
||||||
kw::Let,
|
|
||||||
kw::Loop,
|
|
||||||
kw::Match,
|
|
||||||
kw::Mod,
|
|
||||||
kw::Move,
|
|
||||||
kw::Mut,
|
|
||||||
kw::Pub,
|
|
||||||
kw::Ref,
|
|
||||||
kw::Return,
|
|
||||||
kw::SelfLower,
|
|
||||||
kw::SelfUpper,
|
|
||||||
kw::Static,
|
|
||||||
kw::Struct,
|
|
||||||
kw::Super,
|
|
||||||
kw::Trait,
|
|
||||||
kw::True,
|
|
||||||
kw::Type,
|
|
||||||
kw::Unsafe,
|
|
||||||
kw::Use,
|
|
||||||
kw::Where,
|
|
||||||
kw::While,
|
|
||||||
kw::Abstract,
|
|
||||||
kw::Become,
|
|
||||||
kw::Do,
|
|
||||||
kw::Final,
|
|
||||||
kw::Macro,
|
|
||||||
kw::Override,
|
|
||||||
kw::Priv,
|
|
||||||
kw::Typeof,
|
|
||||||
kw::Unsized,
|
|
||||||
kw::Virtual,
|
|
||||||
kw::Yield,
|
|
||||||
kw::Dyn,
|
|
||||||
kw::Async,
|
|
||||||
kw::Try,
|
|
||||||
kw::UnderscoreLifetime,
|
|
||||||
kw::StaticLifetime,
|
|
||||||
kw::Auto,
|
|
||||||
kw::Catch,
|
|
||||||
kw::Default,
|
|
||||||
kw::Union,
|
|
||||||
];
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue