about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/base_db/src/input.rs4
-rw-r--r--crates/ide/src/highlight_related.rs17
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide_db/src/search.rs129
4 files changed, 118 insertions, 34 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index f182427e478..08d3bc93ffe 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -97,6 +97,10 @@ impl CrateName {
     pub fn normalize_dashes(name: &str) -> CrateName {
         Self(SmolStr::new(name.replace('-', "_")))
     }
+
+    pub fn as_smol_str(&self) -> &SmolStr {
+        &self.0
+    }
 }
 
 impl fmt::Display for CrateName {
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index de6afaef8e5..054b8f297b5 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -378,7 +378,22 @@ struct Foo;
     fn test_hl_self_in_crate_root() {
         check(
             r#"
-use self$0;
+use crate$0;
+  //^^^^^
+use self;
+  //^^^^
+mod __ {
+    use super;
+      //^^^^^
+}
+"#,
+        );
+        check(
+            r#"
+//- /main.rs crate:main deps:lib
+use lib$0;
+  //^^^
+//- /lib.rs crate:lib
 "#,
         );
     }
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index c5fe7d30c96..949c6dc686b 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -756,7 +756,7 @@ use self$0;
             expect![[r#"
                 Module FileId(0) 0..10
 
-                (no references)
+                FileId(0) 4..8
             "#]],
         );
     }
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 0d0f7b78d81..dcfc2b7bfc7 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -4,7 +4,7 @@
 //! get a super-set of matches. Then, we we confirm each match using precise
 //! name resolution.
 
-use std::{convert::TryInto, mem};
+use std::{convert::TryInto, mem, sync::Arc};
 
 use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 use hir::{
@@ -376,32 +376,63 @@ impl<'a> FindUsages<'a> {
             }
         };
 
-        let name = self.def.name(sema.db).or_else(|| {
-            self.include_self_kw_refs.as_ref().and_then(|ty| {
-                ty.as_adt()
-                    .map(|adt| adt.name(self.sema.db))
-                    .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
-            })
-        });
-        let name = match name {
-            Some(name) => name.to_smol_str(),
+        let name = match self.def {
+            // special case crate modules as these do not have a proper name
+            Definition::Module(module) if module.crate_root(self.sema.db) == module => {
+                // FIXME: This assumes the crate name is always equal to its display name when it really isn't
+                module
+                    .krate()
+                    .display_name(self.sema.db)
+                    .map(|crate_name| crate_name.crate_name().as_smol_str().clone())
+            }
+            _ => {
+                let self_kw_refs = || {
+                    self.include_self_kw_refs.as_ref().and_then(|ty| {
+                        ty.as_adt()
+                            .map(|adt| adt.name(self.sema.db))
+                            .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
+                    })
+                };
+                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str())
+            }
+        };
+        let name = match &name {
+            Some(s) => s.as_str(),
             None => return,
         };
-        let name = name.as_str();
-
-        for (file_id, search_range) in search_scope {
-            let text = sema.db.file_text(file_id);
-            let search_range =
-                search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
-
-            let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
 
-            for (idx, _) in text.match_indices(name) {
+        // these can't be closures because rust infers the lifetimes wrong ...
+        fn match_indices<'a>(
+            text: &'a str,
+            name: &'a str,
+            search_range: TextRange,
+        ) -> impl Iterator<Item = TextSize> + 'a {
+            text.match_indices(name).filter_map(move |(idx, _)| {
                 let offset: TextSize = idx.try_into().unwrap();
                 if !search_range.contains_inclusive(offset) {
-                    continue;
+                    return None;
                 }
+                Some(offset)
+            })
+        }
+        fn scope_files<'a>(
+            sema: &'a Semantics<RootDatabase>,
+            scope: &'a SearchScope,
+        ) -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a {
+            scope.entries.iter().map(|(&file_id, &search_range)| {
+                let text = sema.db.file_text(file_id);
+                let search_range =
+                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
+
+                (text, file_id, search_range)
+            })
+        }
+
+        for (text, file_id, search_range) in scope_files(sema, &search_scope) {
+            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 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),
@@ -412,13 +443,9 @@ impl<'a> FindUsages<'a> {
                     }
                 }
             }
+            // Search for occurrences of the `Self` referring to our type
             if let Some(self_ty) = &self.include_self_kw_refs {
-                for (idx, _) in text.match_indices("Self") {
-                    let offset: TextSize = idx.try_into().unwrap();
-                    if !search_range.contains_inclusive(offset) {
-                        continue;
-                    }
-
+                for offset in match_indices(&text, "Self", 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;
@@ -428,6 +455,37 @@ impl<'a> FindUsages<'a> {
             }
         }
 
+        // Search for `super` and `crate` resolving to our module
+        match self.def {
+            Definition::Module(module) => {
+                let scope = search_scope.intersection(&SearchScope::module(self.sema.db, module));
+
+                let is_crate_root = module.crate_root(self.sema.db) == module;
+
+                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 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) {
+                            for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
+                                if self.found_name_ref(&name_ref, sink) {
+                                    return;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            _ => (),
+        }
+
         // search for module `self` references in our module's definition source
         match self.def {
             Definition::Module(module) if self.search_self_mod => {
@@ -439,18 +497,25 @@ impl<'a> FindUsages<'a> {
                     ModuleSource::SourceFile(_) => (file_id, None),
                 };
 
+                let search_range = if let Some(&range) = search_scope.entries.get(&file_id) {
+                    match (range, search_range) {
+                        (None, range) | (range, None) => range,
+                        (Some(range), Some(search_range)) => match range.intersect(search_range) {
+                            Some(range) => Some(range),
+                            None => return,
+                        },
+                    }
+                } else {
+                    return;
+                };
+
                 let text = sema.db.file_text(file_id);
                 let search_range =
                     search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
 
                 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
 
-                for (idx, _) in text.match_indices("self") {
-                    let offset: TextSize = idx.try_into().unwrap();
-                    if !search_range.contains_inclusive(offset) {
-                        continue;
-                    }
-
+                for offset in match_indices(&text, "self", 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;