Skip to content

Commit a5f0713

Browse files
committed
rustdoc: Recognize more weak keywords when highlighting Rust code
1 parent 1f23b48 commit a5f0713

File tree

1 file changed

+45
-33
lines changed

1 file changed

+45
-33
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class>
764764
Some(match text {
765765
"ref" | "mut" => Class::RefKeyWord,
766766
"false" | "true" => Class::Bool,
767-
_ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
767+
// FIXME(#148221): Don't hard-code the edition. The classifier should take it as an argument.
768+
_ if Symbol::intern(text).is_reserved(|| Edition::Edition2024) => Class::KeyWord,
768769
_ => return None,
769770
})
770771
}
@@ -1201,34 +1202,30 @@ impl<'src> Classifier<'src> {
12011202
},
12021203
TokenKind::GuardedStrPrefix => return no_highlight(sink),
12031204
TokenKind::Ident | TokenKind::RawIdent
1204-
if self.peek_non_whitespace() == Some(TokenKind::Bang) =>
1205+
if let Some((TokenKind::Bang, _)) = self.peek_non_trivia() =>
12051206
{
12061207
self.in_macro = true;
12071208
let span = new_span(before, text, file_span);
12081209
sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) });
12091210
sink(span, Highlight::Token { text, class: None });
12101211
return;
12111212
}
1212-
TokenKind::Ident => {
1213-
match get_real_ident_class(text, false) {
1214-
None => match text {
1215-
"Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)),
1216-
"Some" | "None" | "Ok" | "Err" => {
1217-
Class::PreludeVal(new_span(before, text, file_span))
1218-
}
1219-
// "union" is a weak keyword and is only considered as a keyword when declaring
1220-
// a union type.
1221-
"union" if self.check_if_is_union_keyword() => Class::KeyWord,
1222-
_ if self.in_macro_nonterminal => {
1223-
self.in_macro_nonterminal = false;
1224-
Class::MacroNonTerminal
1225-
}
1226-
"self" | "Self" => Class::Self_(new_span(before, text, file_span)),
1227-
_ => Class::Ident(new_span(before, text, file_span)),
1228-
},
1229-
Some(c) => c,
1230-
}
1231-
}
1213+
TokenKind::Ident => match get_real_ident_class(text, false) {
1214+
None => match text {
1215+
"Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)),
1216+
"Some" | "None" | "Ok" | "Err" => {
1217+
Class::PreludeVal(new_span(before, text, file_span))
1218+
}
1219+
_ if self.is_weak_keyword(text) => Class::KeyWord,
1220+
_ if self.in_macro_nonterminal => {
1221+
self.in_macro_nonterminal = false;
1222+
Class::MacroNonTerminal
1223+
}
1224+
"self" | "Self" => Class::Self_(new_span(before, text, file_span)),
1225+
_ => Class::Ident(new_span(before, text, file_span)),
1226+
},
1227+
Some(c) => c,
1228+
},
12321229
TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
12331230
Class::Ident(new_span(before, text, file_span))
12341231
}
@@ -1249,25 +1246,40 @@ impl<'src> Classifier<'src> {
12491246
}
12501247
}
12511248

1249+
fn is_weak_keyword(&mut self, text: &str) -> bool {
1250+
// NOTE: `yeet` (`do yeet $expr`), `catch` (`do catch $block`), `default` (specialization),
1251+
// `contract_{ensures,requires}`, `builtin` (builtin_syntax) & `reuse` (fn_delegation) are
1252+
// too difficult or annoying to properly detect under this simple scheme.
1253+
1254+
let matches = match text {
1255+
"auto" => |text| text == "trait", // `auto trait Trait {}` (`auto_traits`)
1256+
"pin" => |text| text == "const" || text == "mut", // `&pin mut Type` (`pin_ergonomics`)
1257+
"raw" => |text| text == "const" || text == "mut", // `&raw const local`
1258+
"safe" => |text| text == "fn" || text == "extern", // `unsafe extern { safe fn f(); }`
1259+
"union" => |_| true, // `union Untagged { field: () }`
1260+
_ => return false,
1261+
};
1262+
matches!(self.peek_non_trivia(), Some((TokenKind::Ident, text)) if matches(text))
1263+
}
1264+
12521265
fn peek(&mut self) -> Option<TokenKind> {
1253-
self.tokens.peek().map(|(token_kind, _text)| *token_kind)
1266+
self.tokens.peek().map(|&(kind, _)| kind)
12541267
}
12551268

1256-
fn peek_non_whitespace(&mut self) -> Option<TokenKind> {
1257-
while let Some((token_kind, _)) = self.tokens.peek_next() {
1258-
if *token_kind != TokenKind::Whitespace {
1259-
let token_kind = *token_kind;
1260-
self.tokens.stop_peeking();
1261-
return Some(token_kind);
1269+
fn peek_non_trivia(&mut self) -> Option<(TokenKind, &str)> {
1270+
while let Some(&token @ (kind, _)) = self.tokens.peek_next() {
1271+
if let TokenKind::Whitespace
1272+
| TokenKind::LineComment { doc_style: None }
1273+
| TokenKind::BlockComment { doc_style: None, .. } = kind
1274+
{
1275+
continue;
12621276
}
1277+
self.tokens.stop_peeking();
1278+
return Some(token);
12631279
}
12641280
self.tokens.stop_peeking();
12651281
None
12661282
}
1267-
1268-
fn check_if_is_union_keyword(&mut self) -> bool {
1269-
self.peek_non_whitespace().is_some_and(|kind| kind == TokenKind::Ident)
1270-
}
12711283
}
12721284

12731285
fn generate_link_to_def(

0 commit comments

Comments
 (0)