@@ -5,19 +5,19 @@ use std::{
55 env:: { consts:: OS , current_dir} ,
66 fs,
77 path:: PathBuf ,
8- process:: Command ,
9- sync:: { Arc , Mutex , MutexGuard } ,
8+ sync:: { Arc , Mutex } ,
109} ;
1110
1211// non-std crates
13- use anyhow:: { Context , Result } ;
12+ use anyhow:: { Context , Result , anyhow } ;
1413use regex:: Regex ;
1514use serde:: Deserialize ;
15+ use tokio:: process:: Command ;
1616
1717// project-specific modules/crates
1818use super :: MakeSuggestions ;
1919use crate :: {
20- cli:: { ClangParams , LinesChangedOnly } ,
20+ cli:: ClangParams ,
2121 common_fs:: { FileObj , normalize_path} ,
2222} ;
2323
@@ -247,23 +247,26 @@ pub fn tally_tidy_advice(files: &[Arc<Mutex<FileObj>>]) -> u64 {
247247}
248248
249249/// Run clang-tidy, then parse and return it's output.
250- pub fn run_clang_tidy (
251- file : & mut MutexGuard < FileObj > ,
250+ pub async fn run_clang_tidy (
251+ file : & Arc < Mutex < FileObj > > ,
252252 clang_params : & ClangParams ,
253253) -> Result < Vec < ( log:: Level , std:: string:: String ) > > {
254- let mut cmd = Command :: new ( clang_params. clang_tidy_command . as_ref ( ) . unwrap ( ) ) ;
255254 let mut logs = vec ! [ ] ;
256- if !clang_params. tidy_checks . is_empty ( ) {
257- cmd. args ( [ "-checks" , & clang_params. tidy_checks ] ) ;
258- }
259- if let Some ( db) = & clang_params. database {
260- cmd. args ( [ "-p" , & db. to_string_lossy ( ) ] ) ;
261- }
262- for arg in & clang_params. extra_args {
263- cmd. args ( [ "--extra-arg" , format ! ( "\" {}\" " , arg) . as_str ( ) ] ) ;
264- }
265- let file_name = file. name . to_string_lossy ( ) . to_string ( ) ;
266- if clang_params. lines_changed_only != LinesChangedOnly :: Off {
255+ let ( file_name, mut args) = {
256+ let mut args = vec ! [ ] ;
257+ let file = file
258+ . lock ( )
259+ . map_err ( |e| anyhow ! ( "Failed to lock mutex: {e:?}" ) ) ?;
260+ let file_name = file. name . to_string_lossy ( ) . to_string ( ) ;
261+ if !clang_params. tidy_checks . is_empty ( ) {
262+ args. extend ( [ "-checks" . to_string ( ) , clang_params. tidy_checks . to_owned ( ) ] ) ;
263+ }
264+ if let Some ( db) = & clang_params. database {
265+ args. extend ( [ "-p" . to_string ( ) , db. to_string_lossy ( ) . to_string ( ) ] ) ;
266+ }
267+ for arg in & clang_params. extra_args {
268+ args. extend ( [ "--extra-arg" . to_string ( ) , format ! ( "\" {}\" " , arg) ] ) ;
269+ }
267270 let ranges = file. get_ranges ( & clang_params. lines_changed_only ) ;
268271 if !ranges. is_empty ( ) {
269272 let filter = format ! (
@@ -274,36 +277,40 @@ pub fn run_clang_tidy(
274277 . map( |r| [ r. start( ) , r. end( ) ] )
275278 . collect:: <Vec <_>>( )
276279 ) ;
277- cmd . args ( [ "--line-filter" , filter . as_str ( ) ] ) ;
280+ args. extend ( [ "--line-filter" . to_string ( ) , filter ] ) ;
278281 }
279- }
282+ ( file_name, args)
283+ } ;
280284 let original_content = if !clang_params. tidy_review {
281285 None
282286 } else {
283- cmd . arg ( "--fix-errors" ) ;
284- Some ( fs:: read_to_string ( & file . name ) . with_context ( || {
287+ args . push ( "--fix-errors" . to_string ( ) ) ;
288+ Some ( fs:: read_to_string ( & file_name ) . with_context ( || {
285289 format ! (
286290 "Failed to cache file's original content before applying clang-tidy changes: {}" ,
287291 file_name. clone( )
288292 )
289293 } ) ?)
290294 } ;
291295 if !clang_params. style . is_empty ( ) {
292- cmd . args ( [ "--format-style" , clang_params. style . as_str ( ) ] ) ;
296+ args. extend ( [ "--format-style" . to_string ( ) , clang_params. style . to_owned ( ) ] ) ;
293297 }
294- cmd. arg ( file. name . to_string_lossy ( ) . as_ref ( ) ) ;
298+ args. push ( file_name. clone ( ) ) ;
299+ let program = clang_params. clang_tidy_command . as_ref ( ) . unwrap ( ) ;
300+ let mut cmd = Command :: new ( program) ;
301+ cmd. args ( & args) ;
295302 logs. push ( (
296303 log:: Level :: Info ,
297304 format ! (
298305 "Running \" {} {}\" " ,
299- cmd. get_program( ) . to_string_lossy( ) ,
300- cmd. get_args( )
301- . map( |x| x. to_string_lossy( ) )
302- . collect:: <Vec <_>>( )
303- . join( " " )
306+ program. to_string_lossy( ) ,
307+ args. join( " " )
304308 ) ,
305309 ) ) ;
306- let output = cmd. output ( ) . unwrap ( ) ;
310+ let output = cmd
311+ . output ( )
312+ . await
313+ . with_context ( || format ! ( "Failed to run clang-tidy on file: {}" , file_name. clone( ) ) ) ?;
307314 logs. push ( (
308315 log:: Level :: Debug ,
309316 format ! (
@@ -320,22 +327,23 @@ pub fn run_clang_tidy(
320327 ) ,
321328 ) ) ;
322329 }
323- file. tidy_advice = Some ( parse_tidy_output (
324- & output. stdout ,
325- & clang_params. database_json ,
326- ) ?) ;
330+ let mut tidy_advice = parse_tidy_output ( & output. stdout , & clang_params. database_json ) ?;
327331 if clang_params. tidy_review {
328- if let Some ( tidy_advice) = & mut file. tidy_advice {
329- // cache file changes in a buffer and restore the original contents for further analysis
330- tidy_advice. patched =
331- Some ( fs:: read ( & file_name) . with_context ( || {
332- format ! ( "Failed to read changes from clang-tidy: {file_name}" )
333- } ) ?) ;
334- }
332+ // cache file changes in a buffer and restore the original contents for further analysis
333+ tidy_advice. patched = Some (
334+ fs:: read ( & file_name)
335+ . with_context ( || format ! ( "Failed to read changes from clang-tidy: {file_name}" ) ) ?,
336+ ) ;
335337 // original_content is guaranteed to be Some() value at this point
336338 fs:: write ( & file_name, original_content. unwrap ( ) )
337339 . with_context ( || format ! ( "Failed to restore file's original content: {file_name}" ) ) ?;
338340 }
341+ {
342+ let mut file = file
343+ . lock ( )
344+ . map_err ( |e| anyhow ! ( "Failed to lock mutex: {e:?}" ) ) ?;
345+ file. tidy_advice = Some ( tidy_advice) ;
346+ }
339347 Ok ( logs)
340348}
341349
@@ -418,8 +426,8 @@ mod test {
418426 )
419427 }
420428
421- #[ test]
422- fn use_extra_args ( ) {
429+ #[ tokio :: test]
430+ async fn use_extra_args ( ) {
423431 let exe_path = ClangTool :: ClangTidy
424432 . get_exe_path (
425433 & RequestedVersion :: from_str (
@@ -429,7 +437,7 @@ mod test {
429437 )
430438 . unwrap ( ) ;
431439 let file = FileObj :: new ( PathBuf :: from ( "tests/demo/demo.cpp" ) ) ;
432- let arc_ref = Arc :: new ( Mutex :: new ( file) ) ;
440+ let arc_file = Arc :: new ( Mutex :: new ( file) ) ;
433441 let extra_args = vec ! [ "-std=c++17" . to_string( ) , "-Wall" . to_string( ) ] ;
434442 let clang_params = ClangParams {
435443 style : "" . to_string ( ) ,
@@ -445,8 +453,8 @@ mod test {
445453 clang_tidy_command : Some ( exe_path) ,
446454 clang_format_command : None ,
447455 } ;
448- let mut file_lock = arc_ref . lock ( ) . unwrap ( ) ;
449- let logs = run_clang_tidy ( & mut file_lock , & clang_params )
456+ let logs = run_clang_tidy ( & arc_file , & clang_params )
457+ . await
450458 . unwrap ( )
451459 . into_iter ( )
452460 . filter_map ( |( _lvl, msg) | {
0 commit comments