Skip to content

Commit a4b60a9

Browse files
authored
Unrolled build for #150099
Rollup merge of #150099 - GuillaumeGomez:field-handling, r=yotamofek [rustdoc] Fix invalid handling of field followed by negated macro call This is the bug uncovered in #150022. Once fixed Ill rebuild all compiler docs and see if we can enable the option for compiler docs. =D It's a weird case where we extracted some tokens out of the iterator and then, when checking next items (from this iterator), it didn't find the `:` token, and therefore badly assumed the token kind. The solution I came up with is to instead not extract tokens from the iterator and to count how many tokens are in the current path. So when iterate over the items, instead of having a mix of extracted tokens and tokens still inside the iterator, we now only iterate over the iterator. The biggest change here is that `get_full_ident_path` will return an option instead of a `Vec`, and if it's contains `:` (one, not two), then it will return `None` and the `:` will be handled like any token and not like a path (which is more correct imo). r? `@yotamofek`
2 parents f794a08 + 2114b21 commit a4b60a9

File tree

2 files changed

+70
-32
lines changed

2 files changed

+70
-32
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,20 @@ impl<'a> PeekIter<'a> {
832832
.copied()
833833
}
834834

835+
fn peek_next_if<F: Fn((TokenKind, &'a str)) -> bool>(
836+
&mut self,
837+
f: F,
838+
) -> Option<(TokenKind, &'a str)> {
839+
let next = self.peek_next()?;
840+
if f(next) {
841+
Some(next)
842+
} else {
843+
// We go one step back.
844+
self.peek_pos -= 1;
845+
None
846+
}
847+
}
848+
835849
fn stop_peeking(&mut self) {
836850
self.peek_pos = 0;
837851
}
@@ -903,18 +917,17 @@ fn classify<'src>(
903917
}
904918
}
905919

906-
if let Some((TokenKind::Colon | TokenKind::Ident, _)) = classifier.tokens.peek() {
907-
let tokens = classifier.get_full_ident_path();
908-
for &(token, start, end) in &tokens {
909-
let text = &classifier.src[start..end];
910-
classifier.advance(token, text, sink, start as u32);
911-
classifier.byte_pos += text.len() as u32;
912-
}
913-
if !tokens.is_empty() {
914-
continue;
915-
}
916-
}
917-
if let Some((token, text, before)) = classifier.next() {
920+
if let Some((TokenKind::Colon | TokenKind::Ident, _)) = classifier.tokens.peek()
921+
&& let Some(nb_items) = classifier.get_full_ident_path()
922+
{
923+
let start = classifier.byte_pos as usize;
924+
let len: usize = iter::from_fn(|| classifier.next())
925+
.take(nb_items)
926+
.map(|(_, text, _)| text.len())
927+
.sum();
928+
let text = &classifier.src[start..start + len];
929+
classifier.advance(TokenKind::Ident, text, sink, start as u32);
930+
} else if let Some((token, text, before)) = classifier.next() {
918931
classifier.advance(token, text, sink, before);
919932
} else {
920933
break;
@@ -957,47 +970,47 @@ impl<'src> Classifier<'src> {
957970
}
958971

959972
/// Concatenate colons and idents as one when possible.
960-
fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
961-
let start = self.byte_pos as usize;
962-
let mut pos = start;
973+
fn get_full_ident_path(&mut self) -> Option<usize> {
963974
let mut has_ident = false;
975+
let mut nb_items = 0;
964976

965-
loop {
977+
let ret = loop {
966978
let mut nb = 0;
967-
while let Some((TokenKind::Colon, _)) = self.tokens.peek() {
968-
self.tokens.next();
979+
while self.tokens.peek_next_if(|(token, _)| token == TokenKind::Colon).is_some() {
969980
nb += 1;
981+
nb_items += 1;
970982
}
971983
// Ident path can start with "::" but if we already have content in the ident path,
972984
// the "::" is mandatory.
973985
if has_ident && nb == 0 {
974-
return vec![(TokenKind::Ident, start, pos)];
986+
break Some(nb_items);
975987
} else if nb != 0 && nb != 2 {
976988
if has_ident {
977-
return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
989+
// Following `;` will be handled on its own.
990+
break Some(nb_items - 1);
978991
} else {
979-
return vec![(TokenKind::Colon, start, pos + nb)];
992+
break None;
980993
}
981994
}
982995

983-
if let Some((TokenKind::Ident, text)) = self.tokens.peek()
996+
if let Some((TokenKind::Ident, text)) =
997+
self.tokens.peek_next_if(|(token, _)| token == TokenKind::Ident)
984998
&& let symbol = Symbol::intern(text)
985999
&& (symbol.is_path_segment_keyword() || !is_keyword(symbol))
9861000
{
987-
// We only "add" the colon if there is an ident behind.
988-
pos += text.len() + nb;
9891001
has_ident = true;
990-
self.tokens.next();
1002+
nb_items += 1;
9911003
} else if nb > 0 && has_ident {
992-
return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
993-
} else if nb > 0 {
994-
return vec![(TokenKind::Colon, start, start + nb)];
1004+
// Following `;` will be handled on its own.
1005+
break Some(nb_items - 1);
9951006
} else if has_ident {
996-
return vec![(TokenKind::Ident, start, pos)];
1007+
break Some(nb_items);
9971008
} else {
998-
return Vec::new();
1009+
break None;
9991010
}
1000-
}
1011+
};
1012+
self.tokens.stop_peeking();
1013+
ret
10011014
}
10021015

10031016
/// Wraps the tokens iteration to ensure that the `byte_pos` is always correct.
@@ -1243,7 +1256,6 @@ impl<'src> Classifier<'src> {
12431256
Class::MacroNonTerminal
12441257
}
12451258
TokenKind::Ident => {
1246-
let file_span = self.file_span;
12471259
let span = || new_span(before, text, file_span);
12481260

12491261
match text {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// This test ensures that the macro expansion is correctly handled in cases like:
2+
// `field: !f!`, because the `:` was simply not considered because of how paths
3+
// are handled.
4+
5+
//@ compile-flags: -Zunstable-options --generate-macro-expansion
6+
7+
#![crate_name = "foo"]
8+
9+
//@ has 'src/foo/field-followed-by-exclamation.rs.html'
10+
11+
struct Bar {
12+
bla: bool,
13+
}
14+
15+
macro_rules! f {
16+
() => {{ false }}
17+
}
18+
19+
const X: Bar = Bar {
20+
//@ has - '//*[@class="expansion"]/*[@class="original"]/*[@class="macro"]' 'f!'
21+
//@ has - '//*[@class="expansion"]/*[@class="original"]' 'f!()'
22+
//@ has - '//*[@class="expansion"]/*[@class="expanded"]' '{ false }'
23+
// It includes both original and expanded code.
24+
//@ has - '//*[@class="expansion"]' ' bla: !{ false }f!()'
25+
bla: !f!(),
26+
};

0 commit comments

Comments
 (0)