@@ -15,6 +15,8 @@ use rustc_tools_util::*;
1515use std:: path:: Path ;
1616use std:: process:: { exit, Command } ;
1717
18+ mod lintlist;
19+
1820/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
1921/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
2022fn arg_value < ' a > (
@@ -108,6 +110,142 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
108110 }
109111}
110112
113+ #[ allow( clippy:: find_map, clippy:: filter_map) ]
114+ fn describe_lints ( ) {
115+ use lintlist:: * ;
116+ use std:: collections:: HashSet ;
117+
118+ println ! (
119+ "
120+ Available lint options:
121+ -W <foo> Warn about <foo>
122+ -A <foo> Allow <foo>
123+ -D <foo> Deny <foo>
124+ -F <foo> Forbid <foo> (deny <foo> and all attempts to override)
125+
126+ "
127+ ) ;
128+
129+ let lint_level = |lint : & Lint | {
130+ LINT_LEVELS
131+ . iter ( )
132+ . find ( |level_mapping| level_mapping. 0 == lint. group )
133+ . map ( |( _, level) | match level {
134+ Level :: Allow => "allow" ,
135+ Level :: Warn => "warn" ,
136+ Level :: Deny => "deny" ,
137+ } )
138+ . unwrap ( )
139+ } ;
140+
141+ let mut lints: Vec < _ > = ALL_LINTS . iter ( ) . collect ( ) ;
142+ // The sort doesn't case-fold but it's doubtful we care.
143+ lints. sort_by_cached_key ( |x : & & Lint | ( lint_level ( x) , x. name ) ) ;
144+
145+ let max_lint_name_len = lints
146+ . iter ( )
147+ . map ( |lint| lint. name . len ( ) )
148+ . map ( |len| len + "clippy::" . len ( ) )
149+ . max ( )
150+ . unwrap_or ( 0 ) ;
151+
152+ let padded = |x : & str | {
153+ let mut s = " " . repeat ( max_lint_name_len - x. chars ( ) . count ( ) ) ;
154+ s. push_str ( x) ;
155+ s
156+ } ;
157+
158+ let scoped = |x : & str | format ! ( "clippy::{}" , x) ;
159+
160+ let lint_groups: HashSet < _ > = lints. iter ( ) . map ( |lint| lint. group ) . collect ( ) ;
161+
162+ println ! ( "Lint checks provided by clippy:\n " ) ;
163+ println ! ( " {} {:7.7} meaning" , padded( "name" ) , "default" ) ;
164+ println ! ( " {} {:7.7} -------" , padded( "----" ) , "-------" ) ;
165+
166+ let print_lints = |lints : & [ & Lint ] | {
167+ for lint in lints {
168+ let name = lint. name . replace ( "_" , "-" ) ;
169+ println ! (
170+ " {} {:7.7} {}" ,
171+ padded( & scoped( & name) ) ,
172+ lint_level( lint) ,
173+ lint. desc
174+ ) ;
175+ }
176+ println ! ( "\n " ) ;
177+ } ;
178+
179+ print_lints ( & lints) ;
180+
181+ let max_group_name_len = std:: cmp:: max (
182+ "clippy::all" . len ( ) ,
183+ lint_groups
184+ . iter ( )
185+ . map ( |group| group. len ( ) )
186+ . map ( |len| len + "clippy::" . len ( ) )
187+ . max ( )
188+ . unwrap_or ( 0 ) ,
189+ ) ;
190+
191+ let padded_group = |x : & str | {
192+ let mut s = " " . repeat ( max_group_name_len - x. chars ( ) . count ( ) ) ;
193+ s. push_str ( x) ;
194+ s
195+ } ;
196+
197+ println ! ( "Lint groups provided by clippy:\n " ) ;
198+ println ! ( " {} sub-lints" , padded_group( "name" ) ) ;
199+ println ! ( " {} ---------" , padded_group( "----" ) ) ;
200+ println ! ( " {} the set of all clippy lints" , padded_group( "clippy::all" ) ) ;
201+
202+ let print_lint_groups = || {
203+ for group in lint_groups {
204+ let name = group. to_lowercase ( ) . replace ( "_" , "-" ) ;
205+ let desc = lints
206+ . iter ( )
207+ . filter ( |& lint| lint. group == group)
208+ . map ( |lint| lint. name )
209+ . map ( |name| name. replace ( "_" , "-" ) )
210+ . collect :: < Vec < String > > ( )
211+ . join ( ", " ) ;
212+ println ! ( " {} {}" , padded_group( & scoped( & name) ) , desc) ;
213+ }
214+ println ! ( "\n " ) ;
215+ } ;
216+
217+ print_lint_groups ( ) ;
218+ }
219+
220+ fn display_help ( ) {
221+ println ! (
222+ "\
223+ Checks a package to catch common mistakes and improve your Rust code.
224+
225+ Usage:
226+ cargo clippy [options] [--] [<opts>...]
227+
228+ Common options:
229+ -h, --help Print this message
230+ -V, --version Print version info and exit
231+
232+ Other options are the same as `cargo check`.
233+
234+ To allow or deny a lint from the command line you can use `cargo clippy --`
235+ with:
236+
237+ -W --warn OPT Set lint warnings
238+ -A --allow OPT Set lint allowed
239+ -D --deny OPT Set lint denied
240+ -F --forbid OPT Set lint forbidden
241+
242+ You can use tool lints to allow or deny lints from your code, eg.:
243+
244+ #[allow(clippy::needless_lifetimes)]
245+ "
246+ ) ;
247+ }
248+
111249pub fn main ( ) {
112250 rustc_driver:: init_rustc_env_logger ( ) ;
113251 exit (
@@ -153,13 +291,34 @@ pub fn main() {
153291
154292 // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
155293 // We're invoking the compiler programmatically, so we ignore this/
156- if orig_args. len ( ) <= 1 {
157- std:: process:: exit ( 1 ) ;
158- }
159- if Path :: new ( & orig_args[ 1 ] ) . file_stem ( ) == Some ( "rustc" . as_ref ( ) ) {
294+ let wrapper_mode = Path :: new ( & orig_args[ 1 ] ) . file_stem ( ) == Some ( "rustc" . as_ref ( ) ) ;
295+
296+ if wrapper_mode {
160297 // we still want to be able to invoke it normally though
161298 orig_args. remove ( 1 ) ;
162299 }
300+
301+ if !wrapper_mode && std:: env:: args ( ) . any ( |a| a == "--help" || a == "-h" ) {
302+ display_help ( ) ;
303+ exit ( 0 ) ;
304+ }
305+
306+ let should_describe_lints = || {
307+ let args: Vec < _ > = std:: env:: args ( ) . collect ( ) ;
308+ args. windows ( 2 ) . any ( |args| {
309+ args[ 1 ] == "help"
310+ && match args[ 0 ] . as_str ( ) {
311+ "-W" | "-A" | "-D" | "-F" => true ,
312+ _ => false ,
313+ }
314+ } )
315+ } ;
316+
317+ if !wrapper_mode && should_describe_lints ( ) {
318+ describe_lints ( ) ;
319+ exit ( 0 ) ;
320+ }
321+
163322 // this conditional check for the --sysroot flag is there so users can call
164323 // `clippy_driver` directly
165324 // without having to pass --sysroot or anything
0 commit comments