]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/rust-analyzer/crates/ide-db/src/search.rs
Rollup merge of #102258 - cjgillot:core-kappa, r=m-ou-se
[rust.git] / src / tools / rust-analyzer / crates / ide-db / src / search.rs
index 7deffe8e0f637917c2ab05cac45ee069037caf69..7cabdb55e8d284100a4a272f0888029340742bcb 100644 (file)
@@ -8,7 +8,9 @@
 
 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;
 use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
 
@@ -67,6 +69,7 @@ pub enum ReferenceCategory {
     // Create
     Write,
     Read,
+    Import,
     // FIXME: Some day should be able to search in doc comments. Would probably
     // need to switch from enum to bitflags then?
     // DocComment
@@ -409,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<Item = TextSize> + 'a { ... }
         fn match_indices<'a>(
             text: &'a str,
-            name: &'a str,
+            finder: &'a Finder<'a>,
             search_range: TextRange,
         ) -> impl Iterator<Item = TextSize> + '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;
@@ -425,6 +431,7 @@ fn match_indices<'a>(
             })
         }
 
+        // for<'a> |scope: &'a SearchScope| -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a { ... }
         fn scope_files<'a>(
             sema: &'a Semantics<'_, RootDatabase>,
             scope: &'a SearchScope,
@@ -448,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),
@@ -460,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;
@@ -477,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;
@@ -531,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;
@@ -577,7 +587,7 @@ fn found_self_module_name_ref(
                 let reference = FileReference {
                     range,
                     name: ast::NameLike::NameRef(name_ref.clone()),
-                    category: None,
+                    category: is_name_ref_in_import(name_ref).then(|| ReferenceCategory::Import),
                 };
                 sink(file_id, reference)
             }
@@ -756,7 +766,7 @@ impl ReferenceCategory {
     fn new(def: &Definition, r: &ast::NameRef) -> Option<ReferenceCategory> {
         // Only Locals and Fields have accesses for now.
         if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
-            return None;
+            return is_name_ref_in_import(r).then(|| ReferenceCategory::Import);
         }
 
         let mode = r.syntax().ancestors().find_map(|node| {
@@ -783,3 +793,12 @@ fn new(def: &Definition, r: &ast::NameRef) -> Option<ReferenceCategory> {
         mode.or(Some(ReferenceCategory::Read))
     }
 }
+
+fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool {
+    name_ref
+        .syntax()
+        .parent()
+        .and_then(ast::PathSegment::cast)
+        .and_then(|it| it.parent_path().top_path().syntax().parent())
+        .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE)
+}