aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/references
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/references')
-rw-r--r--crates/ra_ide/src/references/classify.rs186
-rw-r--r--crates/ra_ide/src/references/name_definition.rs83
-rw-r--r--crates/ra_ide/src/references/rename.rs328
-rw-r--r--crates/ra_ide/src/references/search_scope.rs145
4 files changed, 742 insertions, 0 deletions
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs
new file mode 100644
index 000000000..5cea805ec
--- /dev/null
+++ b/crates/ra_ide/src/references/classify.rs
@@ -0,0 +1,186 @@
1//! Functions that are used to classify an element from its definition or reference.
2
3use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer};
4use ra_prof::profile;
5use ra_syntax::{ast, match_ast, AstNode};
6use test_utils::tested_by;
7
8use super::{
9 name_definition::{from_assoc_item, from_module_def, from_struct_field},
10 NameDefinition, NameKind,
11};
12use crate::db::RootDatabase;
13
14pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Option<NameDefinition> {
15 let _p = profile("classify_name");
16 let parent = name.value.syntax().parent()?;
17
18 match_ast! {
19 match parent {
20 ast::BindPat(it) => {
21 let src = name.with_value(it);
22 let local = hir::Local::from_source(db, src)?;
23 Some(NameDefinition {
24 visibility: None,
25 container: local.module(db),
26 kind: NameKind::Local(local),
27 })
28 },
29 ast::RecordFieldDef(it) => {
30 let ast = hir::FieldSource::Named(it);
31 let src = name.with_value(ast);
32 let field = hir::StructField::from_source(db, src)?;
33 Some(from_struct_field(db, field))
34 },
35 ast::Module(it) => {
36 let def = {
37 if !it.has_semi() {
38 let ast = hir::ModuleSource::Module(it);
39 let src = name.with_value(ast);
40 hir::Module::from_definition(db, src)
41 } else {
42 let src = name.with_value(it);
43 hir::Module::from_declaration(db, src)
44 }
45 }?;
46 Some(from_module_def(db, def.into(), None))
47 },
48 ast::StructDef(it) => {
49 let src = name.with_value(it);
50 let def = hir::Struct::from_source(db, src)?;
51 Some(from_module_def(db, def.into(), None))
52 },
53 ast::EnumDef(it) => {
54 let src = name.with_value(it);
55 let def = hir::Enum::from_source(db, src)?;
56 Some(from_module_def(db, def.into(), None))
57 },
58 ast::TraitDef(it) => {
59 let src = name.with_value(it);
60 let def = hir::Trait::from_source(db, src)?;
61 Some(from_module_def(db, def.into(), None))
62 },
63 ast::StaticDef(it) => {
64 let src = name.with_value(it);
65 let def = hir::Static::from_source(db, src)?;
66 Some(from_module_def(db, def.into(), None))
67 },
68 ast::EnumVariant(it) => {
69 let src = name.with_value(it);
70 let def = hir::EnumVariant::from_source(db, src)?;
71 Some(from_module_def(db, def.into(), None))
72 },
73 ast::FnDef(it) => {
74 let src = name.with_value(it);
75 let def = hir::Function::from_source(db, src)?;
76 if parent.parent().and_then(ast::ItemList::cast).is_some() {
77 Some(from_assoc_item(db, def.into()))
78 } else {
79 Some(from_module_def(db, def.into(), None))
80 }
81 },
82 ast::ConstDef(it) => {
83 let src = name.with_value(it);
84 let def = hir::Const::from_source(db, src)?;
85 if parent.parent().and_then(ast::ItemList::cast).is_some() {
86 Some(from_assoc_item(db, def.into()))
87 } else {
88 Some(from_module_def(db, def.into(), None))
89 }
90 },
91 ast::TypeAliasDef(it) => {
92 let src = name.with_value(it);
93 let def = hir::TypeAlias::from_source(db, src)?;
94 if parent.parent().and_then(ast::ItemList::cast).is_some() {
95 Some(from_assoc_item(db, def.into()))
96 } else {
97 Some(from_module_def(db, def.into(), None))
98 }
99 },
100 ast::MacroCall(it) => {
101 let src = name.with_value(it);
102 let def = hir::MacroDef::from_source(db, src.clone())?;
103
104 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
105 let module = Module::from_definition(db, src.with_value(module_src))?;
106
107 Some(NameDefinition {
108 visibility: None,
109 container: module,
110 kind: NameKind::Macro(def),
111 })
112 },
113 _ => None,
114 }
115 }
116}
117
118pub(crate) fn classify_name_ref(
119 db: &RootDatabase,
120 name_ref: Source<&ast::NameRef>,
121) -> Option<NameDefinition> {
122 let _p = profile("classify_name_ref");
123
124 let parent = name_ref.value.syntax().parent()?;
125 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
126
127 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
128 tested_by!(goto_definition_works_for_methods);
129 if let Some(func) = analyzer.resolve_method_call(&method_call) {
130 return Some(from_assoc_item(db, func.into()));
131 }
132 }
133
134 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
135 tested_by!(goto_definition_works_for_fields);
136 if let Some(field) = analyzer.resolve_field(&field_expr) {
137 return Some(from_struct_field(db, field));
138 }
139 }
140
141 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
142 tested_by!(goto_definition_works_for_record_fields);
143 if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
144 return Some(from_struct_field(db, field_def));
145 }
146 }
147
148 let ast = ModuleSource::from_child_node(db, name_ref.with_value(&parent));
149 // FIXME: find correct container and visibility for each case
150 let container = Module::from_definition(db, name_ref.with_value(ast))?;
151 let visibility = None;
152
153 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
154 tested_by!(goto_definition_works_for_macros);
155 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) {
156 let kind = NameKind::Macro(macro_def);
157 return Some(NameDefinition { kind, container, visibility });
158 }
159 }
160
161 let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?;
162 let resolved = analyzer.resolve_path(db, &path)?;
163 match resolved {
164 PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))),
165 PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)),
166 PathResolution::Local(local) => {
167 let container = local.module(db);
168 let kind = NameKind::Local(local);
169 Some(NameDefinition { kind, container, visibility: None })
170 }
171 PathResolution::GenericParam(par) => {
172 // FIXME: get generic param def
173 let kind = NameKind::GenericParam(par);
174 Some(NameDefinition { kind, container, visibility })
175 }
176 PathResolution::Macro(def) => {
177 let kind = NameKind::Macro(def);
178 Some(NameDefinition { kind, container, visibility })
179 }
180 PathResolution::SelfType(impl_block) => {
181 let kind = NameKind::SelfType(impl_block);
182 let container = impl_block.module(db);
183 Some(NameDefinition { kind, container, visibility })
184 }
185 }
186}
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs
new file mode 100644
index 000000000..10d3a2364
--- /dev/null
+++ b/crates/ra_ide/src/references/name_definition.rs
@@ -0,0 +1,83 @@
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
6use hir::{
7 Adt, AssocItem, GenericParam, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef,
8 StructField, VariantDef,
9};
10use ra_syntax::{ast, ast::VisibilityOwner};
11
12use crate::db::RootDatabase;
13
14#[derive(Debug, PartialEq, Eq)]
15pub enum NameKind {
16 Macro(MacroDef),
17 Field(StructField),
18 AssocItem(AssocItem),
19 Def(ModuleDef),
20 SelfType(ImplBlock),
21 Local(Local),
22 GenericParam(GenericParam),
23}
24
25#[derive(PartialEq, Eq)]
26pub(crate) struct NameDefinition {
27 pub visibility: Option<ast::Visibility>,
28 pub container: Module,
29 pub kind: NameKind,
30}
31
32pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
33 let container = item.module(db);
34 let visibility = match item {
35 AssocItem::Function(f) => f.source(db).value.visibility(),
36 AssocItem::Const(c) => c.source(db).value.visibility(),
37 AssocItem::TypeAlias(a) => a.source(db).value.visibility(),
38 };
39 let kind = NameKind::AssocItem(item);
40 NameDefinition { kind, container, visibility }
41}
42
43pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition {
44 let kind = NameKind::Field(field);
45 let parent = field.parent_def(db);
46 let container = parent.module(db);
47 let visibility = match parent {
48 VariantDef::Struct(s) => s.source(db).value.visibility(),
49 VariantDef::Union(e) => e.source(db).value.visibility(),
50 VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(),
51 };
52 NameDefinition { kind, container, visibility }
53}
54
55pub(super) fn from_module_def(
56 db: &RootDatabase,
57 def: ModuleDef,
58 module: Option<Module>,
59) -> NameDefinition {
60 let kind = NameKind::Def(def);
61 let (container, visibility) = match def {
62 ModuleDef::Module(it) => {
63 let container = it.parent(db).or_else(|| Some(it)).unwrap();
64 let visibility = it.declaration_source(db).and_then(|s| s.value.visibility());
65 (container, visibility)
66 }
67 ModuleDef::EnumVariant(it) => {
68 let container = it.module(db);
69 let visibility = it.source(db).value.parent_enum().visibility();
70 (container, visibility)
71 }
72 ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()),
73 ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()),
74 ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()),
75 ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()),
76 ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()),
77 ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()),
78 ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()),
79 ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()),
80 ModuleDef::BuiltinType(..) => (module.unwrap(), None),
81 };
82 NameDefinition { kind, container, visibility }
83}
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
new file mode 100644
index 000000000..d58496049
--- /dev/null
+++ b/crates/ra_ide/src/references/rename.rs
@@ -0,0 +1,328 @@
1//! FIXME: write short doc here
2
3use hir::ModuleSource;
4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode};
6use ra_text_edit::TextEdit;
7
8use crate::{
9 db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange,
10 SourceFileEdit, TextRange,
11};
12
13use super::find_all_refs;
14
15pub(crate) fn rename(
16 db: &RootDatabase,
17 position: FilePosition,
18 new_name: &str,
19) -> Option<RangeInfo<SourceChange>> {
20 let parse = db.parse(position.file_id);
21 if let Some((ast_name, ast_module)) =
22 find_name_and_module_at_offset(parse.tree().syntax(), position)
23 {
24 let range = ast_name.syntax().text_range();
25 rename_mod(db, &ast_name, &ast_module, position, new_name)
26 .map(|info| RangeInfo::new(range, info))
27 } else {
28 rename_reference(db, position, new_name)
29 }
30}
31
32fn find_name_and_module_at_offset(
33 syntax: &SyntaxNode,
34 position: FilePosition,
35) -> Option<(ast::Name, ast::Module)> {
36 let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?;
37 let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?;
38 Some((ast_name, ast_module))
39}
40
41fn source_edit_from_file_id_range(
42 file_id: FileId,
43 range: TextRange,
44 new_name: &str,
45) -> SourceFileEdit {
46 SourceFileEdit { file_id, edit: TextEdit::replace(range, new_name.into()) }
47}
48
49fn rename_mod(
50 db: &RootDatabase,
51 ast_name: &ast::Name,
52 ast_module: &ast::Module,
53 position: FilePosition,
54 new_name: &str,
55) -> Option<SourceChange> {
56 let mut source_file_edits = Vec::new();
57 let mut file_system_edits = Vec::new();
58 let module_src = hir::Source { file_id: position.file_id.into(), value: ast_module.clone() };
59 if let Some(module) = hir::Module::from_declaration(db, module_src) {
60 let src = module.definition_source(db);
61 let file_id = src.file_id.original_file(db);
62 match src.value {
63 ModuleSource::SourceFile(..) => {
64 let mod_path: RelativePathBuf = db.file_relative_path(file_id);
65 // mod is defined in path/to/dir/mod.rs
66 let dst_path = if mod_path.file_stem() == Some("mod") {
67 mod_path
68 .parent()
69 .and_then(|p| p.parent())
70 .or_else(|| Some(RelativePath::new("")))
71 .map(|p| p.join(new_name).join("mod.rs"))
72 } else {
73 Some(mod_path.with_file_name(new_name).with_extension("rs"))
74 };
75 if let Some(path) = dst_path {
76 let move_file = FileSystemEdit::MoveFile {
77 src: file_id,
78 dst_source_root: db.file_source_root(position.file_id),
79 dst_path: path,
80 };
81 file_system_edits.push(move_file);
82 }
83 }
84 ModuleSource::Module(..) => {}
85 }
86 }
87
88 let edit = SourceFileEdit {
89 file_id: position.file_id,
90 edit: TextEdit::replace(ast_name.syntax().text_range(), new_name.into()),
91 };
92 source_file_edits.push(edit);
93
94 Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
95}
96
97fn rename_reference(
98 db: &RootDatabase,
99 position: FilePosition,
100 new_name: &str,
101) -> Option<RangeInfo<SourceChange>> {
102 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
103
104 let edit = refs
105 .into_iter()
106 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
107 .collect::<Vec<_>>();
108
109 if edit.is_empty() {
110 return None;
111 }
112
113 Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit)))
114}
115
116#[cfg(test)]
117mod tests {
118 use insta::assert_debug_snapshot;
119 use ra_text_edit::TextEditBuilder;
120 use test_utils::assert_eq_text;
121
122 use crate::{
123 mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId,
124 };
125
126 #[test]
127 fn test_rename_for_local() {
128 test_rename(
129 r#"
130 fn main() {
131 let mut i = 1;
132 let j = 1;
133 i = i<|> + j;
134
135 {
136 i = 0;
137 }
138
139 i = 5;
140 }"#,
141 "k",
142 r#"
143 fn main() {
144 let mut k = 1;
145 let j = 1;
146 k = k + j;
147
148 {
149 k = 0;
150 }
151
152 k = 5;
153 }"#,
154 );
155 }
156
157 #[test]
158 fn test_rename_for_param_inside() {
159 test_rename(
160 r#"
161 fn foo(i : u32) -> u32 {
162 i<|>
163 }"#,
164 "j",
165 r#"
166 fn foo(j : u32) -> u32 {
167 j
168 }"#,
169 );
170 }
171
172 #[test]
173 fn test_rename_refs_for_fn_param() {
174 test_rename(
175 r#"
176 fn foo(i<|> : u32) -> u32 {
177 i
178 }"#,
179 "new_name",
180 r#"
181 fn foo(new_name : u32) -> u32 {
182 new_name
183 }"#,
184 );
185 }
186
187 #[test]
188 fn test_rename_for_mut_param() {
189 test_rename(
190 r#"
191 fn foo(mut i<|> : u32) -> u32 {
192 i
193 }"#,
194 "new_name",
195 r#"
196 fn foo(mut new_name : u32) -> u32 {
197 new_name
198 }"#,
199 );
200 }
201
202 #[test]
203 fn test_rename_mod() {
204 let (analysis, position) = analysis_and_position(
205 "
206 //- /lib.rs
207 mod bar;
208
209 //- /bar.rs
210 mod foo<|>;
211
212 //- /bar/foo.rs
213 // emtpy
214 ",
215 );
216 let new_name = "foo2";
217 let source_change = analysis.rename(position, new_name).unwrap();
218 assert_debug_snapshot!(&source_change,
219@r###"
220 Some(
221 RangeInfo {
222 range: [4; 7),
223 info: SourceChange {
224 label: "rename",
225 source_file_edits: [
226 SourceFileEdit {
227 file_id: FileId(
228 2,
229 ),
230 edit: TextEdit {
231 atoms: [
232 AtomTextEdit {
233 delete: [4; 7),
234 insert: "foo2",
235 },
236 ],
237 },
238 },
239 ],
240 file_system_edits: [
241 MoveFile {
242 src: FileId(
243 3,
244 ),
245 dst_source_root: SourceRootId(
246 0,
247 ),
248 dst_path: "bar/foo2.rs",
249 },
250 ],
251 cursor_position: None,
252 },
253 },
254 )
255 "###);
256 }
257
258 #[test]
259 fn test_rename_mod_in_dir() {
260 let (analysis, position) = analysis_and_position(
261 "
262 //- /lib.rs
263 mod fo<|>o;
264 //- /foo/mod.rs
265 // emtpy
266 ",
267 );
268 let new_name = "foo2";
269 let source_change = analysis.rename(position, new_name).unwrap();
270 assert_debug_snapshot!(&source_change,
271 @r###"
272 Some(
273 RangeInfo {
274 range: [4; 7),
275 info: SourceChange {
276 label: "rename",
277 source_file_edits: [
278 SourceFileEdit {
279 file_id: FileId(
280 1,
281 ),
282 edit: TextEdit {
283 atoms: [
284 AtomTextEdit {
285 delete: [4; 7),
286 insert: "foo2",
287 },
288 ],
289 },
290 },
291 ],
292 file_system_edits: [
293 MoveFile {
294 src: FileId(
295 2,
296 ),
297 dst_source_root: SourceRootId(
298 0,
299 ),
300 dst_path: "foo2/mod.rs",
301 },
302 ],
303 cursor_position: None,
304 },
305 },
306 )
307 "###
308 );
309 }
310
311 fn test_rename(text: &str, new_name: &str, expected: &str) {
312 let (analysis, position) = single_file_with_position(text);
313 let source_change = analysis.rename(position, new_name).unwrap();
314 let mut text_edit_builder = TextEditBuilder::default();
315 let mut file_id: Option<FileId> = None;
316 if let Some(change) = source_change {
317 for edit in change.info.source_file_edits {
318 file_id = Some(edit.file_id);
319 for atom in edit.edit.as_atoms() {
320 text_edit_builder.replace(atom.delete, atom.insert.clone());
321 }
322 }
323 }
324 let result =
325 text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()).unwrap());
326 assert_eq_text!(expected, &*result);
327 }
328}
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs
new file mode 100644
index 000000000..f5c9589f4
--- /dev/null
+++ b/crates/ra_ide/src/references/search_scope.rs
@@ -0,0 +1,145 @@
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, SourceDatabase, SourceDatabaseExt};
9use ra_prof::profile;
10use ra_syntax::{AstNode, TextRange};
11use rustc_hash::FxHashMap;
12
13use crate::db::RootDatabase;
14
15use super::{NameDefinition, NameKind};
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
67impl NameDefinition {
68 pub(crate) fn search_scope(&self, db: &RootDatabase) -> SearchScope {
69 let _p = profile("search_scope");
70
71 let module_src = self.container.definition_source(db);
72 let file_id = module_src.file_id.original_file(db);
73
74 if let NameKind::Local(var) = self.kind {
75 let range = match var.parent(db) {
76 DefWithBody::Function(f) => f.source(db).value.syntax().text_range(),
77 DefWithBody::Const(c) => c.source(db).value.syntax().text_range(),
78 DefWithBody::Static(s) => s.source(db).value.syntax().text_range(),
79 };
80 let mut res = FxHashMap::default();
81 res.insert(file_id, Some(range));
82 return SearchScope::new(res);
83 }
84
85 let vis =
86 self.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or("".to_string());
87
88 if vis.as_str() == "pub(super)" {
89 if let Some(parent_module) = self.container.parent(db) {
90 let mut res = FxHashMap::default();
91 let parent_src = parent_module.definition_source(db);
92 let file_id = parent_src.file_id.original_file(db);
93
94 match parent_src.value {
95 ModuleSource::Module(m) => {
96 let range = Some(m.syntax().text_range());
97 res.insert(file_id, range);
98 }
99 ModuleSource::SourceFile(_) => {
100 res.insert(file_id, None);
101 res.extend(parent_module.children(db).map(|m| {
102 let src = m.definition_source(db);
103 (src.file_id.original_file(db), None)
104 }));
105 }
106 }
107 return SearchScope::new(res);
108 }
109 }
110
111 if vis.as_str() != "" {
112 let source_root_id = db.file_source_root(file_id);
113 let source_root = db.source_root(source_root_id);
114 let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>();
115
116 // FIXME: add "pub(in path)"
117
118 if vis.as_str() == "pub(crate)" {
119 return SearchScope::new(res);
120 }
121 if vis.as_str() == "pub" {
122 let krate = self.container.krate();
123 let crate_graph = db.crate_graph();
124 for crate_id in crate_graph.iter() {
125 let mut crate_deps = crate_graph.dependencies(crate_id);
126 if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) {
127 let root_file = crate_graph.crate_root(crate_id);
128 let source_root_id = db.file_source_root(root_file);
129 let source_root = db.source_root(source_root_id);
130 res.extend(source_root.walk().map(|id| (id, None)));
131 }
132 }
133 return SearchScope::new(res);
134 }
135 }
136
137 let mut res = FxHashMap::default();
138 let range = match module_src.value {
139 ModuleSource::Module(m) => Some(m.syntax().text_range()),
140 ModuleSource::SourceFile(_) => None,
141 };
142 res.insert(file_id, range);
143 SearchScope::new(res)
144 }
145}