1 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
2 // warn on lints, that are included in `rust-lang/rust`s bootstrap
3 #![warn(rust_2018_idioms, unused_lifetimes)]
5 use clap::{Arg, ArgAction, ArgMatches, Command, PossibleValue};
6 use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints};
10 let matches = get_clap_config();
12 match matches.subcommand() {
13 Some(("bless", matches)) => {
14 bless::bless(matches.contains_id("ignore-timestamp"));
16 Some(("dogfood", matches)) => {
18 matches.contains_id("fix"),
19 matches.contains_id("allow-dirty"),
20 matches.contains_id("allow-staged"),
23 Some(("fmt", matches)) => {
24 fmt::run(matches.contains_id("check"), matches.contains_id("verbose"));
26 Some(("update_lints", matches)) => {
27 if matches.contains_id("print-only") {
28 update_lints::print_lints();
29 } else if matches.contains_id("check") {
30 update_lints::update(update_lints::UpdateMode::Check);
32 update_lints::update(update_lints::UpdateMode::Change);
35 Some(("new_lint", matches)) => {
36 match new_lint::create(
37 matches.get_one::<String>("pass"),
38 matches.get_one::<String>("name"),
39 matches.get_one::<String>("category").map(String::as_str),
40 matches.get_one::<String>("type").map(String::as_str),
41 matches.contains_id("msrv"),
43 Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
44 Err(e) => eprintln!("Unable to create lint: {}", e),
47 Some(("setup", sub_command)) => match sub_command.subcommand() {
48 Some(("intellij", matches)) => {
49 if matches.contains_id("remove") {
50 setup::intellij::remove_rustc_src();
52 setup::intellij::setup_rustc_src(
54 .get_one::<String>("rustc-repo-path")
55 .expect("this field is mandatory and therefore always valid"),
59 Some(("git-hook", matches)) => {
60 if matches.contains_id("remove") {
61 setup::git_hook::remove_hook();
63 setup::git_hook::install_hook(matches.contains_id("force-override"));
66 Some(("vscode-tasks", matches)) => {
67 if matches.contains_id("remove") {
68 setup::vscode::remove_tasks();
70 setup::vscode::install_tasks(matches.contains_id("force-override"));
75 Some(("remove", sub_command)) => match sub_command.subcommand() {
76 Some(("git-hook", _)) => setup::git_hook::remove_hook(),
77 Some(("intellij", _)) => setup::intellij::remove_rustc_src(),
78 Some(("vscode-tasks", _)) => setup::vscode::remove_tasks(),
81 Some(("serve", matches)) => {
82 let port = *matches.get_one::<u16>("port").unwrap();
83 let lint = matches.get_one::<String>("lint");
84 serve::run(port, lint);
86 Some(("lint", matches)) => {
87 let path = matches.get_one::<String>("path").unwrap();
88 let args = matches.get_many::<String>("args").into_iter().flatten();
89 lint::run(path, args);
91 Some(("rename_lint", matches)) => {
92 let old_name = matches.get_one::<String>("old_name").unwrap();
93 let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name);
94 let uplift = matches.contains_id("uplift");
95 update_lints::rename(old_name, new_name, uplift);
97 Some(("deprecate", matches)) => {
98 let name = matches.get_one::<String>("name").unwrap();
99 let reason = matches.get_one("reason");
100 update_lints::deprecate(name, reason);
106 fn get_clap_config() -> ArgMatches {
107 Command::new("Clippy developer tooling")
108 .arg_required_else_help(true)
110 Command::new("bless").about("bless the test output changes").arg(
111 Arg::new("ignore-timestamp")
112 .long("ignore-timestamp")
113 .help("Include files updated before clippy was built"),
115 Command::new("dogfood").about("Runs the dogfood test").args([
116 Arg::new("fix").long("fix").help("Apply the suggestions when possible"),
117 Arg::new("allow-dirty")
119 .help("Fix code even if the working directory has changes")
121 Arg::new("allow-staged")
122 .long("allow-staged")
123 .help("Fix code even if the working directory has staged changes")
127 .about("Run rustfmt on all projects and tests")
129 Arg::new("check").long("check").help("Use the rustfmt --check option"),
130 Arg::new("verbose").short('v').long("verbose").help("Echo commands run"),
132 Command::new("update_lints")
133 .about("Updates lint registration and information from the source code")
135 "Makes sure that:\n \
136 * the lint count in README.md is correct\n \
137 * the changelog contains markdown link references at the bottom\n \
138 * all lint groups include the correct lints\n \
139 * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
140 * all lints are registered in the lint store",
143 Arg::new("print-only").long("print-only").help(
144 "Print a table of lints to STDOUT. \
145 This does not include deprecated and internal lints. \
146 (Does not modify any files)",
150 .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
152 Command::new("new_lint")
153 .about("Create new lint and run `cargo dev update_lints`")
158 .help("Specify whether the lint runs during the early or late pass")
160 .value_parser([PossibleValue::new("early"), PossibleValue::new("late")])
161 .conflicts_with("type")
162 .required_unless_present("type"),
166 .help("Name of the new lint in snake case, ex: fn_too_long")
172 .help("What category the lint belongs to")
173 .default_value("nursery")
175 PossibleValue::new("style"),
176 PossibleValue::new("correctness"),
177 PossibleValue::new("suspicious"),
178 PossibleValue::new("complexity"),
179 PossibleValue::new("perf"),
180 PossibleValue::new("pedantic"),
181 PossibleValue::new("restriction"),
182 PossibleValue::new("cargo"),
183 PossibleValue::new("nursery"),
184 PossibleValue::new("internal"),
185 PossibleValue::new("internal_warn"),
190 .help("What directory the lint belongs in")
193 Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"),
195 Command::new("setup")
196 .about("Support for setting up your personal development environment")
197 .arg_required_else_help(true)
199 Command::new("intellij")
200 .about("Alter dependencies so Intellij Rust can find rustc internals")
204 .help("Remove the dependencies added with 'cargo dev setup intellij'")
206 Arg::new("rustc-repo-path")
209 .help("The path to a rustc repo that will be used for setting the dependencies")
212 .conflicts_with("remove")
215 Command::new("git-hook")
216 .about("Add a pre-commit git hook that formats your code to make it look pretty")
220 .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'")
222 Arg::new("force-override")
223 .long("force-override")
225 .help("Forces the override of an existing git pre-commit hook")
228 Command::new("vscode-tasks")
229 .about("Add several tasks to vscode for formatting, validation and testing")
233 .help("Remove the tasks added with 'cargo dev setup vscode-tasks'")
235 Arg::new("force-override")
236 .long("force-override")
238 .help("Forces the override of existing vscode tasks")
242 Command::new("remove")
243 .about("Support for undoing changes done by the setup command")
244 .arg_required_else_help(true)
246 Command::new("git-hook").about("Remove any existing pre-commit git hook"),
247 Command::new("vscode-tasks").about("Remove any existing vscode tasks"),
248 Command::new("intellij").about("Removes rustc source paths added via `cargo dev setup intellij`"),
250 Command::new("serve")
251 .about("Launch a local 'ALL the Clippy Lints' website in a browser")
256 .help("Local port for the http server")
257 .default_value("8000")
258 .value_parser(clap::value_parser!(u16)),
259 Arg::new("lint").help("Which lint's page to load initially (optional)"),
262 .about("Manually run clippy on a file or package")
263 .after_help(indoc! {"
266 cargo dev lint tests/ui/attrs.rs
268 Lint a package directory:
269 cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
270 cargo dev lint ~/my-project
273 cargo dev lint ~/my-project -- --fix
276 cargo dev lint file.rs -- -W clippy::pedantic
277 cargo dev lint ~/my-project -- -- -W clippy::pedantic
282 .help("The path to a file or package directory to lint"),
284 .action(ArgAction::Append)
285 .help("Pass extra arguments to cargo/clippy-driver"),
287 Command::new("rename_lint").about("Renames the given lint").args([
291 .help("The name of the lint to rename"),
294 .required_unless_present("uplift")
295 .help("The new name of the lint"),
298 .help("This lint will be uplifted into rustc"),
300 Command::new("deprecate").about("Deprecates the given lint").args([
304 .help("The name of the lint to deprecate"),
310 .help("The reason for deprecation"),