1- use crate :: Lint ;
1+ use crate :: { Lint , LintExtractor } ;
22use std:: collections:: { BTreeMap , BTreeSet } ;
33use std:: error:: Error ;
44use std:: fmt:: Write ;
55use std:: fs;
6- use std:: path:: Path ;
76use std:: process:: Command ;
87
8+ /// Descriptions of rustc lint groups.
99static GROUP_DESCRIPTIONS : & [ ( & str , & str ) ] = & [
1010 ( "unused" , "Lints that detect things being declared but not used, or excess syntax" ) ,
1111 ( "rustdoc" , "Rustdoc-specific lints" ) ,
@@ -15,100 +15,123 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
1515 ( "rust-2018-compatibility" , "Lints used to transition code from the 2015 edition to 2018" ) ,
1616] ;
1717
18- /// Updates the documentation of lint groups.
19- pub ( crate ) fn generate_group_docs (
20- lints : & [ Lint ] ,
21- rustc : crate :: Rustc < ' _ > ,
22- out_path : & Path ,
23- ) -> Result < ( ) , Box < dyn Error > > {
24- let groups = collect_groups ( rustc) ?;
25- let groups_path = out_path. join ( "groups.md" ) ;
26- let contents = fs:: read_to_string ( & groups_path)
27- . map_err ( |e| format ! ( "could not read {}: {}" , groups_path. display( ) , e) ) ?;
28- let new_contents = contents. replace ( "{{groups-table}}" , & make_groups_table ( lints, & groups) ?) ;
29- // Delete the output because rustbuild uses hard links in its copies.
30- let _ = fs:: remove_file ( & groups_path) ;
31- fs:: write ( & groups_path, new_contents)
32- . map_err ( |e| format ! ( "could not write to {}: {}" , groups_path. display( ) , e) ) ?;
33- Ok ( ( ) )
34- }
35-
3618type LintGroups = BTreeMap < String , BTreeSet < String > > ;
3719
38- /// Collects the group names from rustc.
39- fn collect_groups ( rustc : crate :: Rustc < ' _ > ) -> Result < LintGroups , Box < dyn Error > > {
40- let mut result = BTreeMap :: new ( ) ;
41- let mut cmd = Command :: new ( rustc . path ) ;
42- cmd . arg ( "-Whelp ") ;
43- let output = cmd . output ( ) . map_err ( |e| format ! ( "failed to run command {:?} \n {}" , cmd , e ) ) ? ;
44- if !output . status . success ( ) {
45- return Err ( format ! (
46- "failed to collect lint info: {:?} \n --- stderr \n {}--- stdout \n {} \n " ,
47- output. status ,
48- std :: str :: from_utf8 ( & output . stderr ) . unwrap ( ) ,
49- std :: str :: from_utf8 ( & output . stdout ) . unwrap ( ) ,
50- )
51- . into ( ) ) ;
20+ impl < ' a > LintExtractor < ' a > {
21+ /// Updates the documentation of lint groups.
22+ pub ( crate ) fn generate_group_docs ( & self , lints : & [ Lint ] ) -> Result < ( ) , Box < dyn Error > > {
23+ let groups = self . collect_groups ( ) ? ;
24+ let groups_path = self . out_path . join ( "groups.md ") ;
25+ let contents = fs :: read_to_string ( & groups_path )
26+ . map_err ( |e| format ! ( "could not read {}: {}" , groups_path . display ( ) , e ) ) ? ;
27+ let new_contents =
28+ contents . replace ( "{{groups-table}}" , & self . make_groups_table ( lints , & groups ) ? ) ;
29+ // Delete the output because rustbuild uses hard links in its copies.
30+ let _ = fs :: remove_file ( & groups_path ) ;
31+ fs :: write ( & groups_path , new_contents )
32+ . map_err ( |e| format ! ( "could not write to {}: {}" , groups_path . display ( ) , e ) ) ? ;
33+ Ok ( ( ) )
5234 }
53- let stdout = std:: str:: from_utf8 ( & output. stdout ) . unwrap ( ) ;
54- let lines = stdout. lines ( ) ;
55- let group_start = lines. skip_while ( |line| !line. contains ( "groups provided" ) ) . skip ( 1 ) ;
56- let table_start = group_start. skip_while ( |line| !line. contains ( "----" ) ) . skip ( 1 ) ;
57- for line in table_start {
58- if line. is_empty ( ) {
59- break ;
35+
36+ /// Collects the group names from rustc.
37+ fn collect_groups ( & self ) -> Result < LintGroups , Box < dyn Error > > {
38+ let mut result = BTreeMap :: new ( ) ;
39+ let mut cmd = Command :: new ( self . rustc_path ) ;
40+ cmd. arg ( "-Whelp" ) ;
41+ let output = cmd. output ( ) . map_err ( |e| format ! ( "failed to run command {:?}\n {}" , cmd, e) ) ?;
42+ if !output. status . success ( ) {
43+ return Err ( format ! (
44+ "failed to collect lint info: {:?}\n --- stderr\n {}--- stdout\n {}\n " ,
45+ output. status,
46+ std:: str :: from_utf8( & output. stderr) . unwrap( ) ,
47+ std:: str :: from_utf8( & output. stdout) . unwrap( ) ,
48+ )
49+ . into ( ) ) ;
6050 }
61- let mut parts = line. trim ( ) . splitn ( 2 , ' ' ) ;
62- let name = parts. next ( ) . expect ( "name in group" ) ;
63- if name == "warnings" {
64- // This is special.
65- continue ;
51+ let stdout = std:: str:: from_utf8 ( & output. stdout ) . unwrap ( ) ;
52+ let lines = stdout. lines ( ) ;
53+ let group_start = lines. skip_while ( |line| !line. contains ( "groups provided" ) ) . skip ( 1 ) ;
54+ let table_start = group_start. skip_while ( |line| !line. contains ( "----" ) ) . skip ( 1 ) ;
55+ for line in table_start {
56+ if line. is_empty ( ) {
57+ break ;
58+ }
59+ let mut parts = line. trim ( ) . splitn ( 2 , ' ' ) ;
60+ let name = parts. next ( ) . expect ( "name in group" ) ;
61+ if name == "warnings" {
62+ // This is special.
63+ continue ;
64+ }
65+ let lints = parts
66+ . next ( )
67+ . ok_or_else ( || format ! ( "expected lints following name, got `{}`" , line) ) ?;
68+ let lints = lints. split ( ',' ) . map ( |l| l. trim ( ) . to_string ( ) ) . collect ( ) ;
69+ assert ! ( result. insert( name. to_string( ) , lints) . is_none( ) ) ;
6670 }
67- let lints =
68- parts. next ( ) . ok_or_else ( || format ! ( "expected lints following name, got `{}`" , line) ) ?;
69- let lints = lints. split ( ',' ) . map ( |l| l. trim ( ) . to_string ( ) ) . collect ( ) ;
70- assert ! ( result. insert( name. to_string( ) , lints) . is_none( ) ) ;
71- }
72- if result. is_empty ( ) {
73- return Err (
74- format ! ( "expected at least one group in -Whelp output, got:\n {}" , stdout) . into ( )
75- ) ;
71+ if result. is_empty ( ) {
72+ return Err (
73+ format ! ( "expected at least one group in -Whelp output, got:\n {}" , stdout) . into ( )
74+ ) ;
75+ }
76+ Ok ( result)
7677 }
77- Ok ( result)
78- }
7978
80- fn make_groups_table ( lints : & [ Lint ] , groups : & LintGroups ) -> Result < String , Box < dyn Error > > {
81- let mut result = String :: new ( ) ;
82- let mut to_link = Vec :: new ( ) ;
83- result. push_str ( "| Group | Description | Lints |\n " ) ;
84- result. push_str ( "|-------|-------------|-------|\n " ) ;
85- result. push_str ( "| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n " ) ;
86- for ( group_name, group_lints) in groups {
87- let description = GROUP_DESCRIPTIONS . iter ( ) . find ( |( n, _) | n == group_name)
88- . ok_or_else ( || format ! ( "lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list" , group_name) ) ?
89- . 1 ;
90- to_link. extend ( group_lints) ;
91- let brackets: Vec < _ > = group_lints. iter ( ) . map ( |l| format ! ( "[{}]" , l) ) . collect ( ) ;
92- write ! ( result, "| {} | {} | {} |\n " , group_name, description, brackets. join( ", " ) ) . unwrap ( ) ;
93- }
94- result. push ( '\n' ) ;
95- result. push_str ( "[warn-by-default]: listing/warn-by-default.md\n " ) ;
96- for lint_name in to_link {
97- let lint_def =
98- lints. iter ( ) . find ( |l| l. name == lint_name. replace ( "-" , "_" ) ) . ok_or_else ( || {
99- format ! (
100- "`rustc -W help` defined lint `{}` but that lint does not appear to exist" ,
101- lint_name
102- )
103- } ) ?;
104- write ! (
105- result,
106- "[{}]: listing/{}#{}\n " ,
107- lint_name,
108- lint_def. level. doc_filename( ) ,
109- lint_name
110- )
111- . unwrap ( ) ;
79+ fn make_groups_table (
80+ & self ,
81+ lints : & [ Lint ] ,
82+ groups : & LintGroups ,
83+ ) -> Result < String , Box < dyn Error > > {
84+ let mut result = String :: new ( ) ;
85+ let mut to_link = Vec :: new ( ) ;
86+ result. push_str ( "| Group | Description | Lints |\n " ) ;
87+ result. push_str ( "|-------|-------------|-------|\n " ) ;
88+ result. push_str ( "| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n " ) ;
89+ for ( group_name, group_lints) in groups {
90+ let description = match GROUP_DESCRIPTIONS . iter ( ) . find ( |( n, _) | n == group_name) {
91+ Some ( ( _, desc) ) => desc,
92+ None if self . validate => {
93+ return Err ( format ! (
94+ "lint group `{}` does not have a description, \
95+ please update the GROUP_DESCRIPTIONS list in \
96+ src/tools/lint-docs/src/groups.rs",
97+ group_name
98+ )
99+ . into ( ) ) ;
100+ }
101+ None => {
102+ eprintln ! (
103+ "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n \
104+ If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
105+ src/tools/lint-docs/src/groups.rs",
106+ group_name
107+ ) ;
108+ continue ;
109+ }
110+ } ;
111+ to_link. extend ( group_lints) ;
112+ let brackets: Vec < _ > = group_lints. iter ( ) . map ( |l| format ! ( "[{}]" , l) ) . collect ( ) ;
113+ write ! ( result, "| {} | {} | {} |\n " , group_name, description, brackets. join( ", " ) )
114+ . unwrap ( ) ;
115+ }
116+ result. push ( '\n' ) ;
117+ result. push_str ( "[warn-by-default]: listing/warn-by-default.md\n " ) ;
118+ for lint_name in to_link {
119+ let lint_def =
120+ lints. iter ( ) . find ( |l| l. name == lint_name. replace ( "-" , "_" ) ) . ok_or_else ( || {
121+ format ! (
122+ "`rustc -W help` defined lint `{}` but that lint does not appear to exist" ,
123+ lint_name
124+ )
125+ } ) ?;
126+ write ! (
127+ result,
128+ "[{}]: listing/{}#{}\n " ,
129+ lint_name,
130+ lint_def. level. doc_filename( ) ,
131+ lint_name
132+ )
133+ . unwrap ( ) ;
134+ }
135+ Ok ( result)
112136 }
113- Ok ( result)
114137}
0 commit comments