@@ -12,7 +12,7 @@ use std::process::Command;
12
12
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
13
13
use std:: { collections:: HashMap , io:: ErrorKind } ;
14
14
use std:: {
15
- env, fmt ,
15
+ env,
16
16
fs:: write,
17
17
path:: { Path , PathBuf } ,
18
18
thread,
@@ -101,13 +101,28 @@ struct ClippyWarning {
101
101
is_ice : bool ,
102
102
}
103
103
104
- impl std:: fmt:: Display for ClippyWarning {
105
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
106
- writeln ! (
107
- f,
108
- r#"target/lintcheck/sources/{}-{}/{}:{}:{} {} "{}""# ,
109
- & self . crate_name, & self . crate_version, & self . file, & self . line, & self . column, & self . linttype, & self . message
110
- )
104
+ #[ allow( unused) ]
105
+ impl ClippyWarning {
106
+ fn to_output ( & self , markdown : bool ) -> String {
107
+ let file = format ! ( "{}-{}/{}" , & self . crate_name, & self . crate_version, & self . file) ;
108
+ let file_with_pos = format ! ( "{}:{}:{}" , & file, & self . line, & self . column) ;
109
+ if markdown {
110
+ let lint = format ! ( "`{}`" , self . linttype) ;
111
+
112
+ let mut output = String :: from ( "| " ) ;
113
+ output. push_str ( & format ! (
114
+ "[`{}`](../target/lintcheck/sources/{}#L{})" ,
115
+ file_with_pos, file, self . line
116
+ ) ) ;
117
+ output. push_str ( & format ! ( r#" | {:<50} | "{}" |"# , lint, self . message) ) ;
118
+ output. push ( '\n' ) ;
119
+ output
120
+ } else {
121
+ format ! (
122
+ "target/lintcheck/sources/{} {} \" {}\" \n " ,
123
+ file_with_pos, self . linttype, self . message
124
+ )
125
+ }
111
126
}
112
127
}
113
128
@@ -378,6 +393,8 @@ struct LintcheckConfig {
378
393
fix : bool ,
379
394
/// A list of lint that this lintcheck run shound focus on
380
395
lint_filter : Vec < String > ,
396
+ /// Indicate if the output should support markdown syntax
397
+ markdown : bool ,
381
398
}
382
399
383
400
impl LintcheckConfig {
@@ -393,12 +410,17 @@ impl LintcheckConfig {
393
410
. to_string ( )
394
411
} ) ;
395
412
413
+ let markdown = clap_config. is_present ( "markdown" ) ;
396
414
let sources_toml_path = PathBuf :: from ( sources_toml) ;
397
415
398
416
// for the path where we save the lint results, get the filename without extension (so for
399
417
// wasd.toml, use "wasd"...)
400
418
let filename: PathBuf = sources_toml_path. file_stem ( ) . unwrap ( ) . into ( ) ;
401
- let lintcheck_results_path = PathBuf :: from ( format ! ( "lintcheck-logs/{}_logs.txt" , filename. display( ) ) ) ;
419
+ let lintcheck_results_path = PathBuf :: from ( format ! (
420
+ "lintcheck-logs/{}_logs.{}" ,
421
+ filename. display( ) ,
422
+ if markdown { "md" } else { "txt" }
423
+ ) ) ;
402
424
403
425
// look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
404
426
// use half of that for the physical core count
@@ -440,6 +462,7 @@ impl LintcheckConfig {
440
462
lintcheck_results_path,
441
463
fix,
442
464
lint_filter,
465
+ markdown,
443
466
}
444
467
}
445
468
}
@@ -601,10 +624,15 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
601
624
// to not have a lint with 200 and 2 warnings take the same spot
602
625
stats. sort_by_key ( |( lint, count) | format ! ( "{:0>4}, {}" , count, lint) ) ;
603
626
627
+ let mut header = String :: from ( "| lint | count |\n " ) ;
628
+ header. push_str ( "| -------------------------------------------------- | ----- |\n " ) ;
604
629
let stats_string = stats
605
630
. iter ( )
606
- . map ( |( lint, count) | format ! ( "{} {}\n " , lint, count) )
607
- . collect :: < String > ( ) ;
631
+ . map ( |( lint, count) | format ! ( "| {:<50} | {:>4} |\n " , lint, count) )
632
+ . fold ( header, |mut table, line| {
633
+ table. push_str ( & line) ;
634
+ table
635
+ } ) ;
608
636
609
637
( stats_string, counter)
610
638
}
@@ -802,15 +830,23 @@ pub fn main() {
802
830
. map ( |w| ( & w. crate_name , & w. message ) )
803
831
. collect ( ) ;
804
832
805
- let mut all_msgs: Vec < String > = clippy_warnings. iter ( ) . map ( ToString :: to_string) . collect ( ) ;
833
+ let mut all_msgs: Vec < String > = clippy_warnings
834
+ . iter ( )
835
+ . map ( |warn| warn. to_output ( config. markdown ) )
836
+ . collect ( ) ;
806
837
all_msgs. sort ( ) ;
807
- all_msgs. push ( "\n \n \n \n Stats: \n " . into ( ) ) ;
838
+ all_msgs. push ( "\n \n ### Stats: \n \n " . into ( ) ) ;
808
839
all_msgs. push ( stats_formatted) ;
809
840
810
841
// save the text into lintcheck-logs/logs.txt
811
842
let mut text = clippy_ver; // clippy version number on top
812
- text. push_str ( & format ! ( "\n {}" , all_msgs. join( "" ) ) ) ;
813
- text. push_str ( "ICEs:\n " ) ;
843
+ text. push_str ( "\n ### Reports\n \n " ) ;
844
+ if config. markdown {
845
+ text. push_str ( "| file | lint | message |\n " ) ;
846
+ text. push_str ( "| --- | --- | --- |\n " ) ;
847
+ }
848
+ text. push_str ( & format ! ( "{}" , all_msgs. join( "" ) ) ) ;
849
+ text. push_str ( "\n \n ### ICEs:\n " ) ;
814
850
ices. iter ( )
815
851
. for_each ( |( cratename, msg) | text. push_str ( & format ! ( "{}: '{}'" , cratename, msg) ) ) ;
816
852
@@ -832,20 +868,21 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
832
868
833
869
let lines: Vec < String > = file_content. lines ( ) . map ( ToString :: to_string) . collect ( ) ;
834
870
835
- // search for the beginning "Stats:" and the end "ICEs:" of the section we want
836
- let start = lines. iter ( ) . position ( |line| line == "Stats:" ) . unwrap ( ) ;
837
- let end = lines. iter ( ) . position ( |line| line == "ICEs:" ) . unwrap ( ) ;
838
-
839
- let stats_lines = & lines[ start + 1 ..end] ;
840
-
841
- stats_lines
871
+ lines
842
872
. iter ( )
843
- . map ( |line| {
844
- let mut spl = line. split ( ' ' ) ;
845
- (
846
- spl. next ( ) . unwrap ( ) . to_string ( ) ,
847
- spl. next ( ) . unwrap ( ) . parse :: < usize > ( ) . unwrap ( ) ,
848
- )
873
+ . skip_while ( |line| line. as_str ( ) != "### Stats:" )
874
+ // Skipping the table header and the `Stats:` label
875
+ . skip ( 4 )
876
+ . take_while ( |line| line. starts_with ( "| " ) )
877
+ . filter_map ( |line| {
878
+ let mut spl = line. split ( '|' ) ;
879
+ // Skip the first `|` symbol
880
+ spl. next ( ) ;
881
+ if let ( Some ( lint) , Some ( count) ) = ( spl. next ( ) , spl. next ( ) ) {
882
+ Some ( ( lint. trim ( ) . to_string ( ) , count. trim ( ) . parse :: < usize > ( ) . unwrap ( ) ) )
883
+ } else {
884
+ None
885
+ }
849
886
} )
850
887
. collect :: < HashMap < String , usize > > ( )
851
888
}
@@ -957,6 +994,11 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
957
994
. value_name ( "clippy_lint_name" )
958
995
. help ( "apply a filter to only collect specified lints, this also overrides `allow` attributes" ) ,
959
996
)
997
+ . arg (
998
+ Arg :: with_name ( "markdown" )
999
+ . long ( "--markdown" )
1000
+ . help ( "change the reports table to use markdown links" ) ,
1001
+ )
960
1002
. get_matches ( )
961
1003
}
962
1004
0 commit comments