8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- #![ feature( custom_attribute ) ]
11
+ #![ feature( tool_attributes ) ]
12
12
#![ feature( decl_macro) ]
13
- // FIXME(cramertj) remove after match_default_bindings merges
14
- #![ allow( stable_features) ]
15
13
#![ allow( unused_attributes) ]
16
- #![ feature( match_default_bindings) ]
17
14
#![ feature( type_ascription) ]
18
15
#![ feature( unicode_internals) ]
19
16
@@ -40,6 +37,7 @@ extern crate term;
40
37
extern crate toml;
41
38
extern crate unicode_segmentation;
42
39
40
+ use std:: cell:: RefCell ;
43
41
use std:: collections:: HashMap ;
44
42
use std:: fmt;
45
43
use std:: io:: { self , stdout, Write } ;
@@ -50,7 +48,7 @@ use std::time::Duration;
50
48
51
49
use syntax:: ast;
52
50
pub use syntax:: codemap:: FileName ;
53
- use syntax:: codemap:: { CodeMap , FilePathMapping } ;
51
+ use syntax:: codemap:: { CodeMap , FilePathMapping , Span } ;
54
52
use syntax:: errors:: emitter:: { ColorConfig , EmitterWriter } ;
55
53
use syntax:: errors:: { DiagnosticBuilder , Handler } ;
56
54
use syntax:: parse:: { self , ParseSess } ;
@@ -128,9 +126,14 @@ pub enum ErrorKind {
128
126
// License check has failed
129
127
#[ fail( display = "license check failed" ) ]
130
128
LicenseCheck ,
129
+ // Used deprecated skip attribute
130
+ #[ fail( display = "`rustfmt_skip` is deprecated; use `rustfmt::skip`" ) ]
131
+ DeprecatedAttr ,
132
+ // Used a rustfmt:: attribute other than skip
133
+ #[ fail( display = "invalid attribute" ) ]
134
+ BadAttr ,
131
135
}
132
136
133
- // Formatting errors that are identified *after* rustfmt has run.
134
137
struct FormattingError {
135
138
line : usize ,
136
139
kind : ErrorKind ,
@@ -140,11 +143,28 @@ struct FormattingError {
140
143
}
141
144
142
145
impl FormattingError {
146
+ fn from_span ( span : & Span , codemap : & CodeMap , kind : ErrorKind ) -> FormattingError {
147
+ FormattingError {
148
+ line : codemap. lookup_char_pos ( span. lo ( ) ) . line ,
149
+ kind,
150
+ is_comment : false ,
151
+ is_string : false ,
152
+ line_buffer : codemap
153
+ . span_to_lines ( * span)
154
+ . ok ( )
155
+ . and_then ( |fl| {
156
+ fl. file
157
+ . get_line ( fl. lines [ 0 ] . line_index )
158
+ . map ( |l| l. into_owned ( ) )
159
+ } )
160
+ . unwrap_or_else ( || String :: new ( ) ) ,
161
+ }
162
+ }
143
163
fn msg_prefix ( & self ) -> & str {
144
164
match self . kind {
145
165
ErrorKind :: LineOverflow ( ..) | ErrorKind :: TrailingWhitespace => "internal error:" ,
146
- ErrorKind :: LicenseCheck => "error:" ,
147
- ErrorKind :: BadIssue ( _) => "warning:" ,
166
+ ErrorKind :: LicenseCheck | ErrorKind :: BadAttr => "error:" ,
167
+ ErrorKind :: BadIssue ( _) | ErrorKind :: DeprecatedAttr => "warning:" ,
148
168
}
149
169
}
150
170
@@ -161,7 +181,7 @@ impl FormattingError {
161
181
fn format_len ( & self ) -> ( usize , usize ) {
162
182
match self . kind {
163
183
ErrorKind :: LineOverflow ( found, max) => ( max, found - max) ,
164
- ErrorKind :: TrailingWhitespace => {
184
+ ErrorKind :: TrailingWhitespace | ErrorKind :: DeprecatedAttr | ErrorKind :: BadAttr => {
165
185
let trailing_ws_start = self
166
186
. line_buffer
167
187
. rfind ( |c : char | !c. is_whitespace ( ) )
@@ -177,20 +197,30 @@ impl FormattingError {
177
197
}
178
198
}
179
199
200
+ #[ derive( Clone ) ]
180
201
pub struct FormatReport {
181
202
// Maps stringified file paths to their associated formatting errors.
182
- file_error_map : HashMap < FileName , Vec < FormattingError > > ,
203
+ file_error_map : Rc < RefCell < HashMap < FileName , Vec < FormattingError > > > > ,
183
204
}
184
205
185
206
impl FormatReport {
186
207
fn new ( ) -> FormatReport {
187
208
FormatReport {
188
- file_error_map : HashMap :: new ( ) ,
209
+ file_error_map : Rc :: new ( RefCell :: new ( HashMap :: new ( ) ) ) ,
189
210
}
190
211
}
191
212
213
+ fn append ( & self , f : FileName , mut v : Vec < FormattingError > ) {
214
+ self . file_error_map
215
+ . borrow_mut ( )
216
+ . entry ( f)
217
+ . and_modify ( |fe| fe. append ( & mut v) )
218
+ . or_insert ( v) ;
219
+ }
220
+
192
221
fn warning_count ( & self ) -> usize {
193
222
self . file_error_map
223
+ . borrow ( )
194
224
. iter ( )
195
225
. map ( |( _, errors) | errors. len ( ) )
196
226
. sum ( )
@@ -204,7 +234,7 @@ impl FormatReport {
204
234
& self ,
205
235
mut t : Box < term:: Terminal < Output = io:: Stderr > > ,
206
236
) -> Result < ( ) , term:: Error > {
207
- for ( file, errors) in & self . file_error_map {
237
+ for ( file, errors) in & * self . file_error_map . borrow ( ) {
208
238
for error in errors {
209
239
let prefix_space_len = error. line . to_string ( ) . len ( ) ;
210
240
let prefix_spaces = " " . repeat ( 1 + prefix_space_len) ;
@@ -250,7 +280,7 @@ impl FormatReport {
250
280
}
251
281
}
252
282
253
- if !self . file_error_map . is_empty ( ) {
283
+ if !self . file_error_map . borrow ( ) . is_empty ( ) {
254
284
t. attr ( term:: Attr :: Bold ) ?;
255
285
write ! ( t, "warning: " ) ?;
256
286
t. reset ( ) ?;
@@ -274,7 +304,7 @@ fn target_str(space_len: usize, target_len: usize) -> String {
274
304
impl fmt:: Display for FormatReport {
275
305
// Prints all the formatting errors.
276
306
fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
277
- for ( file, errors) in & self . file_error_map {
307
+ for ( file, errors) in & * self . file_error_map . borrow ( ) {
278
308
for error in errors {
279
309
let prefix_space_len = error. line . to_string ( ) . len ( ) ;
280
310
let prefix_spaces = " " . repeat ( 1 + prefix_space_len) ;
@@ -313,7 +343,7 @@ impl fmt::Display for FormatReport {
313
343
) ?;
314
344
}
315
345
}
316
- if !self . file_error_map . is_empty ( ) {
346
+ if !self . file_error_map . borrow ( ) . is_empty ( ) {
317
347
writeln ! (
318
348
fmt,
319
349
"warning: rustfmt may have failed to format. See previous {} errors." ,
@@ -339,10 +369,11 @@ fn format_ast<F>(
339
369
parse_session : & mut ParseSess ,
340
370
main_file : & FileName ,
341
371
config : & Config ,
372
+ report : FormatReport ,
342
373
mut after_file : F ,
343
374
) -> Result < ( FileMap , bool ) , io:: Error >
344
375
where
345
- F : FnMut ( & FileName , & mut String , & [ ( usize , usize ) ] ) -> Result < bool , io:: Error > ,
376
+ F : FnMut ( & FileName , & mut String , & [ ( usize , usize ) ] , & FormatReport ) -> Result < bool , io:: Error > ,
346
377
{
347
378
let mut result = FileMap :: new ( ) ;
348
379
// diff mode: check if any files are differing
@@ -360,7 +391,8 @@ where
360
391
. file ;
361
392
let big_snippet = filemap. src . as_ref ( ) . unwrap ( ) ;
362
393
let snippet_provider = SnippetProvider :: new ( filemap. start_pos , big_snippet) ;
363
- let mut visitor = FmtVisitor :: from_codemap ( parse_session, config, & snippet_provider) ;
394
+ let mut visitor =
395
+ FmtVisitor :: from_codemap ( parse_session, config, & snippet_provider, report. clone ( ) ) ;
364
396
// Format inner attributes if available.
365
397
if !krate. attrs . is_empty ( ) && path == * main_file {
366
398
visitor. skip_empty_lines ( filemap. end_pos ) ;
@@ -380,8 +412,7 @@ where
380
412
:: utils:: count_newlines( & visitor. buffer)
381
413
) ;
382
414
383
- let filename = path. clone ( ) ;
384
- has_diff |= match after_file ( & filename, & mut visitor. buffer , & visitor. skipped_range ) {
415
+ has_diff |= match after_file ( & path, & mut visitor. buffer , & visitor. skipped_range , & report) {
385
416
Ok ( result) => result,
386
417
Err ( e) => {
387
418
// Create a new error with path_str to help users see which files failed
@@ -390,13 +421,13 @@ where
390
421
}
391
422
} ;
392
423
393
- result. push ( ( filename , visitor. buffer ) ) ;
424
+ result. push ( ( path . clone ( ) , visitor. buffer ) ) ;
394
425
}
395
426
396
427
Ok ( ( result, has_diff) )
397
428
}
398
429
399
- /// Returns true if the line with the given line number was skipped by `#[rustfmt_skip ]`.
430
+ /// Returns true if the line with the given line number was skipped by `#[rustfmt::skip ]`.
400
431
fn is_skipped_line ( line_number : usize , skipped_range : & [ ( usize , usize ) ] ) -> bool {
401
432
skipped_range
402
433
. iter ( )
@@ -429,7 +460,7 @@ fn format_lines(
429
460
name : & FileName ,
430
461
skipped_range : & [ ( usize , usize ) ] ,
431
462
config : & Config ,
432
- report : & mut FormatReport ,
463
+ report : & FormatReport ,
433
464
) {
434
465
let mut trims = vec ! [ ] ;
435
466
let mut last_wspace: Option < usize > = None ;
@@ -543,7 +574,7 @@ fn format_lines(
543
574
}
544
575
}
545
576
546
- report. file_error_map . insert ( name. clone ( ) , errors) ;
577
+ report. append ( name. clone ( ) , errors) ;
547
578
}
548
579
549
580
fn parse_input < ' sess > (
@@ -760,19 +791,20 @@ fn format_input_inner<T: Write>(
760
791
) ) ;
761
792
parse_session. span_diagnostic = Handler :: with_emitter ( true , false , silent_emitter) ;
762
793
763
- let mut report = FormatReport :: new ( ) ;
794
+ let report = FormatReport :: new ( ) ;
764
795
765
796
let format_result = format_ast (
766
797
& krate,
767
798
& mut parse_session,
768
799
& main_file,
769
800
config,
770
- |file_name, file, skipped_range| {
801
+ report. clone ( ) ,
802
+ |file_name, file, skipped_range, report| {
771
803
// For some reason, the codemap does not include terminating
772
804
// newlines so we must add one on for each file. This is sad.
773
805
filemap:: append_newline ( file) ;
774
806
775
- format_lines ( file, file_name, skipped_range, config, & mut report) ;
807
+ format_lines ( file, file_name, skipped_range, config, report) ;
776
808
777
809
if let Some ( ref mut out) = out {
778
810
return filemap:: write_file ( file, file_name, out, config) ;
@@ -975,7 +1007,7 @@ mod unit_tests {
975
1007
976
1008
#[ test]
977
1009
fn test_format_code_block_fail ( ) {
978
- #[ rustfmt_skip ]
1010
+ #[ rustfmt :: skip ]
979
1011
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);" ;
980
1012
assert ! ( format_code_block( code_block, & Config :: default ( ) ) . is_none( ) ) ;
981
1013
}
0 commit comments