about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2025-04-14 14:14:03 -0400
committerJason Newcomb <jsnewcomb@pm.me>2025-05-12 17:07:52 -0400
commit2c85cb0371ca0e8980a4225714ed3407f1670e12 (patch)
tree8f8eccb5a9f7c79a36925f814964e26315a8b56a
parent98cb92f3235c4c963d1c17e8a833f37091b5b487 (diff)
downloadrust-2c85cb0371ca0e8980a4225714ed3407f1670e12.tar.gz
rust-2c85cb0371ca0e8980a4225714ed3407f1670e12.zip
clippy_dev: Only build `AhoCorasick` searcher once for multiple files.
-rw-r--r--clippy_dev/src/rename_lint.rs15
-rw-r--r--clippy_dev/src/utils.rs59
2 files changed, 42 insertions, 32 deletions
diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs
index 25db95a4489..c78ec98c1aa 100644
--- a/clippy_dev/src/rename_lint.rs
+++ b/clippy_dev/src/rename_lint.rs
@@ -1,9 +1,7 @@
 use crate::update_lints::{
     RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test_fn, generate_lint_files,
 };
-use crate::utils::{
-    FileUpdater, UpdateMode, Version, insert_at_marker, replace_ident_like, rewrite_file, try_rename_file,
-};
+use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, insert_at_marker, rewrite_file, try_rename_file};
 use std::ffi::OsStr;
 use std::path::Path;
 use walkdir::WalkDir;
@@ -66,6 +64,8 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
     );
 
     // Update all lint level attributes. (`clippy::lint_name`)
+    let replacements = &[(&*lint.old_name, &*lint.new_name)];
+    let replacer = StringReplacer::new(replacements);
     for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| {
         let name = f.path().file_name();
         let ext = f.path().extension();
@@ -73,9 +73,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
             && name != Some(OsStr::new("rename.rs"))
             && name != Some(OsStr::new("deprecated_lints.rs"))
     }) {
-        updater.update_file(file.path(), &mut |_, src, dst| {
-            replace_ident_like(&[(&lint.old_name, &lint.new_name)], src, dst)
-        });
+        updater.update_file(file.path(), &mut replacer.replace_ident_fn());
     }
 
     rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| {
@@ -167,6 +165,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
 
         // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
         // renamed.
+        let replacer = StringReplacer::new(replacements);
         for file in clippy_lints_src_files() {
             if file
                 .path()
@@ -174,9 +173,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
                 .to_str()
                 .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs")
             {
-                updater.update_file(file.path(), &mut |_, src, dst| {
-                    replace_ident_like(replacements, src, dst)
-                });
+                updater.update_file(file.path(), &mut replacer.replace_ident_fn());
             }
         }
 
diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs
index aaacdcf65c1..9f48832af00 100644
--- a/clippy_dev/src/utils.rs
+++ b/clippy_dev/src/utils.rs
@@ -1,4 +1,4 @@
-use aho_corasick::AhoCorasickBuilder;
+use aho_corasick::{AhoCorasick, AhoCorasickBuilder};
 use core::fmt::{self, Display};
 use core::str::FromStr;
 use std::env;
@@ -344,33 +344,46 @@ pub fn update_text_region_fn(
     move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert)
 }
 
-/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
-/// were no replacements.
 #[must_use]
-pub fn replace_ident_like(replacements: &[(&str, &str)], src: &str, dst: &mut String) -> UpdateStatus {
-    fn is_ident_char(c: u8) -> bool {
-        matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
-    }
+pub fn is_ident_char(c: u8) -> bool {
+    matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
+}
 
-    let searcher = AhoCorasickBuilder::new()
-        .match_kind(aho_corasick::MatchKind::LeftmostLongest)
-        .build(replacements.iter().map(|&(x, _)| x.as_bytes()))
-        .unwrap();
+pub struct StringReplacer<'a> {
+    searcher: AhoCorasick,
+    replacements: &'a [(&'a str, &'a str)],
+}
+impl<'a> StringReplacer<'a> {
+    #[must_use]
+    pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self {
+        Self {
+            searcher: AhoCorasickBuilder::new()
+                .match_kind(aho_corasick::MatchKind::LeftmostLongest)
+                .build(replacements.iter().map(|&(x, _)| x))
+                .unwrap(),
+            replacements,
+        }
+    }
 
-    let mut pos = 0;
-    let mut changed = false;
-    for m in searcher.find_iter(src) {
-        if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
-            && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0))
-        {
-            dst.push_str(&src[pos..m.start()]);
-            dst.push_str(replacements[m.pattern()].1);
-            pos = m.end();
-            changed = true;
+    /// Replace substrings if they aren't bordered by identifier characters.
+    pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus {
+        move |_, src, dst| {
+            let mut pos = 0;
+            let mut changed = false;
+            for m in self.searcher.find_iter(src) {
+                if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
+                    && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0))
+                {
+                    changed = true;
+                    dst.push_str(&src[pos..m.start()]);
+                    dst.push_str(self.replacements[m.pattern()].1);
+                    pos = m.end();
+                }
+            }
+            dst.push_str(&src[pos..]);
+            UpdateStatus::from_changed(changed)
         }
     }
-    dst.push_str(&src[pos..]);
-    UpdateStatus::from_changed(changed)
 }
 
 #[expect(clippy::must_use_candidate)]