1+ use super :: diagnostics:: report_suspicious_mismatch_block;
2+ use super :: diagnostics:: same_identation_level;
3+ use super :: diagnostics:: TokenTreeDiagInfo ;
14use super :: { StringReader , UnmatchedBrace } ;
25use rustc_ast:: token:: { self , Delimiter , Token } ;
36use rustc_ast:: tokenstream:: { DelimSpan , Spacing , TokenStream , TokenTree } ;
47use rustc_ast_pretty:: pprust:: token_to_string;
5- use rustc_data_structures:: fx:: FxHashMap ;
68use rustc_errors:: { PErr , PResult } ;
7- use rustc_span:: Span ;
89
910pub ( super ) struct TokenTreesReader < ' a > {
1011 string_reader : StringReader < ' a > ,
1112 /// The "next" token, which has been obtained from the `StringReader` but
1213 /// not yet handled by the `TokenTreesReader`.
1314 token : Token ,
14- /// Stack of open delimiters and their spans. Used for error message.
15- open_braces : Vec < ( Delimiter , Span ) > ,
16- unmatched_braces : Vec < UnmatchedBrace > ,
17- /// The type and spans for all braces
18- ///
19- /// Used only for error recovery when arriving to EOF with mismatched braces.
20- matching_delim_spans : Vec < ( Delimiter , Span , Span ) > ,
21- last_unclosed_found_span : Option < Span > ,
22- /// Collect empty block spans that might have been auto-inserted by editors.
23- last_delim_empty_block_spans : FxHashMap < Delimiter , Span > ,
24- /// Collect the spans of braces (Open, Close). Used only
25- /// for detecting if blocks are empty and only braces.
26- matching_block_spans : Vec < ( Span , Span ) > ,
15+ diag_info : TokenTreeDiagInfo ,
2716}
2817
2918impl < ' a > TokenTreesReader < ' a > {
@@ -33,15 +22,10 @@ impl<'a> TokenTreesReader<'a> {
3322 let mut tt_reader = TokenTreesReader {
3423 string_reader,
3524 token : Token :: dummy ( ) ,
36- open_braces : Vec :: new ( ) ,
37- unmatched_braces : Vec :: new ( ) ,
38- matching_delim_spans : Vec :: new ( ) ,
39- last_unclosed_found_span : None ,
40- last_delim_empty_block_spans : FxHashMap :: default ( ) ,
41- matching_block_spans : Vec :: new ( ) ,
25+ diag_info : TokenTreeDiagInfo :: default ( ) ,
4226 } ;
4327 let res = tt_reader. parse_token_trees ( /* is_delimited */ false ) ;
44- ( res, tt_reader. unmatched_braces )
28+ ( res, tt_reader. diag_info . unmatched_braces )
4529 }
4630
4731 // Parse a stream of tokens into a list of `TokenTree`s.
@@ -92,9 +76,9 @@ impl<'a> TokenTreesReader<'a> {
9276 fn eof_err ( & mut self ) -> PErr < ' a > {
9377 let msg = "this file contains an unclosed delimiter" ;
9478 let mut err = self . string_reader . sess . span_diagnostic . struct_span_err ( self . token . span , msg) ;
95- for & ( _, sp) in & self . open_braces {
79+ for & ( _, sp) in & self . diag_info . open_braces {
9680 err. span_label ( sp, "unclosed delimiter" ) ;
97- self . unmatched_braces . push ( UnmatchedBrace {
81+ self . diag_info . unmatched_braces . push ( UnmatchedBrace {
9882 expected_delim : Delimiter :: Brace ,
9983 found_delim : None ,
10084 found_span : self . token . span ,
@@ -103,23 +87,13 @@ impl<'a> TokenTreesReader<'a> {
10387 } ) ;
10488 }
10589
106- if let Some ( ( delim, _) ) = self . open_braces . last ( ) {
107- if let Some ( ( _, open_sp, close_sp) ) =
108- self . matching_delim_spans . iter ( ) . find ( |( d, open_sp, close_sp) | {
109- let sm = self . string_reader . sess . source_map ( ) ;
110- if let Some ( close_padding) = sm. span_to_margin ( * close_sp) {
111- if let Some ( open_padding) = sm. span_to_margin ( * open_sp) {
112- return delim == d && close_padding != open_padding;
113- }
114- }
115- false
116- } )
117- // these are in reverse order as they get inserted on close, but
118- {
119- // we want the last open/first close
120- err. span_label ( * open_sp, "this delimiter might not be properly closed..." ) ;
121- err. span_label ( * close_sp, "...as it matches this but it has different indentation" ) ;
122- }
90+ if let Some ( ( delim, _) ) = self . diag_info . open_braces . last ( ) {
91+ report_suspicious_mismatch_block (
92+ & mut err,
93+ & self . diag_info ,
94+ & self . string_reader . sess . source_map ( ) ,
95+ * delim,
96+ )
12397 }
12498 err
12599 }
@@ -128,7 +102,7 @@ impl<'a> TokenTreesReader<'a> {
128102 // The span for beginning of the delimited section
129103 let pre_span = self . token . span ;
130104
131- self . open_braces . push ( ( open_delim, self . token . span ) ) ;
105+ self . diag_info . open_braces . push ( ( open_delim, self . token . span ) ) ;
132106
133107 // Parse the token trees within the delimiters.
134108 // We stop at any delimiter so we can try to recover if the user
@@ -137,35 +111,29 @@ impl<'a> TokenTreesReader<'a> {
137111
138112 // Expand to cover the entire delimited token tree
139113 let delim_span = DelimSpan :: from_pair ( pre_span, self . token . span ) ;
114+ let sm = self . string_reader . sess . source_map ( ) ;
140115
141116 match self . token . kind {
142117 // Correct delimiter.
143118 token:: CloseDelim ( close_delim) if close_delim == open_delim => {
144- let ( open_brace, open_brace_span) = self . open_braces . pop ( ) . unwrap ( ) ;
119+ let ( open_brace, open_brace_span) = self . diag_info . open_braces . pop ( ) . unwrap ( ) ;
145120 let close_brace_span = self . token . span ;
146121
147- if tts. is_empty ( ) {
122+ if tts. is_empty ( ) && close_delim == Delimiter :: Brace {
148123 let empty_block_span = open_brace_span. to ( close_brace_span) ;
149- let sm = self . string_reader . sess . source_map ( ) ;
150124 if !sm. is_multiline ( empty_block_span) {
151125 // Only track if the block is in the form of `{}`, otherwise it is
152126 // likely that it was written on purpose.
153- self . last_delim_empty_block_spans . insert ( open_delim , empty_block_span) ;
127+ self . diag_info . empty_block_spans . push ( empty_block_span) ;
154128 }
155129 }
156130
157- //only add braces
131+ // only add braces
158132 if let ( Delimiter :: Brace , Delimiter :: Brace ) = ( open_brace, open_delim) {
159- self . matching_block_spans . push ( ( open_brace_span, close_brace_span) ) ;
133+ // Add all the matching spans, we will sort by span later
134+ self . diag_info . matching_block_spans . push ( ( open_brace_span, close_brace_span) ) ;
160135 }
161136
162- if self . open_braces . is_empty ( ) {
163- // Clear up these spans to avoid suggesting them as we've found
164- // properly matched delimiters so far for an entire block.
165- self . matching_delim_spans . clear ( ) ;
166- } else {
167- self . matching_delim_spans . push ( ( open_brace, open_brace_span, close_brace_span) ) ;
168- }
169137 // Move past the closing delimiter.
170138 self . token = self . string_reader . next_token ( ) . 0 ;
171139 }
@@ -174,36 +142,33 @@ impl<'a> TokenTreesReader<'a> {
174142 let mut unclosed_delimiter = None ;
175143 let mut candidate = None ;
176144
177- if self . last_unclosed_found_span != Some ( self . token . span ) {
145+ if self . diag_info . last_unclosed_found_span != Some ( self . token . span ) {
178146 // do not complain about the same unclosed delimiter multiple times
179- self . last_unclosed_found_span = Some ( self . token . span ) ;
147+ self . diag_info . last_unclosed_found_span = Some ( self . token . span ) ;
180148 // This is a conservative error: only report the last unclosed
181149 // delimiter. The previous unclosed delimiters could actually be
182150 // closed! The parser just hasn't gotten to them yet.
183- if let Some ( & ( _, sp) ) = self . open_braces . last ( ) {
151+ if let Some ( & ( _, sp) ) = self . diag_info . open_braces . last ( ) {
184152 unclosed_delimiter = Some ( sp) ;
185153 } ;
186- let sm = self . string_reader . sess . source_map ( ) ;
187- if let Some ( current_padding) = sm. span_to_margin ( self . token . span ) {
188- for ( brace, brace_span) in & self . open_braces {
189- if let Some ( padding) = sm. span_to_margin ( * brace_span) {
190- // high likelihood of these two corresponding
191- if current_padding == padding && brace == & close_delim {
192- candidate = Some ( * brace_span) ;
193- }
194- }
154+ for ( brace, brace_span) in & self . diag_info . open_braces {
155+ if same_identation_level ( & sm, self . token . span , * brace_span)
156+ && brace == & close_delim
157+ {
158+ // high likelihood of these two corresponding
159+ candidate = Some ( * brace_span) ;
195160 }
196161 }
197- let ( tok, _) = self . open_braces . pop ( ) . unwrap ( ) ;
198- self . unmatched_braces . push ( UnmatchedBrace {
162+ let ( tok, _) = self . diag_info . open_braces . pop ( ) . unwrap ( ) ;
163+ self . diag_info . unmatched_braces . push ( UnmatchedBrace {
199164 expected_delim : tok,
200165 found_delim : Some ( close_delim) ,
201166 found_span : self . token . span ,
202167 unclosed_span : unclosed_delimiter,
203168 candidate_span : candidate,
204169 } ) ;
205170 } else {
206- self . open_braces . pop ( ) ;
171+ self . diag_info . open_braces . pop ( ) ;
207172 }
208173
209174 // If the incorrect delimiter matches an earlier opening
@@ -213,7 +178,7 @@ impl<'a> TokenTreesReader<'a> {
213178 // fn foo() {
214179 // bar(baz(
215180 // } // Incorrect delimiter but matches the earlier `{`
216- if !self . open_braces . iter ( ) . any ( |& ( b, _) | b == close_delim) {
181+ if !self . diag_info . open_braces . iter ( ) . any ( |& ( b, _) | b == close_delim) {
217182 self . token = self . string_reader . next_token ( ) . 0 ;
218183 }
219184 }
@@ -236,22 +201,12 @@ impl<'a> TokenTreesReader<'a> {
236201 let mut err =
237202 self . string_reader . sess . span_diagnostic . struct_span_err ( self . token . span , & msg) ;
238203
239- // Braces are added at the end, so the last element is the biggest block
240- if let Some ( parent) = self . matching_block_spans . last ( ) {
241- if let Some ( span) = self . last_delim_empty_block_spans . remove ( & delim) {
242- // Check if the (empty block) is in the last properly closed block
243- if ( parent. 0 . to ( parent. 1 ) ) . contains ( span) {
244- err. span_label ( span, "block is empty, you might have not meant to close it" ) ;
245- } else {
246- err. span_label ( parent. 0 , "this opening brace..." ) ;
247- err. span_label ( parent. 1 , "...matches this closing brace" ) ;
248- }
249- } else {
250- err. span_label ( parent. 0 , "this opening brace..." ) ;
251- err. span_label ( parent. 1 , "...matches this closing brace" ) ;
252- }
253- }
254-
204+ report_suspicious_mismatch_block (
205+ & mut err,
206+ & self . diag_info ,
207+ & self . string_reader . sess . source_map ( ) ,
208+ delim,
209+ ) ;
255210 err. span_label ( self . token . span , "unexpected closing delimiter" ) ;
256211 err
257212 }
0 commit comments