@@ -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