Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/search.rs')
| -rw-r--r-- | crates/ide-db/src/search.rs | 106 |
1 files changed, 81 insertions, 25 deletions
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 69459a4b72..f41e293070 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -449,6 +449,8 @@ impl Definition { scope: None, include_self_kw_refs: None, search_self_mod: false, + included_categories: ReferenceCategory::all(), + exclude_library_files: false, } } } @@ -465,6 +467,10 @@ pub struct FindUsages<'a> { include_self_kw_refs: Option<hir::Type<'a>>, /// whether to search for the `self` module search_self_mod: bool, + /// categories to include while collecting usages + included_categories: ReferenceCategory, + /// whether to skip files from library source roots + exclude_library_files: bool, } impl<'a> FindUsages<'a> { @@ -495,6 +501,16 @@ impl<'a> FindUsages<'a> { self } + pub fn set_included_categories(mut self, categories: ReferenceCategory) -> Self { + self.included_categories = categories; + self + } + + pub fn set_exclude_library_files(mut self, exclude_library_files: bool) -> Self { + self.exclude_library_files = exclude_library_files; + self + } + pub fn at_least_one(&self) -> bool { let mut found = false; self.search(&mut |_, _| { @@ -516,14 +532,21 @@ impl<'a> FindUsages<'a> { fn scope_files<'b>( db: &'b RootDatabase, scope: &'b SearchScope, + exclude_library_files: bool, ) -> impl Iterator<Item = (Arc<str>, EditionedFileId, TextRange)> + 'b { - scope.entries.iter().map(|(&file_id, &search_range)| { - let text = db.file_text(file_id.file_id(db)).text(db); - let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&**text))); + scope + .entries + .iter() + .filter(move |(file_id, _)| { + !exclude_library_files || !is_library_file(db, file_id.file_id(db)) + }) + .map(|(&file_id, &search_range)| { + let text = db.file_text(file_id.file_id(db)).text(db); + let search_range = + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&**text))); - (text.clone(), file_id, search_range) - }) + (text.clone(), file_id, search_range) + }) } fn match_indices<'b>( @@ -649,6 +672,7 @@ impl<'a> FindUsages<'a> { fn collect_possible_aliases( sema: &Semantics<'_, RootDatabase>, container: Adt, + exclude_library_files: bool, ) -> Option<(FxHashSet<SmolStr>, Vec<FileRangeWrapper<EditionedFileId>>)> { fn insert_type_alias( db: &RootDatabase, @@ -682,9 +706,11 @@ impl<'a> FindUsages<'a> { }; let finder = Finder::new(current_to_process.as_bytes()); - for (file_text, file_id, search_range) in - FindUsages::scope_files(db, ¤t_to_process_search_scope) - { + for (file_text, file_id, search_range) in FindUsages::scope_files( + db, + ¤t_to_process_search_scope, + exclude_library_files, + ) { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, &finder, search_range) { @@ -869,7 +895,7 @@ impl<'a> FindUsages<'a> { } let Some((container_possible_aliases, is_possibly_self)) = - collect_possible_aliases(self.sema, container) + collect_possible_aliases(self.sema, container, self.exclude_library_files) else { return false; }; @@ -906,7 +932,7 @@ impl<'a> FindUsages<'a> { self, &finder, name, - FindUsages::scope_files(self.sema.db, search_scope), + FindUsages::scope_files(self.sema.db, search_scope, self.exclude_library_files), |path, name_position| { has_any_name(path, |name| container_possible_aliases.contains(name)) && !self_positions.contains(&name_position) @@ -931,6 +957,9 @@ impl<'a> FindUsages<'a> { Some(scope) => base.intersection(scope), } }; + if search_scope.entries.is_empty() { + return; + } let name = match (self.rename, self.def) { (Some(rename), _) => { @@ -982,7 +1011,9 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new(name); let include_self_kw_refs = self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self"))); - for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) { + for (text, file_id, search_range) in + Self::scope_files(sema.db, &search_scope, self.exclude_library_files) + { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); // Search for occurrences of the items name @@ -1039,7 +1070,9 @@ impl<'a> FindUsages<'a> { 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 Self::scope_files(sema.db, &scope) { + for (text, file_id, search_range) in + Self::scope_files(sema.db, &scope, self.exclude_library_files) + { self.sema.db.unwind_if_revision_cancelled(); let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); @@ -1118,6 +1151,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845 let ty_eq = |ty: hir::Type<'_>| match (ty.as_adt(), self_ty.as_adt()) { (Some(ty), Some(self_ty)) => ty == self_ty, @@ -1146,6 +1183,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def @ Definition::Module(_), _)) if def == self.def => { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); @@ -1210,6 +1251,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def, _)) if self.def == def @@ -1241,18 +1286,17 @@ impl<'a> FindUsages<'a> { }; sink(file_id, reference) } - Some(NameRefClass::Definition(def, _)) if self.include_self_kw_refs.is_some() => { - if self.include_self_kw_refs == def_to_ty(self.sema, &def) { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); - let reference = FileReference { - range, - name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(self.sema, &def, name_ref), - }; - sink(file_id, reference) - } else { - false - } + Some(NameRefClass::Definition(def, _)) + if self.include_self_kw_refs.is_some() + && self.include_self_kw_refs == def_to_ty(self.sema, &def) => + { + let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); + let reference = FileReference { + range, + name: FileReferenceNode::NameRef(name_ref.clone()), + category: ReferenceCategory::new(self.sema, &def, name_ref), + }; + sink(file_id, reference) } Some(NameRefClass::FieldShorthand { local_ref: local, @@ -1283,6 +1327,13 @@ impl<'a> FindUsages<'a> { } } + fn is_excluded_name_ref(&self, name_ref: &ast::NameRef) -> bool { + (!self.included_categories.contains(ReferenceCategory::TEST) + && is_name_ref_in_test(self.sema, name_ref)) + || (!self.included_categories.contains(ReferenceCategory::IMPORT) + && is_name_ref_in_import(name_ref)) + } + fn found_name( &self, name: &ast::Name, @@ -1409,3 +1460,8 @@ fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameR None => false, }) } + +fn is_library_file(db: &RootDatabase, file_id: span::FileId) -> bool { + let source_root = db.file_source_root(file_id).source_root_id(db); + db.source_root(source_root).source_root(db).is_library +} |