22
22
//! 6. extern functions
23
23
//! 7. modules + pub use
24
24
25
- use std:: io :: prelude :: * ;
25
+ use std:: fmt :: Display ;
26
26
use std:: ops:: Deref ;
27
- use std:: path:: Path ;
27
+ use std:: path:: { Path , PathBuf } ;
28
28
use std:: { env, fs} ;
29
29
30
30
use syn:: parse:: { Parse , ParseStream } ;
@@ -38,17 +38,13 @@ type Result<T> = std::result::Result<T, Error>;
38
38
#[ test]
39
39
fn check_style ( ) {
40
40
let root_dir = Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "../src" ) ;
41
- let mut errors = Errors { errs : false } ;
42
- walk ( & root_dir, & mut errors) . expect ( "root dir should be walked successfully" ) ;
43
-
44
- if errors. errs {
45
- panic ! ( "found some lint errors" ) ;
46
- } else {
47
- eprintln ! ( "good style!" ) ;
48
- }
41
+ walk ( & root_dir) . unwrap ( ) ;
42
+ eprintln ! ( "good style!" ) ;
49
43
}
50
44
51
- fn walk ( root_dir : & Path , err : & mut Errors ) -> Result < ( ) > {
45
+ fn walk ( root_dir : & Path ) -> Result < ( ) > {
46
+ let mut style_checker = StyleChecker :: new ( ) ;
47
+
52
48
for entry in glob:: glob ( & format ! (
53
49
"{}/**/*.rs" ,
54
50
root_dir. to_str( ) . expect( "dir should be valid UTF-8" )
@@ -64,34 +60,28 @@ fn walk(root_dir: &Path, err: &mut Errors) -> Result<()> {
64
60
continue ;
65
61
}
66
62
67
- let mut contents = String :: new ( ) ;
68
63
let path = entry. as_path ( ) ;
69
- fs:: File :: open ( path) ?. read_to_string ( & mut contents) ?;
70
-
71
- let file = syn:: parse_file ( & contents) ?;
72
- StyleChecker :: new ( |line, msg| err. error ( & path, line, msg) ) . visit_file ( & file) ;
64
+ style_checker. check_file ( path) ?;
65
+ style_checker. reset_state ( ) ;
73
66
}
74
67
75
- Ok ( ( ) )
76
- }
77
-
78
- struct Errors {
79
- errs : bool ,
68
+ style_checker. finalize ( )
80
69
}
81
70
82
- struct StyleChecker < F >
83
- where
84
- F : FnMut ( usize , & str ) ,
85
- {
71
+ #[ derive( Default ) ]
72
+ struct StyleChecker {
86
73
state : State ,
87
74
// FIXME: see StyleChecker::set_state
88
75
_s_macros : usize ,
89
76
f_macros : usize ,
90
- on_err : F ,
77
+ errors : Vec < FileError > ,
78
+ /// Path of the currently active file
79
+ path : PathBuf ,
91
80
}
92
81
93
- #[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
82
+ #[ derive( Default , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
94
83
enum State {
84
+ #[ default]
95
85
Start ,
96
86
Imports ,
97
87
Typedefs ,
@@ -115,24 +105,49 @@ enum ExprCfgElse {
115
105
If ( ExprCfgIf ) ,
116
106
}
117
107
118
- impl < F > StyleChecker < F >
119
- where
120
- F : FnMut ( usize , & str ) ,
121
- {
122
- fn new ( on_err : F ) -> Self {
123
- Self {
124
- state : State :: Start ,
125
- _s_macros : 0 ,
126
- f_macros : 0 ,
127
- on_err,
108
+ impl StyleChecker {
109
+ fn new ( ) -> Self {
110
+ Self :: default ( )
111
+ }
112
+
113
+ /// Reads and parses the file at the given path and checks
114
+ /// for any style violations.
115
+ fn check_file ( & mut self , path : & Path ) -> Result < ( ) > {
116
+ let contents = fs:: read_to_string ( path) ?;
117
+ let file = syn:: parse_file ( & contents) ?;
118
+
119
+ self . path = PathBuf :: from ( path) ;
120
+ self . visit_file ( & file) ;
121
+
122
+ Ok ( ( ) )
123
+ }
124
+
125
+ /// Resets the state of the [StyleChecker].
126
+ fn reset_state ( & mut self ) {
127
+ * self = Self {
128
+ errors : std:: mem:: take ( & mut self . errors ) ,
129
+ ..Self :: default ( )
130
+ } ;
131
+ }
132
+
133
+ /// Collect all errors into a single error, reporting them if any.
134
+ fn finalize ( self ) -> Result < ( ) > {
135
+ if self . errors . is_empty ( ) {
136
+ return Ok ( ( ) ) ;
128
137
}
138
+
139
+ for error in self . errors {
140
+ eprintln ! ( "{error}" ) ;
141
+ }
142
+
143
+ Err ( "some tests failed" . into ( ) )
129
144
}
130
145
131
146
fn set_state ( & mut self , new_state : State , line : usize ) {
132
147
if self . state > new_state {
133
- ( self . on_err ) (
148
+ self . error (
134
149
line,
135
- & format ! (
150
+ format ! (
136
151
"{} found after {} when it belongs before" ,
137
152
new_state. desc( ) ,
138
153
self . state. desc( )
@@ -142,7 +157,7 @@ where
142
157
143
158
if self . f_macros == 2 {
144
159
self . f_macros += 1 ;
145
- ( self . on_err ) ( line, "multiple f! macros in one module" ) ;
160
+ self . error ( line, "multiple f! macros in one module" . to_string ( ) ) ;
146
161
}
147
162
148
163
// FIXME(#4109): multiple should be allowed if at least one is `cfg(not) within `cfg_if`.
@@ -177,24 +192,32 @@ where
177
192
}
178
193
self . state = initial_state;
179
194
}
195
+
196
+ fn error ( & mut self , line : usize , msg : String ) {
197
+ self . errors . push ( FileError {
198
+ path : self . path . clone ( ) ,
199
+ line,
200
+ msg,
201
+ } ) ;
202
+ }
180
203
}
181
204
182
- impl < ' ast , F > Visit < ' ast > for StyleChecker < F >
183
- where
184
- F : FnMut ( usize , & str ) ,
185
- {
205
+ impl < ' ast > Visit < ' ast > for StyleChecker {
186
206
fn visit_meta_list ( & mut self , meta_list : & ' ast syn:: MetaList ) {
187
207
let line = meta_list. span ( ) . start ( ) . line ;
188
208
let meta_str = meta_list. tokens . to_string ( ) ;
189
209
if meta_list. path . is_ident ( "cfg" )
190
210
&& !( meta_str. contains ( "target_endian" ) || meta_str. contains ( "target_arch" ) )
191
211
&& self . state != State :: Structs
192
212
{
193
- ( self . on_err ) ( line, "use cfg_if! and submodules instead of #[cfg]" ) ;
213
+ self . error (
214
+ line,
215
+ "use cfg_if! and submodules instead of #[cfg]" . to_string ( ) ,
216
+ ) ;
194
217
} else if meta_list. path . is_ident ( "derive" )
195
218
&& ( meta_str. contains ( "Copy" ) || meta_str. contains ( "Clone" ) )
196
219
{
197
- ( self . on_err ) ( line, "impl Copy and Clone manually" ) ;
220
+ self . error ( line, "impl Copy and Clone manually" . to_string ( ) ) ;
198
221
}
199
222
200
223
visit:: visit_meta_list ( self , meta_list) ;
@@ -330,9 +353,17 @@ impl State {
330
353
}
331
354
}
332
355
333
- impl Errors {
334
- fn error ( & mut self , path : & Path , line : usize , msg : & str ) {
335
- self . errs = true ;
336
- eprintln ! ( "{}:{}: {}" , path. display( ) , line, msg) ;
356
+ #[ derive( Debug ) ]
357
+ struct FileError {
358
+ path : PathBuf ,
359
+ line : usize ,
360
+ msg : String ,
361
+ }
362
+
363
+ impl Display for FileError {
364
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
365
+ write ! ( f, "{}:{}: {}" , self . path. display( ) , self . line, self . msg)
337
366
}
338
367
}
368
+
369
+ impl std:: error:: Error for FileError { }
0 commit comments