Skip to content

Commit 2353f24

Browse files
author
Michael Wright
committed
Merge branch 'master' into fix-missing-comma-fp
2 parents a3ab512 + 4c3408c commit 2353f24

File tree

10 files changed

+322
-436
lines changed

10 files changed

+322
-436
lines changed

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
180180

181181
The [`rustc_plugin::PluginRegistry`][plugin_registry] provides two methods to register lints: [register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass].
182182
Both take an object that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in every single lint.
183-
It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/update_lints.py` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time.
183+
It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/dev update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time.
184184

185185
```rust
186186
// ./clippy_lints/src/else_if_without_else.rs

ci/base-tests.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ cargo test --features debugging
2323
cd clippy_lints && cargo test && cd ..
2424
cd rustc_tools_util && cargo test && cd ..
2525
cd clippy_dev && cargo test && cd ..
26-
# check that the lint lists are up-to-date
27-
./util/update_lints.py -c
26+
27+
# Perform various checks for lint registration
28+
./util/dev update_lints --check
2829

2930
CLIPPY="`pwd`/target/debug/cargo-clippy clippy"
3031
# run clippy on its own codebase...

clippy_dev/src/lib.rs

+73-49
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,22 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
114114

115115
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
116116
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
117-
lints.iter()
118-
.filter_map(|l| {
119-
l.clone().deprecation.and_then(|depr_text| {
120-
Some(
121-
format!(
122-
" store.register_removed(\n \"{}\",\n \"{}\",\n );",
123-
l.name,
124-
depr_text
117+
itertools::flatten(
118+
lints
119+
.iter()
120+
.filter_map(|l| {
121+
l.clone().deprecation.and_then(|depr_text| {
122+
Some(
123+
vec![
124+
" store.register_removed(".to_string(),
125+
format!(" \"{}\",", l.name),
126+
format!(" \"{}\",", depr_text),
127+
" );".to_string()
128+
]
125129
)
126-
)
130+
})
127131
})
128-
})
129-
.collect()
132+
).collect()
130133
}
131134

132135
/// Gathers all files in `src/clippy_lints` and gathers all lints inside
@@ -168,23 +171,33 @@ fn lint_files() -> impl Iterator<Item=walkdir::DirEntry> {
168171
.filter(|f| f.path().extension() == Some(OsStr::new("rs")))
169172
}
170173

174+
/// Whether a file has had its text changed or not
175+
#[derive(PartialEq, Debug)]
176+
pub struct FileChange {
177+
pub changed: bool,
178+
pub new_lines: String,
179+
}
180+
171181
/// Replace a region in a file delimited by two lines matching regexes.
172182
///
173183
/// `path` is the relative path to the file on which you want to perform the replacement.
174184
///
175185
/// See `replace_region_in_text` for documentation of the other options.
176186
#[allow(clippy::expect_fun_call)]
177-
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, replacements: F) where F: Fn() -> Vec<String> {
187+
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, write_back: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> {
178188
let mut f = fs::File::open(path).expect(&format!("File not found: {}", path));
179189
let mut contents = String::new();
180190
f.read_to_string(&mut contents).expect("Something went wrong reading the file");
181-
let replaced = replace_region_in_text(&contents, start, end, replace_start, replacements);
182-
183-
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
184-
f.write_all(replaced.as_bytes()).expect("Unable to write file");
185-
// Ensure we write the changes with a trailing newline so that
186-
// the file has the proper line endings.
187-
f.write_all(b"\n").expect("Unable to write file");
191+
let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
192+
193+
if write_back {
194+
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
195+
f.write_all(file_change.new_lines.as_bytes()).expect("Unable to write file");
196+
// Ensure we write the changes with a trailing newline so that
197+
// the file has the proper line endings.
198+
f.write_all(b"\n").expect("Unable to write file");
199+
}
200+
file_change
188201
}
189202

190203
/// Replace a region in a text delimited by two lines matching regexes.
@@ -213,18 +226,18 @@ pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_sta
213226
/// || {
214227
/// vec!["a different".to_string(), "text".to_string()]
215228
/// }
216-
/// );
229+
/// ).new_lines;
217230
/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
218231
/// ```
219-
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> String where F: Fn() -> Vec<String> {
232+
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> {
220233
let lines = text.lines();
221234
let mut in_old_region = false;
222235
let mut found = false;
223236
let mut new_lines = vec![];
224237
let start = Regex::new(start).unwrap();
225238
let end = Regex::new(end).unwrap();
226239

227-
for line in lines {
240+
for line in lines.clone() {
228241
if in_old_region {
229242
if end.is_match(&line) {
230243
in_old_region = false;
@@ -248,7 +261,11 @@ pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_sta
248261
// is incorrect.
249262
eprintln!("error: regex `{:?}` not found. You may have to update it.", start);
250263
}
251-
new_lines.join("\n")
264+
265+
FileChange {
266+
changed: lines.ne(new_lines.clone()),
267+
new_lines: new_lines.join("\n")
268+
}
252269
}
253270

254271
#[test]
@@ -292,17 +309,11 @@ declare_deprecated_lint! {
292309

293310
#[test]
294311
fn test_replace_region() {
295-
let text = r#"
296-
abc
297-
123
298-
789
299-
def
300-
ghi"#;
301-
let expected = r#"
302-
abc
303-
hello world
304-
def
305-
ghi"#;
312+
let text = "\nabc\n123\n789\ndef\nghi";
313+
let expected = FileChange {
314+
changed: true,
315+
new_lines: "\nabc\nhello world\ndef\nghi".to_string()
316+
};
306317
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
307318
vec!["hello world".to_string()]
308319
});
@@ -311,22 +322,30 @@ ghi"#;
311322

312323
#[test]
313324
fn test_replace_region_with_start() {
314-
let text = r#"
315-
abc
316-
123
317-
789
318-
def
319-
ghi"#;
320-
let expected = r#"
321-
hello world
322-
def
323-
ghi"#;
325+
let text = "\nabc\n123\n789\ndef\nghi";
326+
let expected = FileChange {
327+
changed: true,
328+
new_lines: "\nhello world\ndef\nghi".to_string()
329+
};
324330
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
325331
vec!["hello world".to_string()]
326332
});
327333
assert_eq!(expected, result);
328334
}
329335

336+
#[test]
337+
fn test_replace_region_no_changes() {
338+
let text = "123\n456\n789";
339+
let expected = FileChange {
340+
changed: false,
341+
new_lines: "123\n456\n789".to_string()
342+
};
343+
let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || {
344+
vec![]
345+
});
346+
assert_eq!(expected, result);
347+
}
348+
330349
#[test]
331350
fn test_usable_lints() {
332351
let lints = vec![
@@ -377,14 +396,19 @@ fn test_gen_changelog_lint_list() {
377396
fn test_gen_deprecated() {
378397
let lints = vec![
379398
Lint::new("should_assert_eq", "group1", "abc", Some("has been superseeded by should_assert_eq2"), "module_name"),
399+
Lint::new("another_deprecated", "group2", "abc", Some("will be removed"), "module_name"),
380400
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")
381401
];
382402
let expected: Vec<String> = vec![
383-
r#" store.register_removed(
384-
"should_assert_eq",
385-
"has been superseeded by should_assert_eq2",
386-
);"#.to_string()
387-
];
403+
" store.register_removed(",
404+
" \"should_assert_eq\",",
405+
" \"has been superseeded by should_assert_eq2\",",
406+
" );",
407+
" store.register_removed(",
408+
" \"another_deprecated\",",
409+
" \"will be removed\",",
410+
" );"
411+
].into_iter().map(String::from).collect();
388412
assert_eq!(expected, gen_deprecated(&lints));
389413
}
390414

clippy_dev/src/main.rs

+41-18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ extern crate regex;
1515
use clap::{App, Arg, SubCommand};
1616
use clippy_dev::*;
1717

18+
#[derive(PartialEq)]
19+
enum UpdateMode {
20+
Check,
21+
Change
22+
}
23+
1824
fn main() {
1925
let matches = App::new("Clippy developer tooling")
2026
.subcommand(
@@ -28,17 +34,23 @@ fn main() {
2834
.arg(
2935
Arg::with_name("print-only")
3036
.long("print-only")
31-
.short("p")
32-
.help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)"),
37+
.help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)")
38+
)
39+
.arg(
40+
Arg::with_name("check")
41+
.long("check")
42+
.help("Checks that util/dev update_lints has been run. Used on CI."),
3343
)
34-
)
35-
.get_matches();
44+
)
45+
.get_matches();
3646

3747
if let Some(matches) = matches.subcommand_matches("update_lints") {
3848
if matches.is_present("print-only") {
3949
print_lints();
50+
} else if matches.is_present("check") {
51+
update_lints(&UpdateMode::Check);
4052
} else {
41-
update_lints();
53+
update_lints(&UpdateMode::Change);
4254
}
4355
}
4456
}
@@ -63,53 +75,58 @@ fn print_lints() {
6375
println!("there are {} lints", lint_count);
6476
}
6577

66-
fn update_lints() {
78+
fn update_lints(update_mode: &UpdateMode) {
6779
let lint_list: Vec<Lint> = gather_all().collect();
6880
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
6981
let lint_count = usable_lints.len();
7082

71-
replace_region_in_file(
83+
let mut file_change = replace_region_in_file(
7284
"../README.md",
7385
r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)"#,
7486
"",
7587
true,
88+
update_mode == &UpdateMode::Change,
7689
|| {
7790
vec![
7891
format!("[There are {} lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)", lint_count)
7992
]
8093
}
81-
);
94+
).changed;
8295

83-
replace_region_in_file(
96+
file_change |= replace_region_in_file(
8497
"../CHANGELOG.md",
8598
"<!-- begin autogenerated links to lint list -->",
8699
"<!-- end autogenerated links to lint list -->",
87100
false,
101+
update_mode == &UpdateMode::Change,
88102
|| { gen_changelog_lint_list(lint_list.clone()) }
89-
);
103+
).changed;
90104

91-
replace_region_in_file(
105+
file_change |= replace_region_in_file(
92106
"../clippy_lints/src/lib.rs",
93107
"begin deprecated lints",
94108
"end deprecated lints",
95109
false,
110+
update_mode == &UpdateMode::Change,
96111
|| { gen_deprecated(&lint_list) }
97-
);
112+
).changed;
98113

99-
replace_region_in_file(
114+
file_change |= replace_region_in_file(
100115
"../clippy_lints/src/lib.rs",
101116
"begin lints modules",
102117
"end lints modules",
103118
false,
119+
update_mode == &UpdateMode::Change,
104120
|| { gen_modules_list(lint_list.clone()) }
105-
);
121+
).changed;
106122

107123
// Generate lists of lints in the clippy::all lint group
108-
replace_region_in_file(
124+
file_change |= replace_region_in_file(
109125
"../clippy_lints/src/lib.rs",
110126
r#"reg.register_lint_group\("clippy::all""#,
111127
r#"\]\);"#,
112128
false,
129+
update_mode == &UpdateMode::Change,
113130
|| {
114131
// clippy::all should only include the following lint groups:
115132
let all_group_lints = usable_lints.clone().into_iter().filter(|l| {
@@ -121,16 +138,22 @@ fn update_lints() {
121138

122139
gen_lint_group_list(all_group_lints)
123140
}
124-
);
141+
).changed;
125142

126143
// Generate the list of lints for all other lint groups
127144
for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
128-
replace_region_in_file(
145+
file_change |= replace_region_in_file(
129146
"../clippy_lints/src/lib.rs",
130147
&format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
131148
r#"\]\);"#,
132149
false,
150+
update_mode == &UpdateMode::Change,
133151
|| { gen_lint_group_list(lints.clone()) }
134-
);
152+
).changed;
153+
}
154+
155+
if update_mode == &UpdateMode::Check && file_change {
156+
println!("Not all lints defined properly. Please run `util/dev update_lints` to make sure all lints are defined properly.");
157+
std::process::exit(1);
135158
}
136159
}

0 commit comments

Comments
 (0)