diff options
author | Kevin DeLorey <[email protected]> | 2020-02-09 16:25:47 +0000 |
---|---|---|
committer | Kevin DeLorey <[email protected]> | 2020-02-09 16:37:43 +0000 |
commit | a957c473fdb79880c39b73dc9e0c923093cf16ac (patch) | |
tree | f998b548f530ce604651e0e6af314ed2ec74b3b5 /crates/ra_ide/src/references | |
parent | 22caf982b99c54058e2e9200aeea0e61cada284a (diff) | |
parent | 1b9b13b4b4a75b5531c3f046ce6bf72d681f2732 (diff) |
Merge branch 'master' into kdelorey/complete-trait-impl
Diffstat (limited to 'crates/ra_ide/src/references')
-rw-r--r-- | crates/ra_ide/src/references/classify.rs | 140 | ||||
-rw-r--r-- | crates/ra_ide/src/references/name_definition.rs | 85 | ||||
-rw-r--r-- | crates/ra_ide/src/references/rename.rs | 16 | ||||
-rw-r--r-- | crates/ra_ide/src/references/search_scope.rs | 104 |
4 files changed, 80 insertions, 265 deletions
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs index 46cba30a3..d0f03d8a8 100644 --- a/crates/ra_ide/src/references/classify.rs +++ b/crates/ra_ide/src/references/classify.rs | |||
@@ -2,119 +2,13 @@ | |||
2 | 2 | ||
3 | use hir::{InFile, PathResolution, SourceBinder}; | 3 | use hir::{InFile, PathResolution, SourceBinder}; |
4 | use ra_prof::profile; | 4 | use ra_prof::profile; |
5 | use ra_syntax::{ast, match_ast, AstNode}; | 5 | use ra_syntax::{ast, AstNode}; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use super::{ | 8 | use super::{NameDefinition, NameKind}; |
9 | name_definition::{from_assoc_item, from_module_def, from_struct_field}, | 9 | use ra_ide_db::RootDatabase; |
10 | NameDefinition, NameKind, | ||
11 | }; | ||
12 | use crate::db::RootDatabase; | ||
13 | 10 | ||
14 | pub(crate) fn classify_name( | 11 | pub use ra_ide_db::defs::{classify_name, from_module_def, from_struct_field}; |
15 | sb: &mut SourceBinder<RootDatabase>, | ||
16 | name: InFile<&ast::Name>, | ||
17 | ) -> Option<NameDefinition> { | ||
18 | let _p = profile("classify_name"); | ||
19 | let parent = name.value.syntax().parent()?; | ||
20 | |||
21 | match_ast! { | ||
22 | match parent { | ||
23 | ast::BindPat(it) => { | ||
24 | let src = name.with_value(it); | ||
25 | let local = sb.to_def(src)?; | ||
26 | Some(NameDefinition { | ||
27 | visibility: None, | ||
28 | container: local.module(sb.db), | ||
29 | kind: NameKind::Local(local), | ||
30 | }) | ||
31 | }, | ||
32 | ast::RecordFieldDef(it) => { | ||
33 | let src = name.with_value(it); | ||
34 | let field: hir::StructField = sb.to_def(src)?; | ||
35 | Some(from_struct_field(sb.db, field)) | ||
36 | }, | ||
37 | ast::Module(it) => { | ||
38 | let def = sb.to_def(name.with_value(it))?; | ||
39 | Some(from_module_def(sb.db, def.into(), None)) | ||
40 | }, | ||
41 | ast::StructDef(it) => { | ||
42 | let src = name.with_value(it); | ||
43 | let def: hir::Struct = sb.to_def(src)?; | ||
44 | Some(from_module_def(sb.db, def.into(), None)) | ||
45 | }, | ||
46 | ast::EnumDef(it) => { | ||
47 | let src = name.with_value(it); | ||
48 | let def: hir::Enum = sb.to_def(src)?; | ||
49 | Some(from_module_def(sb.db, def.into(), None)) | ||
50 | }, | ||
51 | ast::TraitDef(it) => { | ||
52 | let src = name.with_value(it); | ||
53 | let def: hir::Trait = sb.to_def(src)?; | ||
54 | Some(from_module_def(sb.db, def.into(), None)) | ||
55 | }, | ||
56 | ast::StaticDef(it) => { | ||
57 | let src = name.with_value(it); | ||
58 | let def: hir::Static = sb.to_def(src)?; | ||
59 | Some(from_module_def(sb.db, def.into(), None)) | ||
60 | }, | ||
61 | ast::EnumVariant(it) => { | ||
62 | let src = name.with_value(it); | ||
63 | let def: hir::EnumVariant = sb.to_def(src)?; | ||
64 | Some(from_module_def(sb.db, def.into(), None)) | ||
65 | }, | ||
66 | ast::FnDef(it) => { | ||
67 | let src = name.with_value(it); | ||
68 | let def: hir::Function = sb.to_def(src)?; | ||
69 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
70 | Some(from_assoc_item(sb.db, def.into())) | ||
71 | } else { | ||
72 | Some(from_module_def(sb.db, def.into(), None)) | ||
73 | } | ||
74 | }, | ||
75 | ast::ConstDef(it) => { | ||
76 | let src = name.with_value(it); | ||
77 | let def: hir::Const = sb.to_def(src)?; | ||
78 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
79 | Some(from_assoc_item(sb.db, def.into())) | ||
80 | } else { | ||
81 | Some(from_module_def(sb.db, def.into(), None)) | ||
82 | } | ||
83 | }, | ||
84 | ast::TypeAliasDef(it) => { | ||
85 | let src = name.with_value(it); | ||
86 | let def: hir::TypeAlias = sb.to_def(src)?; | ||
87 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
88 | Some(from_assoc_item(sb.db, def.into())) | ||
89 | } else { | ||
90 | Some(from_module_def(sb.db, def.into(), None)) | ||
91 | } | ||
92 | }, | ||
93 | ast::MacroCall(it) => { | ||
94 | let src = name.with_value(it); | ||
95 | let def = sb.to_def(src.clone())?; | ||
96 | |||
97 | let module = sb.to_module_def(src.file_id.original_file(sb.db))?; | ||
98 | |||
99 | Some(NameDefinition { | ||
100 | visibility: None, | ||
101 | container: module, | ||
102 | kind: NameKind::Macro(def), | ||
103 | }) | ||
104 | }, | ||
105 | ast::TypeParam(it) => { | ||
106 | let src = name.with_value(it); | ||
107 | let def = sb.to_def(src)?; | ||
108 | Some(NameDefinition { | ||
109 | visibility: None, | ||
110 | container: def.module(sb.db), | ||
111 | kind: NameKind::TypeParam(def), | ||
112 | }) | ||
113 | }, | ||
114 | _ => None, | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | 12 | ||
119 | pub(crate) fn classify_name_ref( | 13 | pub(crate) fn classify_name_ref( |
120 | sb: &mut SourceBinder<RootDatabase>, | 14 | sb: &mut SourceBinder<RootDatabase>, |
@@ -128,7 +22,7 @@ pub(crate) fn classify_name_ref( | |||
128 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | 22 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
129 | tested_by!(goto_def_for_methods); | 23 | tested_by!(goto_def_for_methods); |
130 | if let Some(func) = analyzer.resolve_method_call(&method_call) { | 24 | if let Some(func) = analyzer.resolve_method_call(&method_call) { |
131 | return Some(from_assoc_item(sb.db, func.into())); | 25 | return Some(from_module_def(sb.db, func.into(), None)); |
132 | } | 26 | } |
133 | } | 27 | } |
134 | 28 | ||
@@ -163,27 +57,35 @@ pub(crate) fn classify_name_ref( | |||
163 | 57 | ||
164 | let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?; | 58 | let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?; |
165 | let resolved = analyzer.resolve_path(sb.db, &path)?; | 59 | let resolved = analyzer.resolve_path(sb.db, &path)?; |
166 | match resolved { | 60 | let res = match resolved { |
167 | PathResolution::Def(def) => Some(from_module_def(sb.db, def, Some(container))), | 61 | PathResolution::Def(def) => from_module_def(sb.db, def, Some(container)), |
168 | PathResolution::AssocItem(item) => Some(from_assoc_item(sb.db, item)), | 62 | PathResolution::AssocItem(item) => { |
63 | let def = match item { | ||
64 | hir::AssocItem::Function(it) => it.into(), | ||
65 | hir::AssocItem::Const(it) => it.into(), | ||
66 | hir::AssocItem::TypeAlias(it) => it.into(), | ||
67 | }; | ||
68 | from_module_def(sb.db, def, Some(container)) | ||
69 | } | ||
169 | PathResolution::Local(local) => { | 70 | PathResolution::Local(local) => { |
170 | let kind = NameKind::Local(local); | 71 | let kind = NameKind::Local(local); |
171 | let container = local.module(sb.db); | 72 | let container = local.module(sb.db); |
172 | Some(NameDefinition { kind, container, visibility: None }) | 73 | NameDefinition { kind, container, visibility: None } |
173 | } | 74 | } |
174 | PathResolution::TypeParam(par) => { | 75 | PathResolution::TypeParam(par) => { |
175 | let kind = NameKind::TypeParam(par); | 76 | let kind = NameKind::TypeParam(par); |
176 | let container = par.module(sb.db); | 77 | let container = par.module(sb.db); |
177 | Some(NameDefinition { kind, container, visibility }) | 78 | NameDefinition { kind, container, visibility } |
178 | } | 79 | } |
179 | PathResolution::Macro(def) => { | 80 | PathResolution::Macro(def) => { |
180 | let kind = NameKind::Macro(def); | 81 | let kind = NameKind::Macro(def); |
181 | Some(NameDefinition { kind, container, visibility }) | 82 | NameDefinition { kind, container, visibility } |
182 | } | 83 | } |
183 | PathResolution::SelfType(impl_block) => { | 84 | PathResolution::SelfType(impl_block) => { |
184 | let kind = NameKind::SelfType(impl_block); | 85 | let kind = NameKind::SelfType(impl_block); |
185 | let container = impl_block.module(sb.db); | 86 | let container = impl_block.module(sb.db); |
186 | Some(NameDefinition { kind, container, visibility }) | 87 | NameDefinition { kind, container, visibility } |
187 | } | 88 | } |
188 | } | 89 | }; |
90 | Some(res) | ||
189 | } | 91 | } |
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs deleted file mode 100644 index 1e4226ab9..000000000 --- a/crates/ra_ide/src/references/name_definition.rs +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | //! `NameDefinition` keeps information about the element we want to search references for. | ||
2 | //! The element is represented by `NameKind`. It's located inside some `container` and | ||
3 | //! has a `visibility`, which defines a search scope. | ||
4 | //! Note that the reference search is possible for not all of the classified items. | ||
5 | |||
6 | use hir::{ | ||
7 | Adt, AssocItem, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, StructField, | ||
8 | TypeParam, VariantDef, | ||
9 | }; | ||
10 | use ra_syntax::{ast, ast::VisibilityOwner}; | ||
11 | |||
12 | use crate::db::RootDatabase; | ||
13 | |||
14 | #[derive(Debug, PartialEq, Eq)] | ||
15 | pub enum NameKind { | ||
16 | Macro(MacroDef), | ||
17 | Field(StructField), | ||
18 | AssocItem(AssocItem), | ||
19 | Def(ModuleDef), | ||
20 | SelfType(ImplBlock), | ||
21 | Local(Local), | ||
22 | TypeParam(TypeParam), | ||
23 | } | ||
24 | |||
25 | #[derive(PartialEq, Eq)] | ||
26 | pub(crate) struct NameDefinition { | ||
27 | pub visibility: Option<ast::Visibility>, | ||
28 | /// FIXME: this doesn't really make sense. For example, builtin types don't | ||
29 | /// really have a module. | ||
30 | pub container: Module, | ||
31 | pub kind: NameKind, | ||
32 | } | ||
33 | |||
34 | pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { | ||
35 | let container = item.module(db); | ||
36 | let visibility = match item { | ||
37 | AssocItem::Function(f) => f.source(db).value.visibility(), | ||
38 | AssocItem::Const(c) => c.source(db).value.visibility(), | ||
39 | AssocItem::TypeAlias(a) => a.source(db).value.visibility(), | ||
40 | }; | ||
41 | let kind = NameKind::AssocItem(item); | ||
42 | NameDefinition { kind, container, visibility } | ||
43 | } | ||
44 | |||
45 | pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition { | ||
46 | let kind = NameKind::Field(field); | ||
47 | let parent = field.parent_def(db); | ||
48 | let container = parent.module(db); | ||
49 | let visibility = match parent { | ||
50 | VariantDef::Struct(s) => s.source(db).value.visibility(), | ||
51 | VariantDef::Union(e) => e.source(db).value.visibility(), | ||
52 | VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(), | ||
53 | }; | ||
54 | NameDefinition { kind, container, visibility } | ||
55 | } | ||
56 | |||
57 | pub(super) fn from_module_def( | ||
58 | db: &RootDatabase, | ||
59 | def: ModuleDef, | ||
60 | module: Option<Module>, | ||
61 | ) -> NameDefinition { | ||
62 | let kind = NameKind::Def(def); | ||
63 | let (container, visibility) = match def { | ||
64 | ModuleDef::Module(it) => { | ||
65 | let container = it.parent(db).or_else(|| Some(it)).unwrap(); | ||
66 | let visibility = it.declaration_source(db).and_then(|s| s.value.visibility()); | ||
67 | (container, visibility) | ||
68 | } | ||
69 | ModuleDef::EnumVariant(it) => { | ||
70 | let container = it.module(db); | ||
71 | let visibility = it.source(db).value.parent_enum().visibility(); | ||
72 | (container, visibility) | ||
73 | } | ||
74 | ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()), | ||
75 | ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()), | ||
76 | ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()), | ||
77 | ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()), | ||
78 | ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()), | ||
79 | ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()), | ||
80 | ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()), | ||
81 | ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()), | ||
82 | ModuleDef::BuiltinType(..) => (module.unwrap(), None), | ||
83 | }; | ||
84 | NameDefinition { kind, container, visibility } | ||
85 | } | ||
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 626efb603..08e77c01f 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -2,12 +2,14 @@ | |||
2 | 2 | ||
3 | use hir::ModuleSource; | 3 | use hir::ModuleSource; |
4 | use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt}; | 4 | use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt}; |
5 | use ra_syntax::{algo::find_node_at_offset, ast, tokenize, AstNode, SyntaxKind, SyntaxNode}; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | ||
7 | algo::find_node_at_offset, ast, lex_single_valid_syntax_kind, AstNode, SyntaxKind, SyntaxNode, | ||
8 | }; | ||
6 | use ra_text_edit::TextEdit; | 9 | use ra_text_edit::TextEdit; |
7 | 10 | ||
8 | use crate::{ | 11 | use crate::{ |
9 | db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange, | 12 | FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange, SourceFileEdit, TextRange, |
10 | SourceFileEdit, TextRange, | ||
11 | }; | 13 | }; |
12 | 14 | ||
13 | use super::find_all_refs; | 15 | use super::find_all_refs; |
@@ -17,11 +19,9 @@ pub(crate) fn rename( | |||
17 | position: FilePosition, | 19 | position: FilePosition, |
18 | new_name: &str, | 20 | new_name: &str, |
19 | ) -> Option<RangeInfo<SourceChange>> { | 21 | ) -> Option<RangeInfo<SourceChange>> { |
20 | let tokens = tokenize(new_name); | 22 | match lex_single_valid_syntax_kind(new_name)? { |
21 | if tokens.len() != 1 | 23 | SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), |
22 | || (tokens[0].kind != SyntaxKind::IDENT && tokens[0].kind != SyntaxKind::UNDERSCORE) | 24 | _ => return None, |
23 | { | ||
24 | return None; | ||
25 | } | 25 | } |
26 | 26 | ||
27 | let parse = db.parse(position.file_id); | 27 | let parse = db.parse(position.file_id); |
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs index f8211a746..279f57be0 100644 --- a/crates/ra_ide/src/references/search_scope.rs +++ b/crates/ra_ide/src/references/search_scope.rs | |||
@@ -10,7 +10,7 @@ use ra_prof::profile; | |||
10 | use ra_syntax::{AstNode, TextRange}; | 10 | use ra_syntax::{AstNode, TextRange}; |
11 | use rustc_hash::FxHashMap; | 11 | use rustc_hash::FxHashMap; |
12 | 12 | ||
13 | use crate::db::RootDatabase; | 13 | use ra_ide_db::RootDatabase; |
14 | 14 | ||
15 | use super::{NameDefinition, NameKind}; | 15 | use super::{NameDefinition, NameKind}; |
16 | 16 | ||
@@ -19,59 +19,13 @@ pub struct SearchScope { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | impl SearchScope { | 21 | impl SearchScope { |
22 | fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope { | 22 | pub(crate) fn for_def(def: &NameDefinition, db: &RootDatabase) -> SearchScope { |
23 | SearchScope { entries } | ||
24 | } | ||
25 | pub fn single_file(file: FileId) -> SearchScope { | ||
26 | SearchScope::new(std::iter::once((file, None)).collect()) | ||
27 | } | ||
28 | pub(crate) fn intersection(&self, other: &SearchScope) -> SearchScope { | ||
29 | let (mut small, mut large) = (&self.entries, &other.entries); | ||
30 | if small.len() > large.len() { | ||
31 | mem::swap(&mut small, &mut large) | ||
32 | } | ||
33 | |||
34 | let res = small | ||
35 | .iter() | ||
36 | .filter_map(|(file_id, r1)| { | ||
37 | let r2 = large.get(file_id)?; | ||
38 | let r = intersect_ranges(*r1, *r2)?; | ||
39 | Some((*file_id, r)) | ||
40 | }) | ||
41 | .collect(); | ||
42 | return SearchScope::new(res); | ||
43 | |||
44 | fn intersect_ranges( | ||
45 | r1: Option<TextRange>, | ||
46 | r2: Option<TextRange>, | ||
47 | ) -> Option<Option<TextRange>> { | ||
48 | match (r1, r2) { | ||
49 | (None, r) | (r, None) => Some(r), | ||
50 | (Some(r1), Some(r2)) => { | ||
51 | let r = r1.intersection(&r2)?; | ||
52 | Some(Some(r)) | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | impl IntoIterator for SearchScope { | ||
60 | type Item = (FileId, Option<TextRange>); | ||
61 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>; | ||
62 | fn into_iter(self) -> Self::IntoIter { | ||
63 | self.entries.into_iter() | ||
64 | } | ||
65 | } | ||
66 | |||
67 | impl NameDefinition { | ||
68 | pub(crate) fn search_scope(&self, db: &RootDatabase) -> SearchScope { | ||
69 | let _p = profile("search_scope"); | 23 | let _p = profile("search_scope"); |
70 | 24 | ||
71 | let module_src = self.container.definition_source(db); | 25 | let module_src = def.container.definition_source(db); |
72 | let file_id = module_src.file_id.original_file(db); | 26 | let file_id = module_src.file_id.original_file(db); |
73 | 27 | ||
74 | if let NameKind::Local(var) = self.kind { | 28 | if let NameKind::Local(var) = def.kind { |
75 | let range = match var.parent(db) { | 29 | let range = match var.parent(db) { |
76 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | 30 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), |
77 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | 31 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), |
@@ -82,10 +36,10 @@ impl NameDefinition { | |||
82 | return SearchScope::new(res); | 36 | return SearchScope::new(res); |
83 | } | 37 | } |
84 | 38 | ||
85 | let vis = self.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); | 39 | let vis = def.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); |
86 | 40 | ||
87 | if vis.as_str() == "pub(super)" { | 41 | if vis.as_str() == "pub(super)" { |
88 | if let Some(parent_module) = self.container.parent(db) { | 42 | if let Some(parent_module) = def.container.parent(db) { |
89 | let mut res = FxHashMap::default(); | 43 | let mut res = FxHashMap::default(); |
90 | let parent_src = parent_module.definition_source(db); | 44 | let parent_src = parent_module.definition_source(db); |
91 | let file_id = parent_src.file_id.original_file(db); | 45 | let file_id = parent_src.file_id.original_file(db); |
@@ -118,7 +72,7 @@ impl NameDefinition { | |||
118 | return SearchScope::new(res); | 72 | return SearchScope::new(res); |
119 | } | 73 | } |
120 | if vis.as_str() == "pub" { | 74 | if vis.as_str() == "pub" { |
121 | let krate = self.container.krate(); | 75 | let krate = def.container.krate(); |
122 | for rev_dep in krate.reverse_dependencies(db) { | 76 | for rev_dep in krate.reverse_dependencies(db) { |
123 | let root_file = rev_dep.root_file(db); | 77 | let root_file = rev_dep.root_file(db); |
124 | let source_root_id = db.file_source_root(root_file); | 78 | let source_root_id = db.file_source_root(root_file); |
@@ -137,4 +91,48 @@ impl NameDefinition { | |||
137 | res.insert(file_id, range); | 91 | res.insert(file_id, range); |
138 | SearchScope::new(res) | 92 | SearchScope::new(res) |
139 | } | 93 | } |
94 | |||
95 | fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope { | ||
96 | SearchScope { entries } | ||
97 | } | ||
98 | pub fn single_file(file: FileId) -> SearchScope { | ||
99 | SearchScope::new(std::iter::once((file, None)).collect()) | ||
100 | } | ||
101 | pub(crate) fn intersection(&self, other: &SearchScope) -> SearchScope { | ||
102 | let (mut small, mut large) = (&self.entries, &other.entries); | ||
103 | if small.len() > large.len() { | ||
104 | mem::swap(&mut small, &mut large) | ||
105 | } | ||
106 | |||
107 | let res = small | ||
108 | .iter() | ||
109 | .filter_map(|(file_id, r1)| { | ||
110 | let r2 = large.get(file_id)?; | ||
111 | let r = intersect_ranges(*r1, *r2)?; | ||
112 | Some((*file_id, r)) | ||
113 | }) | ||
114 | .collect(); | ||
115 | return SearchScope::new(res); | ||
116 | |||
117 | fn intersect_ranges( | ||
118 | r1: Option<TextRange>, | ||
119 | r2: Option<TextRange>, | ||
120 | ) -> Option<Option<TextRange>> { | ||
121 | match (r1, r2) { | ||
122 | (None, r) | (r, None) => Some(r), | ||
123 | (Some(r1), Some(r2)) => { | ||
124 | let r = r1.intersection(&r2)?; | ||
125 | Some(Some(r)) | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl IntoIterator for SearchScope { | ||
133 | type Item = (FileId, Option<TextRange>); | ||
134 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>; | ||
135 | fn into_iter(self) -> Self::IntoIter { | ||
136 | self.entries.into_iter() | ||
137 | } | ||
140 | } | 138 | } |