diff --git a/Cargo.lock b/Cargo.lock index 9f10d92c4e3..eaadcc8b8c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,6 +660,7 @@ dependencies = [ "indexmap", "itertools", "limit", + "memchr", "once_cell", "parser", "profile", diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index a1b0bd6cb30..30272bc16f6 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -20,6 +20,7 @@ either = "1.7.0" itertools = "0.10.3" arrayvec = "0.7.2" indexmap = "1.9.1" +memchr = "2.5.0" stdx = { path = "../stdx", version = "0.0.0" } parser = { path = "../parser", version = "0.0.0" } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 6f885fba783..7cabdb55e8d 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -8,6 +8,7 @@ use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; +use memchr::memmem::Finder; use once_cell::unsync::Lazy; use parser::SyntaxKind; use stdx::hash::NoHashHashMap; @@ -411,14 +412,17 @@ fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) { Some(s) => s.as_str(), None => return, }; + let finder = &Finder::new(name); + let include_self_kw_refs = + self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self"))); - // these can't be closures because rust infers the lifetimes wrong ... + // for<'a> |text: &'a str, name: &'a str, search_range: TextRange| -> impl Iterator + 'a { ... } fn match_indices<'a>( text: &'a str, - name: &'a str, + finder: &'a Finder<'a>, search_range: TextRange, ) -> impl Iterator + 'a { - text.match_indices(name).filter_map(move |(idx, _)| { + finder.find_iter(text.as_bytes()).filter_map(move |idx| { let offset: TextSize = idx.try_into().unwrap(); if !search_range.contains_inclusive(offset) { return None; @@ -427,6 +431,7 @@ fn match_indices<'a>( }) } + // for<'a> |scope: &'a SearchScope| -> impl Iterator, FileId, TextRange)> + 'a { ... } fn scope_files<'a>( sema: &'a Semantics<'_, RootDatabase>, scope: &'a SearchScope, @@ -450,7 +455,7 @@ fn scope_files<'a>( let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); // Search for occurrences of the items name - for offset in match_indices(&text, name, search_range) { + for offset in match_indices(&text, finder, search_range) { for name in sema.find_nodes_at_offset_with_descend(&tree, offset) { if match name { ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), @@ -462,8 +467,8 @@ fn scope_files<'a>( } } // Search for occurrences of the `Self` referring to our type - if let Some(self_ty) = &self.include_self_kw_refs { - for offset in match_indices(&text, "Self", search_range) { + if let Some((self_ty, finder)) = &include_self_kw_refs { + for offset in match_indices(&text, finder, search_range) { for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { return; @@ -479,20 +484,22 @@ fn scope_files<'a>( let scope = search_scope .intersection(&SearchScope::module_and_children(self.sema.db, module)); - let is_crate_root = module.is_crate_root(self.sema.db); + let is_crate_root = + module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); + let finder = &Finder::new("super"); for (text, file_id, search_range) in scope_files(sema, &scope) { let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); - for offset in match_indices(&text, "super", search_range) { + for offset in match_indices(&text, finder, search_range) { for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { if self.found_name_ref(&name_ref, sink) { return; } } } - if is_crate_root { - for offset in match_indices(&text, "crate", search_range) { + if let Some(finder) = &is_crate_root { + for offset in match_indices(&text, finder, search_range) { for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { if self.found_name_ref(&name_ref, sink) { return; @@ -533,8 +540,9 @@ fn scope_files<'a>( search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str()))); let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); + let finder = &Finder::new("self"); - for offset in match_indices(&text, "self", search_range) { + for offset in match_indices(&text, finder, search_range) { for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) { if self.found_self_module_name_ref(&name_ref, sink) { return;