Skip to content

Commit bd39cea

Browse files
committed
Auto merge of rust-lang#4175 - yaahallo:master, r=oli-obk
Implement better help for clippy-driver rust-lang/rust-clippy#4173
2 parents 7b2a7a2 + 2719c1e commit bd39cea

File tree

4 files changed

+2349
-4
lines changed

4 files changed

+2349
-4
lines changed

clippy_dev/src/main.rs

+22
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,31 @@ fn print_lints() {
8787

8888
fn update_lints(update_mode: &UpdateMode) {
8989
let lint_list: Vec<Lint> = gather_all().collect();
90+
9091
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
9192
let lint_count = usable_lints.len();
9293

94+
let mut sorted_usable_lints = usable_lints.clone();
95+
sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
96+
97+
std::fs::write(
98+
"../src/lintlist/mod.rs",
99+
&format!(
100+
"\
101+
//! This file is managed by `util/dev update_lints`. Do not edit.
102+
103+
pub mod lint;
104+
pub use lint::Level;
105+
pub use lint::Lint;
106+
pub use lint::LINT_LEVELS;
107+
108+
pub const ALL_LINTS: [Lint; {}] = {:#?};\n",
109+
sorted_usable_lints.len(),
110+
sorted_usable_lints
111+
),
112+
)
113+
.expect("can write to file");
114+
93115
let mut file_change = replace_region_in_file(
94116
"../README.md",
95117
r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,

src/driver.rs

+163-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use rustc_tools_util::*;
1515
use std::path::Path;
1616
use 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`.
2022
fn 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+
111249
pub 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

src/lintlist/lint.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// Lint data parsed from the Clippy source code.
2+
#[derive(Clone, PartialEq, Debug)]
3+
pub struct Lint {
4+
pub name: &'static str,
5+
pub group: &'static str,
6+
pub desc: &'static str,
7+
pub deprecation: Option<&'static str>,
8+
pub module: &'static str,
9+
}
10+
11+
#[derive(PartialOrd, PartialEq, Ord, Eq)]
12+
pub enum Level {
13+
Allow,
14+
Warn,
15+
Deny,
16+
}
17+
18+
pub const LINT_LEVELS: [(&str, Level); 8] = [
19+
("correctness", Level::Deny),
20+
("style", Level::Warn),
21+
("complexity", Level::Warn),
22+
("perf", Level::Warn),
23+
("restriction", Level::Allow),
24+
("pedantic", Level::Allow),
25+
("nursery", Level::Allow),
26+
("cargo", Level::Allow),
27+
];

0 commit comments

Comments
 (0)