]> git.lizzy.rs Git - rust.git/blob - clippy_dev/src/main.rs
Auto merge of #4941 - lzutao:utils-mod, r=phansch
[rust.git] / clippy_dev / src / main.rs
1 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
2
3 use clap::{App, Arg, SubCommand};
4 use clippy_dev::*;
5
6 mod fmt;
7 mod stderr_length_check;
8
9 #[derive(PartialEq)]
10 enum UpdateMode {
11     Check,
12     Change,
13 }
14
15 fn main() {
16     let matches = App::new("Clippy developer tooling")
17         .subcommand(
18             SubCommand::with_name("fmt")
19                 .about("Run rustfmt on all projects and tests")
20                 .arg(
21                     Arg::with_name("check")
22                         .long("check")
23                         .help("Use the rustfmt --check option"),
24                 )
25                 .arg(
26                     Arg::with_name("verbose")
27                         .short("v")
28                         .long("verbose")
29                         .help("Echo commands run"),
30                 ),
31         )
32         .subcommand(
33             SubCommand::with_name("update_lints")
34                 .about("Updates lint registration and information from the source code")
35                 .long_about(
36                     "Makes sure that:\n \
37                      * the lint count in README.md is correct\n \
38                      * the changelog contains markdown link references at the bottom\n \
39                      * all lint groups include the correct lints\n \
40                      * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
41                      * all lints are registered in the lint store",
42                 )
43                 .arg(Arg::with_name("print-only").long("print-only").help(
44                     "Print a table of lints to STDOUT. \
45                      This does not include deprecated and internal lints. \
46                      (Does not modify any files)",
47                 ))
48                 .arg(
49                     Arg::with_name("check")
50                         .long("check")
51                         .help("Checks that util/dev update_lints has been run. Used on CI."),
52                 ),
53         )
54         .arg(
55             Arg::with_name("limit-stderr-length")
56                 .long("limit-stderr-length")
57                 .help("Ensures that stderr files do not grow longer than a certain amount of lines."),
58         )
59         .get_matches();
60
61     if matches.is_present("limit-stderr-length") {
62         stderr_length_check::check();
63     }
64
65     match matches.subcommand() {
66         ("fmt", Some(matches)) => {
67             fmt::run(matches.is_present("check"), matches.is_present("verbose"));
68         },
69         ("update_lints", Some(matches)) => {
70             if matches.is_present("print-only") {
71                 print_lints();
72             } else if matches.is_present("check") {
73                 update_lints(&UpdateMode::Check);
74             } else {
75                 update_lints(&UpdateMode::Change);
76             }
77         },
78         _ => {},
79     }
80 }
81
82 fn print_lints() {
83     let lint_list = gather_all();
84     let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
85     let lint_count = usable_lints.len();
86     let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);
87
88     for (lint_group, mut lints) in grouped_by_lint_group {
89         if lint_group == "Deprecated" {
90             continue;
91         }
92         println!("\n## {}", lint_group);
93
94         lints.sort_by_key(|l| l.name.clone());
95
96         for lint in lints {
97             println!(
98                 "* [{}]({}#{}) ({})",
99                 lint.name,
100                 clippy_dev::DOCS_LINK.clone(),
101                 lint.name,
102                 lint.desc
103             );
104         }
105     }
106
107     println!("there are {} lints", lint_count);
108 }
109
110 #[allow(clippy::too_many_lines)]
111 fn update_lints(update_mode: &UpdateMode) {
112     let lint_list: Vec<Lint> = gather_all().collect();
113
114     let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
115     let lint_count = usable_lints.len();
116
117     let mut sorted_usable_lints = usable_lints.clone();
118     sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
119
120     let mut file_change = replace_region_in_file(
121         "../src/lintlist/mod.rs",
122         "begin lint list",
123         "end lint list",
124         false,
125         update_mode == &UpdateMode::Change,
126         || {
127             format!(
128                 "pub const ALL_LINTS: [Lint; {}] = {:#?};",
129                 sorted_usable_lints.len(),
130                 sorted_usable_lints
131             )
132             .lines()
133             .map(ToString::to_string)
134             .collect::<Vec<_>>()
135         },
136     )
137     .changed;
138
139     file_change |= replace_region_in_file(
140         "../README.md",
141         r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
142         "",
143         true,
144         update_mode == &UpdateMode::Change,
145         || {
146             vec![
147                 format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
148             ]
149         }
150     ).changed;
151
152     file_change |= replace_region_in_file(
153         "../CHANGELOG.md",
154         "<!-- begin autogenerated links to lint list -->",
155         "<!-- end autogenerated links to lint list -->",
156         false,
157         update_mode == &UpdateMode::Change,
158         || gen_changelog_lint_list(lint_list.clone()),
159     )
160     .changed;
161
162     file_change |= replace_region_in_file(
163         "../clippy_lints/src/lib.rs",
164         "begin deprecated lints",
165         "end deprecated lints",
166         false,
167         update_mode == &UpdateMode::Change,
168         || gen_deprecated(&lint_list),
169     )
170     .changed;
171
172     file_change |= replace_region_in_file(
173         "../clippy_lints/src/lib.rs",
174         "begin register lints",
175         "end register lints",
176         false,
177         update_mode == &UpdateMode::Change,
178         || gen_register_lint_list(&lint_list),
179     )
180     .changed;
181
182     file_change |= replace_region_in_file(
183         "../clippy_lints/src/lib.rs",
184         "begin lints modules",
185         "end lints modules",
186         false,
187         update_mode == &UpdateMode::Change,
188         || gen_modules_list(lint_list.clone()),
189     )
190     .changed;
191
192     // Generate lists of lints in the clippy::all lint group
193     file_change |= replace_region_in_file(
194         "../clippy_lints/src/lib.rs",
195         r#"store.register_group\(true, "clippy::all""#,
196         r#"\]\);"#,
197         false,
198         update_mode == &UpdateMode::Change,
199         || {
200             // clippy::all should only include the following lint groups:
201             let all_group_lints = usable_lints
202                 .clone()
203                 .into_iter()
204                 .filter(|l| {
205                     l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
206                 })
207                 .collect();
208
209             gen_lint_group_list(all_group_lints)
210         },
211     )
212     .changed;
213
214     // Generate the list of lints for all other lint groups
215     for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
216         file_change |= replace_region_in_file(
217             "../clippy_lints/src/lib.rs",
218             &format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
219             r#"\]\);"#,
220             false,
221             update_mode == &UpdateMode::Change,
222             || gen_lint_group_list(lints.clone()),
223         )
224         .changed;
225     }
226
227     if update_mode == &UpdateMode::Check && file_change {
228         println!(
229             "Not all lints defined properly. \
230              Please run `util/dev update_lints` to make sure all lints are defined properly."
231         );
232         std::process::exit(1);
233     }
234 }