@@ -12,7 +12,7 @@ use std::process::Command;
1212use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
1313use std:: { collections:: HashMap , io:: ErrorKind } ;
1414use std:: {
15- env, fmt ,
15+ env,
1616 fs:: write,
1717 path:: { Path , PathBuf } ,
1818 thread,
@@ -101,13 +101,28 @@ struct ClippyWarning {
101101 is_ice : bool ,
102102}
103103
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+ }
111126 }
112127}
113128
@@ -378,6 +393,8 @@ struct LintcheckConfig {
378393 fix : bool ,
379394 /// A list of lint that this lintcheck run shound focus on
380395 lint_filter : Vec < String > ,
396+ /// Indicate if the output should support markdown syntax
397+ markdown : bool ,
381398}
382399
383400impl LintcheckConfig {
@@ -393,12 +410,17 @@ impl LintcheckConfig {
393410 . to_string ( )
394411 } ) ;
395412
413+ let markdown = clap_config. is_present ( "markdown" ) ;
396414 let sources_toml_path = PathBuf :: from ( sources_toml) ;
397415
398416 // for the path where we save the lint results, get the filename without extension (so for
399417 // wasd.toml, use "wasd"...)
400418 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+ ) ) ;
402424
403425 // look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
404426 // use half of that for the physical core count
@@ -440,6 +462,7 @@ impl LintcheckConfig {
440462 lintcheck_results_path,
441463 fix,
442464 lint_filter,
465+ markdown,
443466 }
444467 }
445468}
@@ -601,10 +624,15 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
601624 // to not have a lint with 200 and 2 warnings take the same spot
602625 stats. sort_by_key ( |( lint, count) | format ! ( "{:0>4}, {}" , count, lint) ) ;
603626
627+ let mut header = String :: from ( "| lint | count |\n " ) ;
628+ header. push_str ( "| -------------------------------------------------- | ----- |\n " ) ;
604629 let stats_string = stats
605630 . 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+ } ) ;
608636
609637 ( stats_string, counter)
610638}
@@ -802,15 +830,23 @@ pub fn main() {
802830 . map ( |w| ( & w. crate_name , & w. message ) )
803831 . collect ( ) ;
804832
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 ( ) ;
806837 all_msgs. sort ( ) ;
807- all_msgs. push ( "\n \n \n \n Stats: \n " . into ( ) ) ;
838+ all_msgs. push ( "\n \n ### Stats: \n \n " . into ( ) ) ;
808839 all_msgs. push ( stats_formatted) ;
809840
810841 // save the text into lintcheck-logs/logs.txt
811842 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 " ) ;
814850 ices. iter ( )
815851 . for_each ( |( cratename, msg) | text. push_str ( & format ! ( "{}: '{}'" , cratename, msg) ) ) ;
816852
@@ -832,20 +868,21 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
832868
833869 let lines: Vec < String > = file_content. lines ( ) . map ( ToString :: to_string) . collect ( ) ;
834870
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
842872 . 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+ }
849886 } )
850887 . collect :: < HashMap < String , usize > > ( )
851888}
@@ -957,6 +994,11 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
957994 . value_name ( "clippy_lint_name" )
958995 . help ( "apply a filter to only collect specified lints, this also overrides `allow` attributes" ) ,
959996 )
997+ . arg (
998+ Arg :: with_name ( "markdown" )
999+ . long ( "--markdown" )
1000+ . help ( "change the reports table to use markdown links" ) ,
1001+ )
9601002 . get_matches ( )
9611003}
9621004
0 commit comments