@@ -9,6 +9,7 @@ use std::{
9
9
sync:: { Arc , Mutex , MutexGuard } ,
10
10
} ;
11
11
12
+ use anyhow:: { Context , Result } ;
12
13
// non-std crates
13
14
use regex:: Regex ;
14
15
use serde:: Deserialize ;
@@ -132,7 +133,7 @@ impl MakeSuggestions for TidyAdvice {
132
133
fn parse_tidy_output (
133
134
tidy_stdout : & [ u8 ] ,
134
135
database_json : & Option < Vec < CompilationUnit > > ,
135
- ) -> Option < TidyAdvice > {
136
+ ) -> Result < Option < TidyAdvice > > {
136
137
let note_header = Regex :: new ( r"^(.+):(\d+):(\d+):\s(\w+):(.*)\[([a-zA-Z\d\-\.]+)\]$" ) . unwrap ( ) ;
137
138
let fixed_note =
138
139
Regex :: new ( r"^.+:(\d+):\d+:\snote: FIX-IT applied suggested code changes$" ) . unwrap ( ) ;
@@ -178,14 +179,15 @@ fn parse_tidy_output(
178
179
// likely not a member of the project's sources (ie /usr/include/stdio.h)
179
180
filename = filename
180
181
. 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 ( )
182
184
. to_path_buf ( ) ;
183
185
}
184
186
185
187
notification = Some ( TidyNotification {
186
188
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 ( ) ? ,
189
191
severity : String :: from ( & captured[ 4 ] ) ,
190
192
rationale : String :: from ( & captured[ 5 ] ) . trim ( ) . to_string ( ) ,
191
193
diagnostic : String :: from ( & captured[ 6 ] ) ,
@@ -195,9 +197,7 @@ fn parse_tidy_output(
195
197
// begin capturing subsequent lines as suggestions
196
198
found_fix = false ;
197
199
} 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 ( ) ?;
201
201
if let Some ( note) = & mut notification {
202
202
if !note. fixed_lines . contains ( & fixed_line) {
203
203
note. fixed_lines . push ( fixed_line) ;
@@ -219,12 +219,12 @@ fn parse_tidy_output(
219
219
result. push ( note) ;
220
220
}
221
221
if result. is_empty ( ) {
222
- None
222
+ Ok ( None )
223
223
} else {
224
- Some ( TidyAdvice {
224
+ Ok ( Some ( TidyAdvice {
225
225
notes : result,
226
226
patched : None ,
227
- } )
227
+ } ) )
228
228
}
229
229
}
230
230
@@ -249,7 +249,7 @@ pub fn tally_tidy_advice(files: &[Arc<Mutex<FileObj>>]) -> u64 {
249
249
pub fn run_clang_tidy (
250
250
file : & mut MutexGuard < FileObj > ,
251
251
clang_params : & ClangParams ,
252
- ) -> Vec < ( log:: Level , std:: string:: String ) > {
252
+ ) -> Result < Vec < ( log:: Level , std:: string:: String ) > > {
253
253
let mut cmd = Command :: new ( clang_params. clang_tidy_command . as_ref ( ) . unwrap ( ) ) ;
254
254
let mut logs = vec ! [ ] ;
255
255
if !clang_params. tidy_checks . is_empty ( ) {
@@ -258,19 +258,15 @@ pub fn run_clang_tidy(
258
258
if let Some ( db) = & clang_params. database {
259
259
cmd. args ( [ "-p" , & db. to_string_lossy ( ) ] ) ;
260
260
}
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 ( ) ] ) ;
265
263
}
264
+ let file_name = file. name . to_string_lossy ( ) . to_string ( ) ;
266
265
if clang_params. lines_changed_only != LinesChangedOnly :: Off {
267
266
let ranges = file. get_ranges ( & clang_params. lines_changed_only ) ;
268
267
let filter = format ! (
269
268
"[{{\" name\" :{:?},\" lines\" :{:?}}}]" ,
270
- & file
271
- . name
272
- . to_string_lossy( )
273
- . replace( '/' , if OS == "windows" { "\\ " } else { "/" } ) ,
269
+ & file_name. replace( '/' , if OS == "windows" { "\\ " } else { "/" } ) ,
274
270
ranges
275
271
. iter( )
276
272
. map( |r| [ r. start( ) , r. end( ) ] )
@@ -281,10 +277,12 @@ pub fn run_clang_tidy(
281
277
let mut original_content = None ;
282
278
if clang_params. tidy_review {
283
279
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
+ } ) ?) ;
288
286
}
289
287
if !clang_params. style . is_empty ( ) {
290
288
cmd. args ( [ "--format-style" , clang_params. style . as_str ( ) ] ) ;
@@ -310,29 +308,32 @@ pub fn run_clang_tidy(
310
308
) ,
311
309
) ) ;
312
310
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
+ }
320
322
}
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 ) ? ;
322
324
if clang_params. tidy_review {
323
- let file_name = & file. name . to_owned ( ) ;
324
325
if let Some ( tidy_advice) = & mut file. tidy_advice {
325
326
// cache file changes in a buffer and restore the original contents for further analysis by clang-format
326
327
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
+ } ) ?) ;
328
331
}
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}" ) ) ?;
334
335
}
335
- logs
336
+ Ok ( logs)
336
337
}
337
338
338
339
#[ cfg( test) ]
@@ -427,7 +428,7 @@ mod test {
427
428
tidy_checks : "" . to_string ( ) , // use .clang-tidy config file
428
429
lines_changed_only : LinesChangedOnly :: Off ,
429
430
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
431
432
database_json : None ,
432
433
format_filter : None ,
433
434
tidy_filter : None ,
@@ -438,6 +439,7 @@ mod test {
438
439
} ;
439
440
let mut file_lock = arc_ref. lock ( ) . unwrap ( ) ;
440
441
let logs = run_clang_tidy ( & mut file_lock, & clang_params)
442
+ . unwrap ( )
441
443
. into_iter ( )
442
444
. filter_map ( |( _lvl, msg) | {
443
445
if msg. contains ( "Running " ) {
0 commit comments