@@ -36,57 +36,41 @@ struct BrokenLink {
3636 span : Span ,
3737}
3838
39+ enum State {
40+ ProcessingLinkText ,
41+ ProcessedLinkText ,
42+ ProcessingLinkUrl ( UrlState ) ,
43+ }
44+
45+ enum UrlState {
46+ Empty ,
47+ FilledEntireSingleLine ,
48+ FilledBrokenMultipleLines ,
49+ }
50+
3951/// Scan AST attributes looking up in doc comments for broken links
4052/// which rustdoc won't be able to properly create link tags later.
4153struct BrokenLinkLoader {
4254 /// List of spans for detected broken links.
4355 broken_links : Vec < BrokenLink > ,
4456
45- /// Mark it has detected a link and it is processing whether
46- /// or not it is broken.
47- active : bool ,
57+ state : Option < State > ,
4858
4959 /// Keep track of the span for the processing broken link.
5060 active_span : Option < Span > ,
5161
5262 /// Keep track where exactly the link definition has started in the code.
5363 active_pos_start : u32 ,
54-
55- /// Mark it is processing the link text tag.
56- processing_link_text : bool ,
57-
58- /// Mark it is processing the link url tag.
59- processing_link_url : bool ,
60-
61- /// Mark it is reading the url tag content. It will be false if the loader
62- /// got to the url tag processing, but all the chars read so far were just
63- /// whitespaces.
64- reading_link_url : bool ,
65-
66- /// Mark the url url isn't empty, but it still being processed in a new line.
67- reading_link_url_new_line : bool ,
68-
69- /// Mark the current link url is broken across multiple lines.
70- url_multiple_lines : bool ,
71-
72- /// Mark the link's span start position.
73- start : u32 ,
7464}
7565
7666impl BrokenLinkLoader {
7767 /// Return spans of broken links.
7868 fn collect_spans_broken_link ( attrs : & [ Attribute ] ) -> Vec < BrokenLink > {
7969 let mut loader = BrokenLinkLoader {
8070 broken_links : vec ! [ ] ,
81- active : false ,
71+ state : None ,
8272 active_pos_start : 0 ,
8373 active_span : None ,
84- processing_link_text : false ,
85- processing_link_url : false ,
86- reading_link_url : false ,
87- reading_link_url_new_line : false ,
88- url_multiple_lines : false ,
89- start : 0_u32 ,
9074 } ;
9175 loader. scan_attrs ( attrs) ;
9276 loader. broken_links
@@ -109,72 +93,71 @@ impl BrokenLinkLoader {
10993 // exactly that. It provides an iterator over tuples of the form `(byte position, char)`.
11094 let char_indices: Vec < _ > = line. char_indices ( ) . collect ( ) ;
11195
112- self . reading_link_url_new_line = self . reading_link_url ;
96+ let reading_link_url_new_line = match self . state {
97+ Some ( State :: ProcessingLinkUrl ( UrlState :: FilledEntireSingleLine ) ) => true ,
98+ _ => false ,
99+ } ;
113100
114101 for ( pos, c) in char_indices {
115102 if pos == 0 && c. is_whitespace ( ) {
116103 // ignore prefix whitespace on comments
117104 continue ;
118105 }
119106
120- if ! self . active {
121- if c == '[' {
122- self . processing_link_text = true ;
123- self . active = true ;
124- // +3 skips the opening delimiter
125- self . active_pos_start = attr_span. lo ( ) . 0 + u32:: try_from ( pos) . unwrap ( ) + 3 ;
126- self . active_span = Some ( attr_span) ;
127- }
128- continue ;
129- }
130-
131- if self . processing_link_text {
132- if c == ']' {
133- self . processing_link_text = false ;
134- }
135- continue ;
136- }
137-
138- if ! self . processing_link_url {
139- if c == '(' {
140- self . processing_link_url = true ;
141- } else {
142- // not a real link, start lookup over again
143- self . reset_lookup ( ) ;
144- }
145- continue ;
146- }
147-
148- if c == ')' {
149- // record full broken link tag
150- if self . url_multiple_lines {
151- // +3 skips the opening delimiter and +1 to include the closing parethesis
152- let pos_end = attr_span . lo ( ) . 0 + u32 :: try_from ( pos ) . unwrap ( ) + 4 ;
153- self . record_broken_link ( pos_end , BrokenLinkReason :: MultipleLines ) ;
154- self . reset_lookup ( ) ;
155- }
156- self . reset_lookup ( ) ;
157- continue ;
158- }
159-
160- if !c . is_whitespace ( ) {
161- self . reading_link_url = true ;
162- }
163-
164- if self . reading_link_url_new_line {
165- self . url_multiple_lines = true ;
166- }
107+ match & self . state {
108+ None => {
109+ if c == '[' {
110+ self . state = Some ( State :: ProcessingLinkText ) ;
111+ // +3 skips the opening delimiter
112+ self . active_pos_start = attr_span. lo ( ) . 0 + u32:: try_from ( pos) . unwrap ( ) + 3 ;
113+ self . active_span = Some ( attr_span) ;
114+ }
115+ } ,
116+ Some ( State :: ProcessingLinkText ) => {
117+ if c == ']' {
118+ self . state = Some ( State :: ProcessedLinkText ) ;
119+ }
120+ } ,
121+ Some ( State :: ProcessedLinkText ) => {
122+ if c == '(' {
123+ self . state = Some ( State :: ProcessingLinkUrl ( UrlState :: Empty ) ) ;
124+ } else {
125+ // not a real link, start lookup over again
126+ self . reset_lookup ( ) ;
127+ }
128+ } ,
129+ Some ( State :: ProcessingLinkUrl ( url_state ) ) => {
130+ if c == ')' {
131+ // record full broken link tag
132+ if let UrlState :: FilledBrokenMultipleLines = url_state {
133+ // +3 skips the opening delimiter and +1 to include the closing parethesis
134+ let pos_end = attr_span . lo ( ) . 0 + u32 :: try_from ( pos ) . unwrap ( ) + 4 ;
135+ self . record_broken_link ( pos_end , BrokenLinkReason :: MultipleLines ) ;
136+ self . reset_lookup ( ) ;
137+ }
138+ self . reset_lookup ( ) ;
139+ continue ;
140+ }
141+
142+ if !c . is_whitespace ( ) {
143+ if reading_link_url_new_line {
144+ // It was reading a link url which was entirely in a single line, but a new char
145+ // was found in this new line which turned the url into a broken state.
146+ self . state = Some ( State :: ProcessingLinkUrl ( UrlState :: FilledBrokenMultipleLines ) ) ;
147+ continue ;
148+ }
149+
150+ self . state = Some ( State :: ProcessingLinkUrl ( UrlState :: FilledEntireSingleLine ) ) ;
151+ }
152+ } ,
153+ } ;
167154 }
168155 }
169156
170157 fn reset_lookup ( & mut self ) {
171- self . active = false ;
172- self . start = 0 ;
173- self . processing_link_text = false ;
174- self . processing_link_url = false ;
175- self . reading_link_url = false ;
176- self . reading_link_url_new_line = false ;
177- self . url_multiple_lines = false ;
158+ self . state = None ;
159+ self . active_span = None ;
160+ self . active_pos_start = 0 ;
178161 }
179162
180163 fn record_broken_link ( & mut self , pos_end : u32 , reason : BrokenLinkReason ) {
0 commit comments