@@ -9,6 +9,7 @@ use std::{
99 sync:: { Arc , Mutex , MutexGuard } ,
1010} ;
1111
12+ use anyhow:: { Context , Result } ;
1213// non-std crates
1314use regex:: Regex ;
1415use serde:: Deserialize ;
@@ -132,7 +133,7 @@ impl MakeSuggestions for TidyAdvice {
132133fn parse_tidy_output (
133134 tidy_stdout : & [ u8 ] ,
134135 database_json : & Option < Vec < CompilationUnit > > ,
135- ) -> Option < TidyAdvice > {
136+ ) -> Result < Option < TidyAdvice > > {
136137 let note_header = Regex :: new ( r"^(.+):(\d+):(\d+):\s(\w+):(.*)\[([a-zA-Z\d\-\.]+)\]$" ) . unwrap ( ) ;
137138 let fixed_note =
138139 Regex :: new ( r"^.+:(\d+):\d+:\snote: FIX-IT applied suggested code changes$" ) . unwrap ( ) ;
@@ -178,14 +179,15 @@ fn parse_tidy_output(
178179 // likely not a member of the project's sources (ie /usr/include/stdio.h)
179180 filename = filename
180181 . strip_prefix ( & cur_dir)
181- . expect ( "cannot determine filename by relative path." )
182+ // we already checked above that filename.starts_with(current_directory)
183+ . unwrap ( )
182184 . to_path_buf ( ) ;
183185 }
184186
185187 notification = Some ( TidyNotification {
186188 filename : filename. to_string_lossy ( ) . to_string ( ) . replace ( '\\' , "/" ) ,
187- line : captured[ 2 ] . parse :: < u32 > ( ) . unwrap ( ) ,
188- cols : captured[ 3 ] . parse :: < u32 > ( ) . unwrap ( ) ,
189+ line : captured[ 2 ] . parse ( ) ? ,
190+ cols : captured[ 3 ] . parse ( ) ? ,
189191 severity : String :: from ( & captured[ 4 ] ) ,
190192 rationale : String :: from ( & captured[ 5 ] ) . trim ( ) . to_string ( ) ,
191193 diagnostic : String :: from ( & captured[ 6 ] ) ,
@@ -195,9 +197,7 @@ fn parse_tidy_output(
195197 // begin capturing subsequent lines as suggestions
196198 found_fix = false ;
197199 } else if let Some ( capture) = fixed_note. captures ( line) {
198- let fixed_line = capture[ 1 ]
199- . parse ( )
200- . expect ( "Failed to parse fixed line number's string as integer" ) ;
200+ let fixed_line = capture[ 1 ] . parse ( ) ?;
201201 if let Some ( note) = & mut notification {
202202 if !note. fixed_lines . contains ( & fixed_line) {
203203 note. fixed_lines . push ( fixed_line) ;
@@ -219,12 +219,12 @@ fn parse_tidy_output(
219219 result. push ( note) ;
220220 }
221221 if result. is_empty ( ) {
222- None
222+ Ok ( None )
223223 } else {
224- Some ( TidyAdvice {
224+ Ok ( Some ( TidyAdvice {
225225 notes : result,
226226 patched : None ,
227- } )
227+ } ) )
228228 }
229229}
230230
@@ -249,7 +249,7 @@ pub fn tally_tidy_advice(files: &[Arc<Mutex<FileObj>>]) -> u64 {
249249pub fn run_clang_tidy (
250250 file : & mut MutexGuard < FileObj > ,
251251 clang_params : & ClangParams ,
252- ) -> Vec < ( log:: Level , std:: string:: String ) > {
252+ ) -> Result < Vec < ( log:: Level , std:: string:: String ) > > {
253253 let mut cmd = Command :: new ( clang_params. clang_tidy_command . as_ref ( ) . unwrap ( ) ) ;
254254 let mut logs = vec ! [ ] ;
255255 if !clang_params. tidy_checks . is_empty ( ) {
@@ -258,19 +258,15 @@ pub fn run_clang_tidy(
258258 if let Some ( db) = & clang_params. database {
259259 cmd. args ( [ "-p" , & db. to_string_lossy ( ) ] ) ;
260260 }
261- if let Some ( extras) = & clang_params. extra_args {
262- for arg in extras {
263- cmd. args ( [ "--extra-arg" , format ! ( "\" {}\" " , arg) . as_str ( ) ] ) ;
264- }
261+ for arg in & clang_params. extra_args {
262+ cmd. args ( [ "--extra-arg" , format ! ( "\" {}\" " , arg) . as_str ( ) ] ) ;
265263 }
264+ let file_name = file. name . to_string_lossy ( ) . to_string ( ) ;
266265 if clang_params. lines_changed_only != LinesChangedOnly :: Off {
267266 let ranges = file. get_ranges ( & clang_params. lines_changed_only ) ;
268267 let filter = format ! (
269268 "[{{\" name\" :{:?},\" lines\" :{:?}}}]" ,
270- & file
271- . name
272- . to_string_lossy( )
273- . replace( '/' , if OS == "windows" { "\\ " } else { "/" } ) ,
269+ & file_name. replace( '/' , if OS == "windows" { "\\ " } else { "/" } ) ,
274270 ranges
275271 . iter( )
276272 . map( |r| [ r. start( ) , r. end( ) ] )
@@ -281,10 +277,12 @@ pub fn run_clang_tidy(
281277 let mut original_content = None ;
282278 if clang_params. tidy_review {
283279 cmd. arg ( "--fix-errors" ) ;
284- original_content =
285- Some ( fs:: read_to_string ( & file. name ) . expect (
286- "Failed to cache file's original content before applying clang-tidy changes." ,
287- ) ) ;
280+ original_content = Some ( fs:: read_to_string ( & file. name ) . with_context ( || {
281+ format ! (
282+ "Failed to cache file's original content before applying clang-tidy changes: {}" ,
283+ file_name. clone( )
284+ )
285+ } ) ?) ;
288286 }
289287 if !clang_params. style . is_empty ( ) {
290288 cmd. args ( [ "--format-style" , clang_params. style . as_str ( ) ] ) ;
@@ -310,29 +308,32 @@ pub fn run_clang_tidy(
310308 ) ,
311309 ) ) ;
312310 if !output. stderr . is_empty ( ) {
313- logs. push ( (
314- log:: Level :: Debug ,
315- format ! (
316- "clang-tidy made the following summary:\n {}" ,
317- String :: from_utf8( output. stderr) . unwrap( )
318- ) ,
319- ) ) ;
311+ if let Ok ( stderr) = String :: from_utf8 ( output. stderr ) {
312+ logs. push ( (
313+ log:: Level :: Debug ,
314+ format ! ( "clang-tidy made the following summary:\n {}" , stderr) ,
315+ ) ) ;
316+ } else {
317+ logs. push ( (
318+ log:: Level :: Error ,
319+ "clang-tidy stderr is not UTF-8 encoded" . to_string ( ) ,
320+ ) ) ;
321+ }
320322 }
321- file. tidy_advice = parse_tidy_output ( & output. stdout , & clang_params. database_json ) ;
323+ file. tidy_advice = parse_tidy_output ( & output. stdout , & clang_params. database_json ) ? ;
322324 if clang_params. tidy_review {
323- let file_name = & file. name . to_owned ( ) ;
324325 if let Some ( tidy_advice) = & mut file. tidy_advice {
325326 // cache file changes in a buffer and restore the original contents for further analysis by clang-format
326327 tidy_advice. patched =
327- Some ( fs:: read ( file_name) . expect ( "Failed to read changes from clang-tidy" ) ) ;
328+ Some ( fs:: read ( & file_name) . with_context ( || {
329+ format ! ( "Failed to read changes from clang-tidy: {file_name}" )
330+ } ) ?) ;
328331 }
329- fs:: write (
330- file_name,
331- original_content. expect ( "original content of file was not cached" ) ,
332- )
333- . expect ( "failed to restore file's original content." ) ;
332+ // original_content is guaranteed to be Some() value at this point
333+ fs:: write ( & file_name, original_content. unwrap ( ) )
334+ . with_context ( || format ! ( "Failed to restore file's original content: {file_name}" ) ) ?;
334335 }
335- logs
336+ Ok ( logs)
336337}
337338
338339#[ cfg( test) ]
@@ -427,7 +428,7 @@ mod test {
427428 tidy_checks : "" . to_string ( ) , // use .clang-tidy config file
428429 lines_changed_only : LinesChangedOnly :: Off ,
429430 database : None ,
430- extra_args : Some ( extra_args. clone ( ) ) , // <---- the reason for this test
431+ extra_args : extra_args. clone ( ) , // <---- the reason for this test
431432 database_json : None ,
432433 format_filter : None ,
433434 tidy_filter : None ,
@@ -438,6 +439,7 @@ mod test {
438439 } ;
439440 let mut file_lock = arc_ref. lock ( ) . unwrap ( ) ;
440441 let logs = run_clang_tidy ( & mut file_lock, & clang_params)
442+ . unwrap ( )
441443 . into_iter ( )
442444 . filter_map ( |( _lvl, msg) | {
443445 if msg. contains ( "Running " ) {
0 commit comments