1 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
3 use clap::{App, Arg, SubCommand};
8 mod stderr_length_check;
17 let matches = App::new("Clippy developer tooling")
19 SubCommand::with_name("fmt")
20 .about("Run rustfmt on all projects and tests")
22 Arg::with_name("check")
24 .help("Use the rustfmt --check option"),
27 Arg::with_name("verbose")
30 .help("Echo commands run"),
34 SubCommand::with_name("update_lints")
35 .about("Updates lint registration and information from the source code")
38 * the lint count in README.md is correct\n \
39 * the changelog contains markdown link references at the bottom\n \
40 * all lint groups include the correct lints\n \
41 * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
42 * all lints are registered in the lint store",
44 .arg(Arg::with_name("print-only").long("print-only").help(
45 "Print a table of lints to STDOUT. \
46 This does not include deprecated and internal lints. \
47 (Does not modify any files)",
50 Arg::with_name("check")
52 .help("Checks that util/dev update_lints has been run. Used on CI."),
56 SubCommand::with_name("new_lint")
57 .about("Create new lint and run util/dev update_lints")
59 Arg::with_name("pass")
62 .help("Specify whether the lint runs during the early or late pass")
64 .possible_values(&["early", "late"])
68 Arg::with_name("name")
71 .help("Name of the new lint in snake case, ex: fn_too_long")
76 Arg::with_name("category")
79 .help("What category the lint belongs to")
80 .default_value("nursery")
97 Arg::with_name("limit-stderr-length")
98 .long("limit-stderr-length")
99 .help("Ensures that stderr files do not grow longer than a certain amount of lines."),
103 if matches.is_present("limit-stderr-length") {
104 stderr_length_check::check();
107 match matches.subcommand() {
108 ("fmt", Some(matches)) => {
109 fmt::run(matches.is_present("check"), matches.is_present("verbose"));
111 ("update_lints", Some(matches)) => {
112 if matches.is_present("print-only") {
114 } else if matches.is_present("check") {
115 update_lints(&UpdateMode::Check);
117 update_lints(&UpdateMode::Change);
120 ("new_lint", Some(matches)) => {
121 match new_lint::create(
122 matches.value_of("pass"),
123 matches.value_of("name"),
124 matches.value_of("category"),
126 Ok(_) => update_lints(&UpdateMode::Change),
127 Err(e) => eprintln!("Unable to create lint: {}", e),
135 let lint_list = gather_all();
136 let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
137 let lint_count = usable_lints.len();
138 let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);
140 for (lint_group, mut lints) in grouped_by_lint_group {
141 if lint_group == "Deprecated" {
144 println!("\n## {}", lint_group);
146 lints.sort_by_key(|l| l.name.clone());
150 "* [{}]({}#{}) ({})",
152 clippy_dev::DOCS_LINK.clone(),
159 println!("there are {} lints", lint_count);
162 #[allow(clippy::too_many_lines)]
163 fn update_lints(update_mode: &UpdateMode) {
164 let lint_list: Vec<Lint> = gather_all().collect();
166 let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
167 let lint_count = usable_lints.len();
169 let mut sorted_usable_lints = usable_lints.clone();
170 sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
172 let mut file_change = replace_region_in_file(
173 "../src/lintlist/mod.rs",
177 update_mode == &UpdateMode::Change,
180 "pub const ALL_LINTS: [Lint; {}] = {:#?};",
181 sorted_usable_lints.len(),
185 .map(ToString::to_string)
191 file_change |= replace_region_in_file(
193 r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
196 update_mode == &UpdateMode::Change,
199 format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
204 file_change |= replace_region_in_file(
206 "<!-- begin autogenerated links to lint list -->",
207 "<!-- end autogenerated links to lint list -->",
209 update_mode == &UpdateMode::Change,
210 || gen_changelog_lint_list(lint_list.clone()),
214 file_change |= replace_region_in_file(
215 "../clippy_lints/src/lib.rs",
216 "begin deprecated lints",
217 "end deprecated lints",
219 update_mode == &UpdateMode::Change,
220 || gen_deprecated(&lint_list),
224 file_change |= replace_region_in_file(
225 "../clippy_lints/src/lib.rs",
226 "begin register lints",
227 "end register lints",
229 update_mode == &UpdateMode::Change,
230 || gen_register_lint_list(&lint_list),
234 file_change |= replace_region_in_file(
235 "../clippy_lints/src/lib.rs",
236 "begin lints modules",
239 update_mode == &UpdateMode::Change,
240 || gen_modules_list(lint_list.clone()),
244 // Generate lists of lints in the clippy::all lint group
245 file_change |= replace_region_in_file(
246 "../clippy_lints/src/lib.rs",
247 r#"store.register_group\(true, "clippy::all""#,
250 update_mode == &UpdateMode::Change,
252 // clippy::all should only include the following lint groups:
253 let all_group_lints = usable_lints
257 l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
261 gen_lint_group_list(all_group_lints)
266 // Generate the list of lints for all other lint groups
267 for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
268 file_change |= replace_region_in_file(
269 "../clippy_lints/src/lib.rs",
270 &format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
273 update_mode == &UpdateMode::Change,
274 || gen_lint_group_list(lints.clone()),
279 if update_mode == &UpdateMode::Check && file_change {
281 "Not all lints defined properly. \
282 Please run `util/dev update_lints` to make sure all lints are defined properly."
284 std::process::exit(1);