aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/lib.rs5
-rw-r--r--crates/ra_ide_api/src/references.rs61
-rw-r--r--crates/ra_ide_api/src/references/rename.rs6
-rw-r--r--crates/ra_ide_api/src/references/search_scope.rs87
4 files changed, 127 insertions, 32 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 19669a7f0..0832229fd 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -71,7 +71,7 @@ pub use crate::{
71 inlay_hints::{InlayHint, InlayKind}, 71 inlay_hints::{InlayHint, InlayKind},
72 line_index::{LineCol, LineIndex}, 72 line_index::{LineCol, LineIndex},
73 line_index_utils::translate_offset_with_edit, 73 line_index_utils::translate_offset_with_edit,
74 references::ReferenceSearchResult, 74 references::{ReferenceSearchResult, SearchScope},
75 runnables::{Runnable, RunnableKind}, 75 runnables::{Runnable, RunnableKind},
76 syntax_highlighting::HighlightedRange, 76 syntax_highlighting::HighlightedRange,
77}; 77};
@@ -481,8 +481,9 @@ impl Analysis {
481 pub fn find_all_refs( 481 pub fn find_all_refs(
482 &self, 482 &self,
483 position: FilePosition, 483 position: FilePosition,
484 search_scope: Option<SearchScope>,
484 ) -> Cancelable<Option<ReferenceSearchResult>> { 485 ) -> Cancelable<Option<ReferenceSearchResult>> {
485 self.with_db(|db| references::find_all_refs(db, position).map(|it| it.info)) 486 self.with_db(|db| references::find_all_refs(db, position, search_scope).map(|it| it.info))
486 } 487 }
487 488
488 /// Returns a short text describing element at position. 489 /// Returns a short text describing element at position.
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 8200bd1ef..b5b1c9a16 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -27,6 +27,8 @@ pub(crate) use self::{
27 rename::rename, 27 rename::rename,
28}; 28};
29 29
30pub use self::search_scope::SearchScope;
31
30#[derive(Debug, Clone)] 32#[derive(Debug, Clone)]
31pub struct ReferenceSearchResult { 33pub struct ReferenceSearchResult {
32 declaration: NavigationTarget, 34 declaration: NavigationTarget,
@@ -67,6 +69,7 @@ impl IntoIterator for ReferenceSearchResult {
67pub(crate) fn find_all_refs( 69pub(crate) fn find_all_refs(
68 db: &RootDatabase, 70 db: &RootDatabase,
69 position: FilePosition, 71 position: FilePosition,
72 search_scope: Option<SearchScope>,
70) -> Option<RangeInfo<ReferenceSearchResult>> { 73) -> Option<RangeInfo<ReferenceSearchResult>> {
71 let parse = db.parse(position.file_id); 74 let parse = db.parse(position.file_id);
72 let syntax = parse.tree().syntax().clone(); 75 let syntax = parse.tree().syntax().clone();
@@ -86,7 +89,15 @@ pub(crate) fn find_all_refs(
86 NameKind::GenericParam(_) => return None, 89 NameKind::GenericParam(_) => return None,
87 }; 90 };
88 91
89 let references = process_definition(db, def, name); 92 let search_scope = {
93 let base = def.search_scope(db);
94 match search_scope {
95 None => base,
96 Some(scope) => base.intersection(&scope),
97 }
98 };
99
100 let references = process_definition(db, def, name, search_scope);
90 101
91 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 102 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }))
92} 103}
@@ -107,11 +118,15 @@ fn find_name<'a>(
107 Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) 118 Some(RangeInfo::new(range, (name_ref.text().to_string(), def)))
108} 119}
109 120
110fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> Vec<FileRange> { 121fn process_definition(
122 db: &RootDatabase,
123 def: NameDefinition,
124 name: String,
125 scope: SearchScope,
126) -> Vec<FileRange> {
111 let _p = profile("process_definition"); 127 let _p = profile("process_definition");
112 128
113 let pat = name.as_str(); 129 let pat = name.as_str();
114 let scope = def.search_scope(db);
115 let mut refs = vec![]; 130 let mut refs = vec![];
116 131
117 for (file_id, search_range) in scope { 132 for (file_id, search_range) in scope {
@@ -144,8 +159,8 @@ fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> V
144#[cfg(test)] 159#[cfg(test)]
145mod tests { 160mod tests {
146 use crate::{ 161 use crate::{
147 mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, 162 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
148 ReferenceSearchResult, 163 ReferenceSearchResult, SearchScope,
149 }; 164 };
150 165
151 #[test] 166 #[test]
@@ -270,7 +285,7 @@ mod tests {
270 "#; 285 "#;
271 286
272 let (analysis, pos) = analysis_and_position(code); 287 let (analysis, pos) = analysis_and_position(code);
273 let refs = analysis.find_all_refs(pos).unwrap().unwrap(); 288 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
274 assert_eq!(refs.len(), 3); 289 assert_eq!(refs.len(), 3);
275 } 290 }
276 291
@@ -296,7 +311,7 @@ mod tests {
296 "#; 311 "#;
297 312
298 let (analysis, pos) = analysis_and_position(code); 313 let (analysis, pos) = analysis_and_position(code);
299 let refs = analysis.find_all_refs(pos).unwrap().unwrap(); 314 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
300 assert_eq!(refs.len(), 2); 315 assert_eq!(refs.len(), 2);
301 } 316 }
302 317
@@ -321,12 +336,40 @@ mod tests {
321 "#; 336 "#;
322 337
323 let (analysis, pos) = analysis_and_position(code); 338 let (analysis, pos) = analysis_and_position(code);
324 let refs = analysis.find_all_refs(pos).unwrap().unwrap(); 339 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
340 assert_eq!(refs.len(), 3);
341 }
342
343 #[test]
344 fn test_find_all_refs_with_scope() {
345 let code = r#"
346 //- /lib.rs
347 mod foo;
348 mod bar;
349
350 pub fn quux<|>() {}
351
352 //- /foo.rs
353 fn f() { super::quux(); }
354
355 //- /bar.rs
356 fn f() { super::quux(); }
357 "#;
358
359 let (mock, pos) = MockAnalysis::with_files_and_position(code);
360 let bar = mock.id_of("/bar.rs");
361 let analysis = mock.analysis();
362
363 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
325 assert_eq!(refs.len(), 3); 364 assert_eq!(refs.len(), 3);
365
366 let refs =
367 analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap();
368 assert_eq!(refs.len(), 2);
326 } 369 }
327 370
328 fn get_all_refs(text: &str) -> ReferenceSearchResult { 371 fn get_all_refs(text: &str) -> ReferenceSearchResult {
329 let (analysis, position) = single_file_with_position(text); 372 let (analysis, position) = single_file_with_position(text);
330 analysis.find_all_refs(position).unwrap().unwrap() 373 analysis.find_all_refs(position, None).unwrap().unwrap()
331 } 374 }
332} 375}
diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs
index 0e2e088e0..ee6e73e1b 100644
--- a/crates/ra_ide_api/src/references/rename.rs
+++ b/crates/ra_ide_api/src/references/rename.rs
@@ -110,7 +110,7 @@ fn rename_reference(
110 position: FilePosition, 110 position: FilePosition,
111 new_name: &str, 111 new_name: &str,
112) -> Option<RangeInfo<SourceChange>> { 112) -> Option<RangeInfo<SourceChange>> {
113 let RangeInfo { range, info: refs } = find_all_refs(db, position)?; 113 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
114 114
115 let edit = refs 115 let edit = refs
116 .into_iter() 116 .into_iter()
@@ -255,13 +255,13 @@ mod tests {
255 "#; 255 "#;
256 256
257 let (analysis, pos) = analysis_and_position(code); 257 let (analysis, pos) = analysis_and_position(code);
258 let refs = analysis.find_all_refs(pos).unwrap().unwrap(); 258 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
259 assert_eq!(refs.len(), 3); 259 assert_eq!(refs.len(), 3);
260 } 260 }
261 261
262 fn get_all_refs(text: &str) -> ReferenceSearchResult { 262 fn get_all_refs(text: &str) -> ReferenceSearchResult {
263 let (analysis, position) = single_file_with_position(text); 263 let (analysis, position) = single_file_with_position(text);
264 analysis.find_all_refs(position).unwrap().unwrap() 264 analysis.find_all_refs(position, None).unwrap().unwrap()
265 } 265 }
266 266
267 #[test] 267 #[test]
diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs
index 21e667c83..b6eb248b7 100644
--- a/crates/ra_ide_api/src/references/search_scope.rs
+++ b/crates/ra_ide_api/src/references/search_scope.rs
@@ -2,33 +2,84 @@
2//! For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates. 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`, 3//! In some cases, the location of the references is known to within a `TextRange`,
4//! e.g. for things like local variables. 4//! e.g. for things like local variables.
5use std::mem;
5 6
6use hir::{DefWithBody, HasSource, ModuleSource}; 7use hir::{DefWithBody, HasSource, ModuleSource};
7use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; 8use ra_db::{FileId, SourceDatabase, SourceDatabaseExt};
8use ra_prof::profile; 9use ra_prof::profile;
9use ra_syntax::{AstNode, TextRange}; 10use ra_syntax::{AstNode, TextRange};
10use rustc_hash::FxHashSet; 11use rustc_hash::FxHashMap;
11 12
12use crate::db::RootDatabase; 13use crate::db::RootDatabase;
13 14
14use super::{NameDefinition, NameKind}; 15use super::{NameDefinition, NameKind};
15 16
17pub struct SearchScope {
18 entries: FxHashMap<FileId, Option<TextRange>>,
19}
20
21impl SearchScope {
22 fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> 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
59impl 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
16impl NameDefinition { 67impl NameDefinition {
17 pub(crate) fn search_scope(&self, db: &RootDatabase) -> FxHashSet<(FileId, Option<TextRange>)> { 68 pub(crate) fn search_scope(&self, db: &RootDatabase) -> SearchScope {
18 let _p = profile("search_scope"); 69 let _p = profile("search_scope");
19 70
20 let module_src = self.container.definition_source(db); 71 let module_src = self.container.definition_source(db);
21 let file_id = module_src.file_id.original_file(db); 72 let file_id = module_src.file_id.original_file(db);
22 73
23 if let NameKind::Pat((def, _)) = self.kind { 74 if let NameKind::Pat((def, _)) = self.kind {
24 let mut res = FxHashSet::default(); 75 let mut res = FxHashMap::default();
25 let range = match def { 76 let range = match def {
26 DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), 77 DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(),
27 DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), 78 DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(),
28 DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), 79 DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(),
29 }; 80 };
30 res.insert((file_id, Some(range))); 81 res.insert(file_id, Some(range));
31 return res; 82 return SearchScope::new(res);
32 } 83 }
33 84
34 let vis = 85 let vis =
@@ -36,37 +87,37 @@ impl NameDefinition {
36 87
37 if vis.as_str() == "pub(super)" { 88 if vis.as_str() == "pub(super)" {
38 if let Some(parent_module) = self.container.parent(db) { 89 if let Some(parent_module) = self.container.parent(db) {
39 let mut files = FxHashSet::default(); 90 let mut res = FxHashMap::default();
40 let parent_src = parent_module.definition_source(db); 91 let parent_src = parent_module.definition_source(db);
41 let file_id = parent_src.file_id.original_file(db); 92 let file_id = parent_src.file_id.original_file(db);
42 93
43 match parent_src.ast { 94 match parent_src.ast {
44 ModuleSource::Module(m) => { 95 ModuleSource::Module(m) => {
45 let range = Some(m.syntax().text_range()); 96 let range = Some(m.syntax().text_range());
46 files.insert((file_id, range)); 97 res.insert(file_id, range);
47 } 98 }
48 ModuleSource::SourceFile(_) => { 99 ModuleSource::SourceFile(_) => {
49 files.insert((file_id, None)); 100 res.insert(file_id, None);
50 files.extend(parent_module.children(db).map(|m| { 101 res.extend(parent_module.children(db).map(|m| {
51 let src = m.definition_source(db); 102 let src = m.definition_source(db);
52 (src.file_id.original_file(db), None) 103 (src.file_id.original_file(db), None)
53 })); 104 }));
54 } 105 }
55 } 106 }
56 return files; 107 return SearchScope::new(res);
57 } 108 }
58 } 109 }
59 110
60 if vis.as_str() != "" { 111 if vis.as_str() != "" {
61 let source_root_id = db.file_source_root(file_id); 112 let source_root_id = db.file_source_root(file_id);
62 let source_root = db.source_root(source_root_id); 113 let source_root = db.source_root(source_root_id);
63 let mut files = 114 let mut res =
64 source_root.walk().map(|id| (id.into(), None)).collect::<FxHashSet<_>>(); 115 source_root.walk().map(|id| (id.into(), None)).collect::<FxHashMap<_, _>>();
65 116
66 // FIXME: add "pub(in path)" 117 // FIXME: add "pub(in path)"
67 118
68 if vis.as_str() == "pub(crate)" { 119 if vis.as_str() == "pub(crate)" {
69 return files; 120 return SearchScope::new(res);
70 } 121 }
71 if vis.as_str() == "pub" { 122 if vis.as_str() == "pub" {
72 let krate = self.container.krate(db).unwrap(); 123 let krate = self.container.krate(db).unwrap();
@@ -77,19 +128,19 @@ impl NameDefinition {
77 let root_file = crate_graph.crate_root(crate_id); 128 let root_file = crate_graph.crate_root(crate_id);
78 let source_root_id = db.file_source_root(root_file); 129 let source_root_id = db.file_source_root(root_file);
79 let source_root = db.source_root(source_root_id); 130 let source_root = db.source_root(source_root_id);
80 files.extend(source_root.walk().map(|id| (id.into(), None))); 131 res.extend(source_root.walk().map(|id| (id.into(), None)));
81 } 132 }
82 } 133 }
83 return files; 134 return SearchScope::new(res);
84 } 135 }
85 } 136 }
86 137
87 let mut res = FxHashSet::default(); 138 let mut res = FxHashMap::default();
88 let range = match module_src.ast { 139 let range = match module_src.ast {
89 ModuleSource::Module(m) => Some(m.syntax().text_range()), 140 ModuleSource::Module(m) => Some(m.syntax().text_range()),
90 ModuleSource::SourceFile(_) => None, 141 ModuleSource::SourceFile(_) => None,
91 }; 142 };
92 res.insert((file_id, range)); 143 res.insert(file_id, range);
93 res 144 SearchScope::new(res)
94 } 145 }
95} 146}