2222//! 6. extern functions
2323//! 7. modules + pub use
2424
25- use std:: io :: prelude :: * ;
25+ use std:: fmt :: Display ;
2626use std:: ops:: Deref ;
27- use std:: path:: Path ;
27+ use std:: path:: { Path , PathBuf } ;
2828use std:: { env, fs} ;
2929
3030use syn:: parse:: { Parse , ParseStream } ;
@@ -38,17 +38,13 @@ type Result<T> = std::result::Result<T, Error>;
3838#[ test]
3939fn check_style ( ) {
4040 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!" ) ;
4943}
5044
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+
5248 for entry in glob:: glob ( & format ! (
5349 "{}/**/*.rs" ,
5450 root_dir. to_str( ) . expect( "dir should be valid UTF-8" )
@@ -64,34 +60,28 @@ fn walk(root_dir: &Path, err: &mut Errors) -> Result<()> {
6460 continue ;
6561 }
6662
67- let mut contents = String :: new ( ) ;
6863 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 ( ) ;
7366 }
7467
75- Ok ( ( ) )
76- }
77-
78- struct Errors {
79- errs : bool ,
68+ style_checker. finalize ( )
8069}
8170
82- struct StyleChecker < F >
83- where
84- F : FnMut ( usize , & str ) ,
85- {
71+ #[ derive( Default ) ]
72+ struct StyleChecker {
8673 state : State ,
8774 // FIXME: see StyleChecker::set_state
8875 _s_macros : usize ,
8976 f_macros : usize ,
90- on_err : F ,
77+ errors : Vec < FileError > ,
78+ /// Path of the currently active file
79+ path : PathBuf ,
9180}
9281
93- #[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
82+ #[ derive( Default , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
9483enum State {
84+ #[ default]
9585 Start ,
9686 Imports ,
9787 Typedefs ,
@@ -115,24 +105,49 @@ enum ExprCfgElse {
115105 If ( ExprCfgIf ) ,
116106}
117107
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 ( ( ) ) ;
128137 }
138+
139+ for error in self . errors {
140+ eprintln ! ( "{error}" ) ;
141+ }
142+
143+ Err ( "some tests failed" . into ( ) )
129144 }
130145
131146 fn set_state ( & mut self , new_state : State , line : usize ) {
132147 if self . state > new_state {
133- ( self . on_err ) (
148+ self . error (
134149 line,
135- & format ! (
150+ format ! (
136151 "{} found after {} when it belongs before" ,
137152 new_state. desc( ) ,
138153 self . state. desc( )
@@ -142,7 +157,7 @@ where
142157
143158 if self . f_macros == 2 {
144159 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 ( ) ) ;
146161 }
147162
148163 // FIXME(#4109): multiple should be allowed if at least one is `cfg(not) within `cfg_if`.
@@ -177,24 +192,32 @@ where
177192 }
178193 self . state = initial_state;
179194 }
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+ }
180203}
181204
182- impl < ' ast , F > Visit < ' ast > for StyleChecker < F >
183- where
184- F : FnMut ( usize , & str ) ,
185- {
205+ impl < ' ast > Visit < ' ast > for StyleChecker {
186206 fn visit_meta_list ( & mut self , meta_list : & ' ast syn:: MetaList ) {
187207 let line = meta_list. span ( ) . start ( ) . line ;
188208 let meta_str = meta_list. tokens . to_string ( ) ;
189209 if meta_list. path . is_ident ( "cfg" )
190210 && !( meta_str. contains ( "target_endian" ) || meta_str. contains ( "target_arch" ) )
191211 && self . state != State :: Structs
192212 {
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+ ) ;
194217 } else if meta_list. path . is_ident ( "derive" )
195218 && ( meta_str. contains ( "Copy" ) || meta_str. contains ( "Clone" ) )
196219 {
197- ( self . on_err ) ( line, "impl Copy and Clone manually" ) ;
220+ self . error ( line, "impl Copy and Clone manually" . to_string ( ) ) ;
198221 }
199222
200223 visit:: visit_meta_list ( self , meta_list) ;
@@ -330,9 +353,17 @@ impl State {
330353 }
331354}
332355
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)
337366 }
338367}
368+
369+ impl std:: error:: Error for FileError { }
0 commit comments