Skip to content

Commit e83c808

Browse files
committed
Don't highlight # which does not start an attribute in rustdoc
1 parent a7e0d3a commit e83c808

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

src/librustdoc/html/highlight.rs

+43-15
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,21 @@ impl<'a> Classifier<'a> {
172172
}
173173
}
174174

175+
/// Gets the next token out of the lexer, emitting fatal errors if lexing fails.
176+
fn try_next_token(&mut self) -> io::Result<TokenAndSpan> {
177+
match self.lexer.try_next_token() {
178+
Ok(tas) => Ok(tas),
179+
Err(_) => {
180+
self.lexer.emit_fatal_errors();
181+
self.lexer.sess.span_diagnostic
182+
.struct_warn("Backing out of syntax highlighting")
183+
.note("You probably did not intend to render this as a rust code-block")
184+
.emit();
185+
Err(io::Error::new(io::ErrorKind::Other, ""))
186+
}
187+
}
188+
}
189+
175190
/// Exhausts the `lexer` writing the output into `out`.
176191
///
177192
/// The general structure for this method is to iterate over each token,
@@ -183,18 +198,7 @@ impl<'a> Classifier<'a> {
183198
out: &mut W)
184199
-> io::Result<()> {
185200
loop {
186-
let next = match self.lexer.try_next_token() {
187-
Ok(tas) => tas,
188-
Err(_) => {
189-
self.lexer.emit_fatal_errors();
190-
self.lexer.sess.span_diagnostic
191-
.struct_warn("Backing out of syntax highlighting")
192-
.note("You probably did not intend to render this as a rust code-block")
193-
.emit();
194-
return Err(io::Error::new(io::ErrorKind::Other, ""));
195-
}
196-
};
197-
201+
let next = self.try_next_token()?;
198202
if next.tok == token::Eof {
199203
break;
200204
}
@@ -255,13 +259,37 @@ impl<'a> Classifier<'a> {
255259
}
256260
}
257261

258-
// This is the start of an attribute. We're going to want to
262+
// This might be the start of an attribute. We're going to want to
259263
// continue highlighting it as an attribute until the ending ']' is
260264
// seen, so skip out early. Down below we terminate the attribute
261265
// span when we see the ']'.
262266
token::Pound => {
263-
self.in_attribute = true;
264-
out.enter_span(Class::Attribute)?;
267+
// We can't be sure that our # begins an attribute (it could
268+
// just be appearing in a macro) until we read either `#![` or
269+
// `#[` from the input stream.
270+
//
271+
// We don't want to start highlighting as an attribute until
272+
// we're confident there is going to be a ] coming up, as
273+
// otherwise # tokens in macros highlight the rest of the input
274+
// as an attribute.
275+
276+
// Case 1: #![inner_attribute]
277+
if self.lexer.peek().tok == token::Not {
278+
self.try_next_token()?; // NOTE: consumes `!` token!
279+
if self.lexer.peek().tok == token::OpenDelim(token::Bracket) {
280+
self.in_attribute = true;
281+
out.enter_span(Class::Attribute)?;
282+
}
283+
out.string("#", Class::None, None)?;
284+
out.string("!", Class::None, None)?;
285+
return Ok(());
286+
}
287+
288+
// Case 2: #[outer_attribute]
289+
if self.lexer.peek().tok == token::OpenDelim(token::Bracket) {
290+
self.in_attribute = true;
291+
out.enter_span(Class::Attribute)?;
292+
}
265293
out.string("#", Class::None, None)?;
266294
return Ok(());
267295
}

0 commit comments

Comments
 (0)