@@ -103,12 +103,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
103103 } ) ;
104104 } ;
105105
106- let mut tagp = TagParser {
107- tags : Vec :: new ( ) ,
108- tag_name : String :: with_capacity ( 8 ) ,
109- is_closing : false ,
110- tag_start_pos : 0 ,
111- } ;
106+ let mut tagp = TagParser :: new ( ) ;
112107 let mut is_in_comment = None ;
113108 let mut in_code_block = false ;
114109
@@ -257,6 +252,15 @@ struct TagParser {
257252}
258253
259254impl TagParser {
255+ fn new ( ) -> Self {
256+ Self {
257+ tags : Vec :: new ( ) ,
258+ tag_name : String :: with_capacity ( 8 ) ,
259+ is_closing : false ,
260+ tag_start_pos : 0 ,
261+ }
262+ }
263+
260264 fn drop_tag (
261265 & mut self ,
262266 range : Range < usize > ,
@@ -293,6 +297,19 @@ impl TagParser {
293297 }
294298 }
295299
300+ /// Handle a `<` that appeared while parsing a tag.
301+ fn handle_lt_in_tag ( & mut self , range : Range < usize > , lt_pos : usize , f : & impl Fn ( String , & Range < usize > , bool ) , ) {
302+ let global_pos = range. start + lt_pos;
303+ // is this check needed?
304+ if global_pos == self . tag_start_pos {
305+ // `<` is in the tag because it is the start.
306+ return ;
307+ }
308+ // tried to start a new tag while in a tag
309+ f ( format ! ( "incomplete HTML tag `{}`" , & self . tag_name) , & ( self . tag_start_pos ..global_pos) , false ) ;
310+ self . tag_parsed ( ) ;
311+ }
312+
296313
297314 fn extract_html_tag (
298315 & mut self ,
@@ -341,9 +358,7 @@ impl TagParser {
341358 r. end = range. start + new_pos + 1 ;
342359 found = true ;
343360 } else if c == '<' {
344- // tried to start a new tag while in a tag
345- f ( format ! ( "incomplete HTML tag `{}`" , & self . tag_name) , & ( self . tag_start_pos ..range. start + start_pos + new_pos) , false ) ;
346- self . tag_parsed ( ) ;
361+ self . handle_lt_in_tag ( range. clone ( ) , pos + new_pos, f) ;
347362
348363 }
349364 break ;
@@ -371,9 +386,7 @@ impl TagParser {
371386 } else if c == '>' {
372387 break ;
373388 } else if c == '<' {
374- // tried to start a new tag while in a tag
375- f ( format ! ( "incomplete HTML tag `{}`" , & self . tag_name) , & ( self . tag_start_pos ..range. start + start_pos + i) , false ) ;
376- self . tag_parsed ( ) ;
389+ self . handle_lt_in_tag ( range. clone ( ) , pos + i, f) ;
377390 } else if c == '/' && !after_eq {
378391 is_self_closing = true ;
379392 } else {
@@ -454,12 +467,15 @@ impl TagParser {
454467 end : range. start + start_pos + 3 ,
455468 } ) ;
456469 } else {
457- if !self . tag_name . is_empty ( ) {
470+ if self . tag_name . is_empty ( ) {
471+ self . tag_start_pos = range. start + start_pos;
472+ }
473+ /*if !self.tag_name.is_empty() {
474+
458475 f(format!("incomplete HTML tag `{}`", &self.tag_name), &(self.tag_start_pos..range.start + start_pos), false);
459476 self.tag_parsed();
460477
461- }
462- self . tag_start_pos = range. start + start_pos;
478+ }*/
463479 self . extract_html_tag ( text, & range, dox, start_pos, & mut iter, f) ;
464480 }
465481 } else if !self . tag_name . is_empty ( ) {
@@ -470,3 +486,19 @@ impl TagParser {
470486 }
471487
472488}
489+
490+ #[ test]
491+ fn test_extract_tags_nested_unclosed ( ) {
492+ use std:: rc:: Rc ;
493+ use std:: cell:: RefCell ;
494+ use std:: ops:: Deref ;
495+
496+ let mut tagp = TagParser :: new ( ) ;
497+ let mut diags = RefCell :: new ( Vec :: new ( ) ) ;
498+ let dox = "<div>\n <br<div>" ;
499+ tagp. extract_tags ( dox, 0 ..dox. len ( ) , dox, & mut None , & |s, r, b| {
500+ diags. borrow_mut ( ) . push ( ( s, r. clone ( ) , b) ) ;
501+ } ) ;
502+ assert_eq ! ( diags. borrow( ) . len( ) , 1 , "did not get expected diagnostics: {diags:?}" ) ;
503+ assert_eq ! ( diags. borrow( ) [ 0 ] . 1 , 6 ..9 )
504+ }
0 commit comments