about summary refs log tree commit diff
path: root/clippy_dev/src/utils.rs
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 /clippy_dev/src/utils.rs
parent98cb92f3235c4c963d1c17e8a833f37091b5b487 (diff)
downloadrust-2c85cb0371ca0e8980a4225714ed3407f1670e12.tar.gz
rust-2c85cb0371ca0e8980a4225714ed3407f1670e12.zip
clippy_dev: Only build `AhoCorasick` searcher once for multiple files.
Diffstat (limited to 'clippy_dev/src/utils.rs')
-rw-r--r--clippy_dev/src/utils.rs59
1 files changed, 36 insertions, 23 deletions
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)]