aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/references.rs2
-rw-r--r--crates/ra_ide/src/references/search_scope.rs144
-rw-r--r--crates/ra_ide_db/src/lib.rs1
-rw-r--r--crates/ra_ide_db/src/search.rs147
4 files changed, 149 insertions, 145 deletions
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 95468d434..6fd46c52d 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -31,7 +31,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
31 31
32pub(crate) use self::rename::rename; 32pub(crate) use self::rename::rename;
33 33
34pub use self::search_scope::SearchScope; 34pub use ra_ide_db::search::SearchScope;
35 35
36#[derive(Debug, Clone)] 36#[derive(Debug, Clone)]
37pub struct ReferenceSearchResult { 37pub struct ReferenceSearchResult {
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs
index d98c84d91..8b1378917 100644
--- a/crates/ra_ide/src/references/search_scope.rs
+++ b/crates/ra_ide/src/references/search_scope.rs
@@ -1,145 +1 @@
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.
5use std::mem;
6
7use hir::{DefWithBody, HasSource, ModuleSource};
8use ra_db::{FileId, SourceDatabaseExt};
9use ra_prof::profile;
10use ra_syntax::{AstNode, TextRange};
11use rustc_hash::FxHashMap;
12
13use ra_ide_db::RootDatabase;
14
15use super::Definition;
16
17pub struct SearchScope {
18 entries: FxHashMap<FileId, Option<TextRange>>,
19}
20
21impl SearchScope {
22 fn empty() -> SearchScope {
23 SearchScope { entries: FxHashMap::default() }
24 }
25
26 pub(crate) fn for_def(def: &Definition, db: &RootDatabase) -> SearchScope {
27 let _p = profile("search_scope");
28 let module = match def.module(db) {
29 Some(it) => it,
30 None => return SearchScope::empty(),
31 };
32 let module_src = module.definition_source(db);
33 let file_id = module_src.file_id.original_file(db);
34
35 if let Definition::Local(var) = def {
36 let range = match var.parent(db) {
37 DefWithBody::Function(f) => f.source(db).value.syntax().text_range(),
38 DefWithBody::Const(c) => c.source(db).value.syntax().text_range(),
39 DefWithBody::Static(s) => s.source(db).value.syntax().text_range(),
40 };
41 let mut res = FxHashMap::default();
42 res.insert(file_id, Some(range));
43 return SearchScope::new(res);
44 }
45
46 let vis = def.visibility(db).as_ref().map(|v| v.syntax().to_string()).unwrap_or_default();
47
48 if vis.as_str() == "pub(super)" {
49 if let Some(parent_module) = module.parent(db) {
50 let mut res = FxHashMap::default();
51 let parent_src = parent_module.definition_source(db);
52 let file_id = parent_src.file_id.original_file(db);
53
54 match parent_src.value {
55 ModuleSource::Module(m) => {
56 let range = Some(m.syntax().text_range());
57 res.insert(file_id, range);
58 }
59 ModuleSource::SourceFile(_) => {
60 res.insert(file_id, None);
61 res.extend(parent_module.children(db).map(|m| {
62 let src = m.definition_source(db);
63 (src.file_id.original_file(db), None)
64 }));
65 }
66 }
67 return SearchScope::new(res);
68 }
69 }
70
71 if vis.as_str() != "" {
72 let source_root_id = db.file_source_root(file_id);
73 let source_root = db.source_root(source_root_id);
74 let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>();
75
76 // FIXME: add "pub(in path)"
77
78 if vis.as_str() == "pub(crate)" {
79 return SearchScope::new(res);
80 }
81 if vis.as_str() == "pub" {
82 let krate = module.krate();
83 for rev_dep in krate.reverse_dependencies(db) {
84 let root_file = rev_dep.root_file(db);
85 let source_root_id = db.file_source_root(root_file);
86 let source_root = db.source_root(source_root_id);
87 res.extend(source_root.walk().map(|id| (id, None)));
88 }
89 return SearchScope::new(res);
90 }
91 }
92
93 let mut res = FxHashMap::default();
94 let range = match module_src.value {
95 ModuleSource::Module(m) => Some(m.syntax().text_range()),
96 ModuleSource::SourceFile(_) => None,
97 };
98 res.insert(file_id, range);
99 SearchScope::new(res)
100 }
101
102 fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope {
103 SearchScope { entries }
104 }
105 pub fn single_file(file: FileId) -> SearchScope {
106 SearchScope::new(std::iter::once((file, None)).collect())
107 }
108 pub(crate) 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 return SearchScope::new(res);
123
124 fn intersect_ranges(
125 r1: Option<TextRange>,
126 r2: Option<TextRange>,
127 ) -> Option<Option<TextRange>> {
128 match (r1, r2) {
129 (None, r) | (r, None) => Some(r),
130 (Some(r1), Some(r2)) => {
131 let r = r1.intersection(&r2)?;
132 Some(Some(r))
133 }
134 }
135 }
136 }
137}
138
139impl IntoIterator for SearchScope {
140 type Item = (FileId, Option<TextRange>);
141 type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>;
142 fn into_iter(self) -> Self::IntoIter {
143 self.entries.into_iter()
144 }
145}
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;
9pub mod symbol_index; 9pub mod symbol_index;
10pub mod change; 10pub mod change;
11pub mod defs; 11pub mod defs;
12pub mod search;
12pub mod imports_locator; 13pub mod imports_locator;
13mod wasm_shims; 14mod 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.
5use std::mem;
6
7use hir::{DefWithBody, HasSource, ModuleSource};
8use ra_db::{FileId, SourceDatabaseExt};
9use ra_prof::profile;
10use ra_syntax::{AstNode, TextRange};
11use rustc_hash::FxHashMap;
12
13use crate::{defs::Definition, RootDatabase};
14
15pub struct SearchScope {
16 entries: FxHashMap<FileId, Option<TextRange>>,
17}
18
19impl 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
140impl 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}