]> git.lizzy.rs Git - rust.git/blob - clippy_dev/src/main.rs
Merge branch 'master' into dev-fmt-4
[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 fn update_lints(update_mode: &UpdateMode) {
113     let lint_list: Vec<Lint> = gather_all().collect();
114
115     let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
116     let lint_count = usable_lints.len();
117
118     let mut sorted_usable_lints = usable_lints.clone();
119     sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
120
121     let mut file_change = replace_region_in_file(
122         "../src/lintlist/mod.rs",
123         "begin lint list",
124         "end lint list",
125         false,
126         update_mode == &UpdateMode::Change,
127         || {
128             format!(
129                 "pub const ALL_LINTS: [Lint; {}] = {:#?};",
130                 sorted_usable_lints.len(),
131                 sorted_usable_lints
132             )
133             .lines()
134             .map(ToString::to_string)
135             .collect::<Vec<_>>()
136         },
137     )
138     .changed;
139
140     file_change |= replace_region_in_file(
141         "../README.md",
142         r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
143         "",
144         true,
145         update_mode == &UpdateMode::Change,
146         || {
147             vec![
148                 format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
149             ]
150         }
151     ).changed;
152
153     file_change |= replace_region_in_file(
154         "../CHANGELOG.md",
155         "<!-- begin autogenerated links to lint list -->",
156         "<!-- end autogenerated links to lint list -->",
157         false,
158         update_mode == &UpdateMode::Change,
159         || gen_changelog_lint_list(lint_list.clone()),
160     )
161     .changed;
162
163     file_change |= replace_region_in_file(
164         "../clippy_lints/src/lib.rs",
165         "begin deprecated lints",
166         "end deprecated lints",
167         false,
168         update_mode == &UpdateMode::Change,
169         || gen_deprecated(&lint_list),
170     )
171     .changed;
172
173     file_change |= replace_region_in_file(
174         "../clippy_lints/src/lib.rs",
175         "begin lints modules",
176         "end lints modules",
177         false,
178         update_mode == &UpdateMode::Change,
179         || gen_modules_list(lint_list.clone()),
180     )
181     .changed;
182
183     // Generate lists of lints in the clippy::all lint group
184     file_change |= replace_region_in_file(
185         "../clippy_lints/src/lib.rs",
186         r#"reg.register_lint_group\("clippy::all""#,
187         r#"\]\);"#,
188         false,
189         update_mode == &UpdateMode::Change,
190         || {
191             // clippy::all should only include the following lint groups:
192             let all_group_lints = usable_lints
193                 .clone()
194                 .into_iter()
195                 .filter(|l| {
196                     l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
197                 })
198                 .collect();
199
200             gen_lint_group_list(all_group_lints)
201         },
202     )
203     .changed;
204
205     // Generate the list of lints for all other lint groups
206     for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
207         file_change |= replace_region_in_file(
208             "../clippy_lints/src/lib.rs",
209             &format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
210             r#"\]\);"#,
211             false,
212             update_mode == &UpdateMode::Change,
213             || gen_lint_group_list(lints.clone()),
214         )
215         .changed;
216     }
217
218     if update_mode == &UpdateMode::Check && file_change {
219         println!(
220             "Not all lints defined properly. \
221              Please run `util/dev update_lints` to make sure all lints are defined properly."
222         );
223         std::process::exit(1);
224     }
225 }