@@ -4,6 +4,8 @@ use crate::core::DocContext;
44use crate :: fold:: DocFolder ;
55use crate :: html:: markdown:: opts;
66use core:: ops:: Range ;
7+ use std:: iter:: Peekable ;
8+ use std:: str:: CharIndices ;
79use pulldown_cmark:: { Event , Parser } ;
810use rustc_feature:: UnstableFeatures ;
911use rustc_session:: lint;
@@ -75,71 +77,83 @@ fn drop_tag(
7577 }
7678}
7779
78- fn extract_tag (
80+ fn extract_html_tag (
7981 tags : & mut Vec < ( String , Range < usize > ) > ,
8082 text : & str ,
81- range : Range < usize > ,
83+ range : & Range < usize > ,
84+ start_pos : usize ,
85+ iter : & mut Peekable < CharIndices < ' _ > > ,
8286 f : & impl Fn ( & str , & Range < usize > ) ,
8387) {
84- let mut iter = text. char_indices ( ) . peekable ( ) ;
88+ let mut tag_name = String :: new ( ) ;
89+ let mut is_closing = false ;
90+ let mut prev_pos = start_pos;
8591
86- while let Some ( ( start_pos, c) ) = iter. next ( ) {
87- if c == '<' {
88- let mut tag_name = String :: new ( ) ;
89- let mut is_closing = false ;
90- let mut prev_pos = start_pos;
91- loop {
92- let ( pos, c) = match iter. peek ( ) {
93- Some ( ( pos, c) ) => ( * pos, * c) ,
94- // In case we reached the of the doc comment, we want to check that it's an
95- // unclosed HTML tag. For example "/// <h3".
96- None => ( prev_pos, '\0' ) ,
97- } ;
98- prev_pos = pos;
99- // Checking if this is a closing tag (like `</a>` for `<a>`).
100- if c == '/' && tag_name. is_empty ( ) {
101- is_closing = true ;
102- } else if c. is_ascii_alphanumeric ( ) {
103- tag_name. push ( c) ;
104- } else {
105- if !tag_name. is_empty ( ) {
106- let mut r =
107- Range { start : range. start + start_pos, end : range. start + pos } ;
108- if c == '>' {
109- // In case we have a tag without attribute, we can consider the span to
110- // refer to it fully.
111- r. end += 1 ;
92+ loop {
93+ let ( pos, c) = match iter. peek ( ) {
94+ Some ( ( pos, c) ) => ( * pos, * c) ,
95+ // In case we reached the of the doc comment, we want to check that it's an
96+ // unclosed HTML tag. For example "/// <h3".
97+ None => ( prev_pos, '\0' ) ,
98+ } ;
99+ prev_pos = pos;
100+ // Checking if this is a closing tag (like `</a>` for `<a>`).
101+ if c == '/' && tag_name. is_empty ( ) {
102+ is_closing = true ;
103+ } else if c. is_ascii_alphanumeric ( ) {
104+ tag_name. push ( c) ;
105+ } else {
106+ if !tag_name. is_empty ( ) {
107+ let mut r =
108+ Range { start : range. start + start_pos, end : range. start + pos } ;
109+ if c == '>' {
110+ // In case we have a tag without attribute, we can consider the span to
111+ // refer to it fully.
112+ r. end += 1 ;
113+ }
114+ if is_closing {
115+ // In case we have "</div >" or even "</div >".
116+ if c != '>' {
117+ if !c. is_whitespace ( ) {
118+ // It seems like it's not a valid HTML tag.
119+ break ;
112120 }
113- if is_closing {
114- // In case we have "</div >" or even "</div >".
115- if c != '>' {
116- if !c. is_whitespace ( ) {
117- // It seems like it's not a valid HTML tag.
118- break ;
119- }
120- let mut found = false ;
121- for ( new_pos, c) in text[ pos..] . char_indices ( ) {
122- if !c. is_whitespace ( ) {
123- if c == '>' {
124- r. end = range. start + new_pos + 1 ;
125- found = true ;
126- }
127- break ;
128- }
129- }
130- if !found {
131- break ;
121+ let mut found = false ;
122+ for ( new_pos, c) in text[ pos..] . char_indices ( ) {
123+ if !c. is_whitespace ( ) {
124+ if c == '>' {
125+ r. end = range. start + new_pos + 1 ;
126+ found = true ;
132127 }
128+ break ;
133129 }
134- drop_tag ( tags , tag_name , r , f ) ;
135- } else {
136- tags . push ( ( tag_name , r ) ) ;
130+ }
131+ if !found {
132+ break ;
137133 }
138134 }
139- break ;
135+ drop_tag ( tags, tag_name, r, f) ;
136+ } else {
137+ tags. push ( ( tag_name, r) ) ;
140138 }
141- iter. next ( ) ;
142139 }
140+ break ;
141+ }
142+ iter. next ( ) ;
143+ }
144+ }
145+
146+ fn extract_tags (
147+ tags : & mut Vec < ( String , Range < usize > ) > ,
148+ text : & str ,
149+ range : Range < usize > ,
150+ f : & impl Fn ( & str , & Range < usize > ) ,
151+ ) {
152+ let mut iter = text. char_indices ( ) . peekable ( ) ;
153+
154+ while let Some ( ( start_pos, c) ) = iter. next ( ) {
155+ if c == '<' {
156+ extract_html_tag ( tags, text, & range, start_pos, & mut iter, f) ;
143157 }
144158 }
145159}
@@ -172,7 +186,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
172186
173187 for ( event, range) in p {
174188 match event {
175- Event :: Html ( text) => extract_tag ( & mut tags, & text, range, & report_diag) ,
189+ Event :: Html ( text) => extract_tags ( & mut tags, & text, range, & report_diag) ,
176190 _ => { }
177191 }
178192 }
0 commit comments