diff options
Diffstat (limited to 'crates/ra_ide_db')
-rw-r--r-- | crates/ra_ide_db/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_db/src/search.rs | 147 |
2 files changed, 148 insertions, 0 deletions
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index aa312c140..79f48c9e3 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -9,6 +9,7 @@ pub mod feature_flags; | |||
9 | pub mod symbol_index; | 9 | pub mod symbol_index; |
10 | pub mod change; | 10 | pub mod change; |
11 | pub mod defs; | 11 | pub mod defs; |
12 | pub mod search; | ||
12 | pub mod imports_locator; | 13 | pub mod imports_locator; |
13 | mod wasm_shims; | 14 | mod wasm_shims; |
14 | 15 | ||
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs new file mode 100644 index 000000000..add63b870 --- /dev/null +++ b/crates/ra_ide_db/src/search.rs | |||
@@ -0,0 +1,147 @@ | |||
1 | //! Generally, `search_scope` returns files that might contain references for the element. | ||
2 | //! For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates. | ||
3 | //! In some cases, the location of the references is known to within a `TextRange`, | ||
4 | //! e.g. for things like local variables. | ||
5 | use std::mem; | ||
6 | |||
7 | use hir::{DefWithBody, HasSource, ModuleSource}; | ||
8 | use ra_db::{FileId, SourceDatabaseExt}; | ||
9 | use ra_prof::profile; | ||
10 | use ra_syntax::{AstNode, TextRange}; | ||
11 | use rustc_hash::FxHashMap; | ||
12 | |||
13 | use crate::{defs::Definition, RootDatabase}; | ||
14 | |||
15 | pub struct SearchScope { | ||
16 | entries: FxHashMap<FileId, Option<TextRange>>, | ||
17 | } | ||
18 | |||
19 | impl SearchScope { | ||
20 | fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope { | ||
21 | SearchScope { entries } | ||
22 | } | ||
23 | |||
24 | pub fn empty() -> SearchScope { | ||
25 | SearchScope::new(FxHashMap::default()) | ||
26 | } | ||
27 | |||
28 | pub fn single_file(file: FileId) -> SearchScope { | ||
29 | SearchScope::new(std::iter::once((file, None)).collect()) | ||
30 | } | ||
31 | |||
32 | pub fn for_def(def: &Definition, db: &RootDatabase) -> SearchScope { | ||
33 | let _p = profile("search_scope"); | ||
34 | let module = match def.module(db) { | ||
35 | Some(it) => it, | ||
36 | None => return SearchScope::empty(), | ||
37 | }; | ||
38 | let module_src = module.definition_source(db); | ||
39 | let file_id = module_src.file_id.original_file(db); | ||
40 | |||
41 | if let Definition::Local(var) = def { | ||
42 | let range = match var.parent(db) { | ||
43 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | ||
44 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | ||
45 | DefWithBody::Static(s) => s.source(db).value.syntax().text_range(), | ||
46 | }; | ||
47 | let mut res = FxHashMap::default(); | ||
48 | res.insert(file_id, Some(range)); | ||
49 | return SearchScope::new(res); | ||
50 | } | ||
51 | |||
52 | let vis = def.visibility(db).as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); | ||
53 | |||
54 | if vis.as_str() == "pub(super)" { | ||
55 | if let Some(parent_module) = module.parent(db) { | ||
56 | let mut res = FxHashMap::default(); | ||
57 | let parent_src = parent_module.definition_source(db); | ||
58 | let file_id = parent_src.file_id.original_file(db); | ||
59 | |||
60 | match parent_src.value { | ||
61 | ModuleSource::Module(m) => { | ||
62 | let range = Some(m.syntax().text_range()); | ||
63 | res.insert(file_id, range); | ||
64 | } | ||
65 | ModuleSource::SourceFile(_) => { | ||
66 | res.insert(file_id, None); | ||
67 | res.extend(parent_module.children(db).map(|m| { | ||
68 | let src = m.definition_source(db); | ||
69 | (src.file_id.original_file(db), None) | ||
70 | })); | ||
71 | } | ||
72 | } | ||
73 | return SearchScope::new(res); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | if vis.as_str() != "" { | ||
78 | let source_root_id = db.file_source_root(file_id); | ||
79 | let source_root = db.source_root(source_root_id); | ||
80 | let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>(); | ||
81 | |||
82 | // FIXME: add "pub(in path)" | ||
83 | |||
84 | if vis.as_str() == "pub(crate)" { | ||
85 | return SearchScope::new(res); | ||
86 | } | ||
87 | if vis.as_str() == "pub" { | ||
88 | let krate = module.krate(); | ||
89 | for rev_dep in krate.reverse_dependencies(db) { | ||
90 | let root_file = rev_dep.root_file(db); | ||
91 | let source_root_id = db.file_source_root(root_file); | ||
92 | let source_root = db.source_root(source_root_id); | ||
93 | res.extend(source_root.walk().map(|id| (id, None))); | ||
94 | } | ||
95 | return SearchScope::new(res); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | let mut res = FxHashMap::default(); | ||
100 | let range = match module_src.value { | ||
101 | ModuleSource::Module(m) => Some(m.syntax().text_range()), | ||
102 | ModuleSource::SourceFile(_) => None, | ||
103 | }; | ||
104 | res.insert(file_id, range); | ||
105 | SearchScope::new(res) | ||
106 | } | ||
107 | |||
108 | pub fn intersection(&self, other: &SearchScope) -> SearchScope { | ||
109 | let (mut small, mut large) = (&self.entries, &other.entries); | ||
110 | if small.len() > large.len() { | ||
111 | mem::swap(&mut small, &mut large) | ||
112 | } | ||
113 | |||
114 | let res = small | ||
115 | .iter() | ||
116 | .filter_map(|(file_id, r1)| { | ||
117 | let r2 = large.get(file_id)?; | ||
118 | let r = intersect_ranges(*r1, *r2)?; | ||
119 | Some((*file_id, r)) | ||
120 | }) | ||
121 | .collect(); | ||
122 | |||
123 | return SearchScope::new(res); | ||
124 | |||
125 | fn intersect_ranges( | ||
126 | r1: Option<TextRange>, | ||
127 | r2: Option<TextRange>, | ||
128 | ) -> Option<Option<TextRange>> { | ||
129 | match (r1, r2) { | ||
130 | (None, r) | (r, None) => Some(r), | ||
131 | (Some(r1), Some(r2)) => { | ||
132 | let r = r1.intersection(&r2)?; | ||
133 | Some(Some(r)) | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | impl IntoIterator for SearchScope { | ||
141 | type Item = (FileId, Option<TextRange>); | ||
142 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>; | ||
143 | |||
144 | fn into_iter(self) -> Self::IntoIter { | ||
145 | self.entries.into_iter() | ||
146 | } | ||
147 | } | ||