Skip to content

Commit 4f28e71

Browse files
committed
Automatically rename more files with cargo dev rename_lint
1 parent 5bb7c1a commit 4f28e71

File tree

1 file changed

+96
-50
lines changed

1 file changed

+96
-50
lines changed

clippy_dev/src/update_lints.rs

Lines changed: 96 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
55
use std::collections::{HashMap, HashSet};
66
use std::ffi::OsStr;
77
use std::fs;
8-
use std::io::Write as _;
8+
use std::io::{self, Read as _, Seek as _, Write as _};
99
use std::path::{Path, PathBuf};
1010
use walkdir::{DirEntry, WalkDir};
1111

@@ -189,7 +189,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
189189
};
190190

191191
// Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in
192-
// case.)
192+
// case.
193193
assert!(
194194
!renamed_lints.iter().any(|l| lint.old_name == l.old_name),
195195
"`{}` has already been renamed",
@@ -207,18 +207,15 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
207207
.map(Result::unwrap)
208208
.filter(|f| {
209209
let name = f.path().file_name();
210-
f.path().extension() == Some(OsStr::new("rs"))
210+
let ext = f.path().extension();
211+
(ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
211212
&& name != Some(OsStr::new("rename.rs"))
212213
&& name != Some(OsStr::new("renamed_lints.rs"))
213214
})
214215
{
215-
let path = file.path();
216-
let contents =
217-
fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
218-
if let Some(contents) = replace_ident_like(&contents, &[(&lint.old_name, &lint.new_name)]) {
219-
fs::write(path, contents.as_bytes())
220-
.unwrap_or_else(|e| panic!("Cannot write to `{}`: {}", path.display(), e));
221-
}
216+
rewrite_file(file.path(), |s| {
217+
replace_ident_like(s, &[(&lint.old_name, &lint.new_name)])
218+
});
222219
}
223220

224221
renamed_lints.push(lint);
@@ -230,72 +227,75 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
230227
.then_with(|| lhs.old_name.cmp(&rhs.old_name))
231228
});
232229

230+
write_file(
231+
Path::new("clippy_lints/src/renamed_lints.rs"),
232+
&gen_renamed_lints_list(&renamed_lints),
233+
);
234+
233235
if uplift {
236+
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_list(&renamed_lints));
234237
println!(
235-
"`{}` has be uplifted. Please remove all the code inside `clippy_lints` related to it.",
238+
"`{}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually.",
236239
old_name
237240
);
238-
let contents = gen_renamed_lints_test(&renamed_lints);
239-
fs::write("tests/ui/rename.rs", contents.as_bytes())
240-
.unwrap_or_else(|e| panic!("error writing file `tests/ui/rename.rs`: {}", e));
241241
} else if found_new_name {
242+
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_list(&renamed_lints));
242243
println!(
243-
"`{}` is already defined. The old linting code inside `clippy_lints` has to be updated/removed manually",
244+
"`{}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually.",
244245
new_name
245246
);
246-
let contents = gen_renamed_lints_test(&renamed_lints);
247-
fs::write("tests/ui/rename.rs", contents.as_bytes())
248-
.unwrap_or_else(|e| panic!("error writing file `tests/ui/rename.rs`: {}", e));
249247
} else {
250248
// Rename the lint struct and the containing module if it shares the lint name across all files.
251249
let lint = &mut lints[old_lint_index];
252250
let old_name_upper = old_name.to_uppercase();
253251
let new_name_upper = new_name.to_uppercase();
254-
let new_module_path = PathBuf::from(format!("clippy_lints/src/{}.rs", new_name));
255-
let replacements;
256252

257-
let (replacements, mut renamed_file) = if lint.module == lint.name
258-
// Only rename the module if the file doesn't already exist.
259-
&& let Ok(file) = fs::OpenOptions::new().create_new(true).write(true).open(&new_module_path)
260-
{
253+
if try_rename_file(
254+
Path::new(&format!("tests/ui/{}.rs", old_name)),
255+
Path::new(&format!("tests/ui/{}.rs", new_name)),
256+
) {
257+
try_rename_file(
258+
Path::new(&format!("tests/ui/{}.stderr", old_name)),
259+
Path::new(&format!("tests/ui/{}.stderr", new_name)),
260+
);
261+
try_rename_file(
262+
Path::new(&format!("tests/ui/{}.fixed", old_name)),
263+
Path::new(&format!("tests/ui/{}.fixed", new_name)),
264+
);
265+
}
266+
267+
let replacements;
268+
let replacements = if lint.module == lint.name
269+
&& try_rename_file(
270+
Path::new(&format!("clippy_lints/src/{}.rs", old_name)),
271+
Path::new(&format!("clippy_lints/src/{}.rs", new_name)),
272+
) {
261273
lint.module = new_name.into();
262274
replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
263-
(replacements.as_slice(), Some(file))
275+
replacements.as_slice()
276+
} else if !lint.module.contains("::")
277+
&& try_rename_file(
278+
Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, old_name)),
279+
Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, new_name)),
280+
)
281+
{
282+
replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
283+
replacements.as_slice()
264284
} else {
265285
replacements = [(&*old_name_upper, &*new_name_upper), ("", "")];
266-
(&replacements[0..1], None)
286+
&replacements[0..1]
267287
};
268288
lint.name = new_name.into();
269289

270-
for (rel_path, file) in clippy_lints_src_files() {
271-
let path = file.path();
272-
let contents =
273-
fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
274-
let new_contents = replace_ident_like(&contents, replacements);
275-
276-
if let Some(ref mut file) = renamed_file
277-
// Make sure the file is directly in the src directory and not a sub-directory.
278-
&& rel_path.parent().map_or(false, |p| p.as_os_str().is_empty())
279-
&& rel_path.file_stem() == Some(OsStr::new(old_name))
280-
{
281-
let contents = new_contents.as_ref().unwrap_or(&contents);
282-
file.write_all(contents.as_bytes())
283-
.unwrap_or_else(|e| panic!("Cannot write to `{}`: {}", new_module_path.display(), e));
284-
renamed_file = None;
285-
fs::remove_file(path)
286-
.unwrap_or_else(|e| panic!("Cannot delete file `{}`: {}", path.display(), e));
287-
} else if let Some(contents) = new_contents {
288-
fs::write(path, contents.as_bytes())
289-
.unwrap_or_else(|e| panic!("Cannot write to `{}`: {}", path.display(), e));
290-
}
290+
for (_, file) in clippy_lints_src_files() {
291+
rewrite_file(file.path(), |s| replace_ident_like(s, replacements));
291292
}
292293

293294
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
295+
println!("{} has been successfully renamed", old_name);
294296
}
295297

296-
let contents = gen_renamed_lints_list(&renamed_lints);
297-
fs::write("clippy_lints/src/renamed_lints.rs", contents.as_bytes())
298-
.unwrap_or_else(|e| panic!("error writing file `clippy_lints/src/renamed_lints.rs`: {}", e));
298+
println!("note: `cargo uitest` still needs to be run to update the test results");
299299
}
300300

301301
/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
@@ -741,6 +741,52 @@ fn replace_region_in_text<'a>(
741741
Ok(res)
742742
}
743743

744+
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
745+
match fs::OpenOptions::new().create_new(true).write(true).open(new_name) {
746+
Ok(file) => drop(file),
747+
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => return false,
748+
Err(e) => panic_file(e, new_name, "create"),
749+
};
750+
match fs::rename(old_name, new_name) {
751+
Ok(()) => true,
752+
Err(e) => {
753+
drop(fs::remove_file(new_name));
754+
if e.kind() == io::ErrorKind::NotFound {
755+
false
756+
} else {
757+
panic_file(e, old_name, "rename");
758+
}
759+
},
760+
}
761+
}
762+
763+
#[allow(clippy::needless_pass_by_value)]
764+
fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
765+
panic!("failed to {} file `{}`: {}", action, name.display(), error)
766+
}
767+
768+
fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
769+
let mut file = fs::OpenOptions::new()
770+
.write(true)
771+
.read(true)
772+
.open(path)
773+
.unwrap_or_else(|e| panic_file(e, path, "open"));
774+
let mut buf = String::new();
775+
file.read_to_string(&mut buf)
776+
.unwrap_or_else(|e| panic_file(e, path, "read"));
777+
if let Some(new_contents) = f(&buf) {
778+
file.rewind().unwrap_or_else(|e| panic_file(e, path, "write"));
779+
file.write_all(new_contents.as_bytes())
780+
.unwrap_or_else(|e| panic_file(e, path, "write"));
781+
file.set_len(new_contents.len() as u64)
782+
.unwrap_or_else(|e| panic_file(e, path, "write"));
783+
}
784+
}
785+
786+
fn write_file(path: &Path, contents: &str) {
787+
fs::write(path, contents).unwrap_or_else(|e| panic_file(e, path, "write"));
788+
}
789+
744790
#[cfg(test)]
745791
mod tests {
746792
use super::*;

0 commit comments

Comments
 (0)