Skip to content

Commit 8effa01

Browse files
Fix invalid macro tag generation for keywords which can be followed by values
1 parent 9606412 commit 8effa01

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,9 @@ fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class>
798798
})
799799
}
800800

801+
/// Used to know if a keyword followed by a `!` should never be treated as a macro.
802+
const KEYWORDS_FOLLOWABLE_BY_VALUE: &[&str] = &["if", "while", "match", "break", "return"];
803+
801804
/// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than
802805
/// just the next item by using `peek_next`. The `peek` method always returns the next item after
803806
/// the current one whereas `peek_next` will return the next item after the last one peeked.
@@ -1017,6 +1020,19 @@ impl<'src> Classifier<'src> {
10171020
}
10181021
}
10191022

1023+
fn new_macro_span(
1024+
&mut self,
1025+
text: &'src str,
1026+
sink: &mut dyn FnMut(Span, Highlight<'src>),
1027+
before: u32,
1028+
file_span: Span,
1029+
) {
1030+
self.in_macro = true;
1031+
let span = new_span(before, text, file_span);
1032+
sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) });
1033+
sink(span, Highlight::Token { text, class: None });
1034+
}
1035+
10201036
/// Single step of highlighting. This will classify `token`, but maybe also a couple of
10211037
/// following ones as well.
10221038
///
@@ -1223,17 +1239,18 @@ impl<'src> Classifier<'src> {
12231239
LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
12241240
},
12251241
TokenKind::GuardedStrPrefix => return no_highlight(sink),
1226-
TokenKind::Ident | TokenKind::RawIdent
1227-
if self.peek_non_whitespace() == Some(TokenKind::Bang) =>
1228-
{
1229-
self.in_macro = true;
1230-
let span = new_span(before, text, file_span);
1231-
sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) });
1232-
sink(span, Highlight::Token { text, class: None });
1242+
TokenKind::RawIdent if self.peek_non_whitespace() == Some(TokenKind::Bang) => {
1243+
self.new_macro_span(text, sink, before, file_span);
12331244
return;
12341245
}
12351246
TokenKind::Ident => {
12361247
match get_real_ident_class(text, false) {
1248+
// If it's not a keyword and the next non whitespace token is a `!`, then
1249+
// we consider it's a macro.
1250+
None if self.peek_non_whitespace() == Some(TokenKind::Bang) => {
1251+
self.new_macro_span(text, sink, before, file_span);
1252+
return;
1253+
}
12371254
None => match text {
12381255
"Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)),
12391256
"Some" | "None" | "Ok" | "Err" => {
@@ -1249,7 +1266,18 @@ impl<'src> Classifier<'src> {
12491266
"self" | "Self" => Class::Self_(new_span(before, text, file_span)),
12501267
_ => Class::Ident(new_span(before, text, file_span)),
12511268
},
1252-
Some(c) => c,
1269+
Some(c) => {
1270+
// So if it's not a keyword which can be followed by a value (like `if` or
1271+
// `return`) and the next non-whitespace token is a `!`, then we consider
1272+
// it's a macro.
1273+
if !KEYWORDS_FOLLOWABLE_BY_VALUE.contains(&text)
1274+
&& self.peek_non_whitespace() == Some(TokenKind::Bang)
1275+
{
1276+
self.new_macro_span(text, sink, before, file_span);
1277+
return;
1278+
}
1279+
c
1280+
}
12531281
}
12541282
}
12551283
TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {

0 commit comments

Comments
 (0)