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