From e83c8085a0260b7280210adebbb1db852d17eee9 Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Wed, 16 Aug 2017 20:08:27 -0400 Subject: [PATCH] Don't highlight # which does not start an attribute in rustdoc --- src/librustdoc/html/highlight.rs | 58 +++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 89a40b0db9662..239bcb3d69b99 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -172,6 +172,21 @@ impl<'a> Classifier<'a> { } } + /// Gets the next token out of the lexer, emitting fatal errors if lexing fails. + fn try_next_token(&mut self) -> io::Result { + match self.lexer.try_next_token() { + Ok(tas) => Ok(tas), + Err(_) => { + self.lexer.emit_fatal_errors(); + self.lexer.sess.span_diagnostic + .struct_warn("Backing out of syntax highlighting") + .note("You probably did not intend to render this as a rust code-block") + .emit(); + Err(io::Error::new(io::ErrorKind::Other, "")) + } + } + } + /// Exhausts the `lexer` writing the output into `out`. /// /// The general structure for this method is to iterate over each token, @@ -183,18 +198,7 @@ impl<'a> Classifier<'a> { out: &mut W) -> io::Result<()> { loop { - let next = match self.lexer.try_next_token() { - Ok(tas) => tas, - Err(_) => { - self.lexer.emit_fatal_errors(); - self.lexer.sess.span_diagnostic - .struct_warn("Backing out of syntax highlighting") - .note("You probably did not intend to render this as a rust code-block") - .emit(); - return Err(io::Error::new(io::ErrorKind::Other, "")); - } - }; - + let next = self.try_next_token()?; if next.tok == token::Eof { break; } @@ -255,13 +259,37 @@ impl<'a> Classifier<'a> { } } - // This is the start of an attribute. We're going to want to + // This might be the start of an attribute. We're going to want to // continue highlighting it as an attribute until the ending ']' is // seen, so skip out early. Down below we terminate the attribute // span when we see the ']'. token::Pound => { - self.in_attribute = true; - out.enter_span(Class::Attribute)?; + // We can't be sure that our # begins an attribute (it could + // just be appearing in a macro) until we read either `#![` or + // `#[` from the input stream. + // + // We don't want to start highlighting as an attribute until + // we're confident there is going to be a ] coming up, as + // otherwise # tokens in macros highlight the rest of the input + // as an attribute. + + // Case 1: #![inner_attribute] + if self.lexer.peek().tok == token::Not { + self.try_next_token()?; // NOTE: consumes `!` token! + if self.lexer.peek().tok == token::OpenDelim(token::Bracket) { + self.in_attribute = true; + out.enter_span(Class::Attribute)?; + } + out.string("#", Class::None, None)?; + out.string("!", Class::None, None)?; + return Ok(()); + } + + // Case 2: #[outer_attribute] + if self.lexer.peek().tok == token::OpenDelim(token::Bracket) { + self.in_attribute = true; + out.enter_span(Class::Attribute)?; + } out.string("#", Class::None, None)?; return Ok(()); }