aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion.rs4
-rw-r--r--crates/ra_analysis/src/descriptors/mod.rs8
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs149
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs29
-rw-r--r--crates/ra_analysis/src/imp.rs33
-rw-r--r--crates/ra_analysis/src/lib.rs8
-rw-r--r--crates/ra_analysis/src/syntax_ptr.rs4
-rw-r--r--crates/ra_analysis/tests/tests.rs23
8 files changed, 184 insertions, 74 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs
index 6667c06e7..766df1d96 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion.rs
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
11use crate::{ 11use crate::{
12 db::{self, SyntaxDatabase}, 12 db::{self, SyntaxDatabase},
13 descriptors::function::FnScopes, 13 descriptors::function::FnScopes,
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree}, 14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource},
15 descriptors::DescriptorDatabase, 15 descriptors::DescriptorDatabase,
16 input::FilesDatabase, 16 input::FilesDatabase,
17 Cancelable, FileId, 17 Cancelable, FileId,
@@ -35,7 +35,7 @@ pub(crate) fn resolve_based_completion(
35 let source_root_id = db.file_source_root(file_id); 35 let source_root_id = db.file_source_root(file_id);
36 let file = db.file_syntax(file_id); 36 let file = db.file_syntax(file_id);
37 let module_tree = db.module_tree(source_root_id)?; 37 let module_tree = db.module_tree(source_root_id)?;
38 let module_id = match module_tree.any_module_for_file(file_id) { 38 let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) {
39 None => return Ok(None), 39 None => return Ok(None),
40 Some(it) => it, 40 Some(it) => it,
41 }; 41 };
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs
index eaeef54c1..56bde3849 100644
--- a/crates/ra_analysis/src/descriptors/mod.rs
+++ b/crates/ra_analysis/src/descriptors/mod.rs
@@ -5,16 +5,16 @@ use std::sync::Arc;
5 5
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, AstNode, FnDefNode}, 7 ast::{self, AstNode, FnDefNode},
8 SmolStr, TextRange, 8 TextRange,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 db::SyntaxDatabase, 12 db::SyntaxDatabase,
13 descriptors::function::{resolve_local_name, FnId, FnScopes}, 13 descriptors::function::{resolve_local_name, FnId, FnScopes},
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree}, 14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource},
15 input::SourceRootId, 15 input::SourceRootId,
16 syntax_ptr::LocalSyntaxPtr, 16 syntax_ptr::LocalSyntaxPtr,
17 Cancelable, FileId, 17 Cancelable,
18}; 18};
19 19
20salsa::query_group! { 20salsa::query_group! {
@@ -23,7 +23,7 @@ salsa::query_group! {
23 type ModuleTreeQuery; 23 type ModuleTreeQuery;
24 use fn module::imp::module_tree; 24 use fn module::imp::module_tree;
25 } 25 }
26 fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { 26 fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> {
27 type SubmodulesQuery; 27 type SubmodulesQuery;
28 use fn module::imp::submodules; 28 use fn module::imp::submodules;
29 } 29 }
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index 3a010ecf5..b3b1f1f21 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -19,25 +19,66 @@ use super::{
19 ModuleTree, Problem, 19 ModuleTree, Problem,
20}; 20};
21 21
22#[derive(Clone, Hash, PartialEq, Eq, Debug)]
23pub(crate) enum Submodule {
24 Declaration(SmolStr),
25 Definition(SmolStr, ModuleSource),
26}
27
28impl Submodule {
29 fn name(&self) -> &SmolStr {
30 match self {
31 Submodule::Declaration(name) => name,
32 Submodule::Definition(name, _) => name,
33 }
34 }
35}
36
22pub(crate) fn submodules( 37pub(crate) fn submodules(
23 db: &impl DescriptorDatabase, 38 db: &impl DescriptorDatabase,
24 file_id: FileId, 39 source: ModuleSource,
25) -> Cancelable<Arc<Vec<SmolStr>>> { 40) -> Cancelable<Arc<Vec<Submodule>>> {
26 db::check_canceled(db)?; 41 db::check_canceled(db)?;
27 let file = db.file_syntax(file_id); 42 let file_id = source.file_id();
28 let root = file.ast(); 43 let submodules = match source.resolve(db) {
29 let submodules = modules(root).map(|(name, _)| name).collect(); 44 ModuleSourceNode::Root(it) => collect_submodules(file_id, it.ast()),
30 Ok(Arc::new(submodules)) 45 ModuleSourceNode::Inline(it) => it
46 .ast()
47 .item_list()
48 .map(|it| collect_submodules(file_id, it))
49 .unwrap_or_else(Vec::new),
50 };
51 return Ok(Arc::new(submodules));
52
53 fn collect_submodules<'a>(
54 file_id: FileId,
55 root: impl ast::ModuleItemOwner<'a>,
56 ) -> Vec<Submodule> {
57 modules(root)
58 .map(|(name, m)| {
59 if m.has_semi() {
60 Submodule::Declaration(name)
61 } else {
62 let src = ModuleSource::new_inline(file_id, m);
63 Submodule::Definition(name, src)
64 }
65 })
66 .collect()
67 }
31} 68}
32 69
33pub(crate) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { 70pub(crate) fn modules<'a>(
34 root.modules().filter_map(|module| { 71 root: impl ast::ModuleItemOwner<'a>,
35 let name = module.name()?.text(); 72) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> {
36 if !module.has_semi() { 73 root.items()
37 return None; 74 .filter_map(|item| match item {
38 } 75 ast::ModuleItem::Module(m) => Some(m),
39 Some((name, module)) 76 _ => None,
40 }) 77 })
78 .filter_map(|module| {
79 let name = module.name()?.text();
80 Some((name, module))
81 })
41} 82}
42 83
43pub(crate) fn module_scope( 84pub(crate) fn module_scope(
@@ -66,11 +107,6 @@ pub(crate) fn module_tree(
66 Ok(Arc::new(res)) 107 Ok(Arc::new(res))
67} 108}
68 109
69#[derive(Clone, Hash, PartialEq, Eq, Debug)]
70pub struct Submodule {
71 pub name: SmolStr,
72}
73
74fn create_module_tree<'a>( 110fn create_module_tree<'a>(
75 db: &impl DescriptorDatabase, 111 db: &impl DescriptorDatabase,
76 source_root: SourceRootId, 112 source_root: SourceRootId,
@@ -85,7 +121,8 @@ fn create_module_tree<'a>(
85 121
86 let source_root = db.source_root(source_root); 122 let source_root = db.source_root(source_root);
87 for &file_id in source_root.files.iter() { 123 for &file_id in source_root.files.iter() {
88 if visited.contains(&file_id) { 124 let source = ModuleSource::File(file_id);
125 if visited.contains(&source) {
89 continue; // TODO: use explicit crate_roots here 126 continue; // TODO: use explicit crate_roots here
90 } 127 }
91 assert!(!roots.contains_key(&file_id)); 128 assert!(!roots.contains_key(&file_id));
@@ -96,7 +133,7 @@ fn create_module_tree<'a>(
96 &mut visited, 133 &mut visited,
97 &mut roots, 134 &mut roots,
98 None, 135 None,
99 file_id, 136 source,
100 )?; 137 )?;
101 roots.insert(file_id, module_id); 138 roots.insert(file_id, module_id);
102 } 139 }
@@ -107,36 +144,63 @@ fn build_subtree(
107 db: &impl DescriptorDatabase, 144 db: &impl DescriptorDatabase,
108 source_root: &SourceRoot, 145 source_root: &SourceRoot,
109 tree: &mut ModuleTree, 146 tree: &mut ModuleTree,
110 visited: &mut FxHashSet<FileId>, 147 visited: &mut FxHashSet<ModuleSource>,
111 roots: &mut FxHashMap<FileId, ModuleId>, 148 roots: &mut FxHashMap<FileId, ModuleId>,
112 parent: Option<LinkId>, 149 parent: Option<LinkId>,
113 file_id: FileId, 150 source: ModuleSource,
114) -> Cancelable<ModuleId> { 151) -> Cancelable<ModuleId> {
115 visited.insert(file_id); 152 visited.insert(source);
116 let id = tree.push_mod(ModuleData { 153 let id = tree.push_mod(ModuleData {
117 source: ModuleSource::File(file_id), 154 source,
118 parent, 155 parent,
119 children: Vec::new(), 156 children: Vec::new(),
120 }); 157 });
121 for name in db.submodules(file_id)?.iter() { 158 for sub in db.submodules(source)?.iter() {
122 let (points_to, problem) = resolve_submodule(file_id, name, &source_root.file_resolver);
123 let link = tree.push_link(LinkData { 159 let link = tree.push_link(LinkData {
124 name: name.clone(), 160 name: sub.name().clone(),
125 owner: id, 161 owner: id,
126 points_to: Vec::new(), 162 points_to: Vec::new(),
127 problem: None, 163 problem: None,
128 }); 164 });
129 165
130 let points_to = points_to 166 let (points_to, problem) = match sub {
131 .into_iter() 167 Submodule::Declaration(name) => {
132 .map(|file_id| match roots.remove(&file_id) { 168 let (points_to, problem) =
133 Some(module_id) => { 169 resolve_submodule(source, &name, &source_root.file_resolver);
134 tree.module_mut(module_id).parent = Some(link); 170 let points_to = points_to
135 Ok(module_id) 171 .into_iter()
136 } 172 .map(|file_id| match roots.remove(&file_id) {
137 None => build_subtree(db, source_root, tree, visited, roots, Some(link), file_id), 173 Some(module_id) => {
138 }) 174 tree.module_mut(module_id).parent = Some(link);
139 .collect::<Cancelable<Vec<_>>>()?; 175 Ok(module_id)
176 }
177 None => build_subtree(
178 db,
179 source_root,
180 tree,
181 visited,
182 roots,
183 Some(link),
184 ModuleSource::File(file_id),
185 ),
186 })
187 .collect::<Cancelable<Vec<_>>>()?;
188 (points_to, problem)
189 }
190 Submodule::Definition(_name, submodule_source) => {
191 let points_to = build_subtree(
192 db,
193 source_root,
194 tree,
195 visited,
196 roots,
197 Some(link),
198 *submodule_source,
199 )?;
200 (vec![points_to], None)
201 }
202 };
203
140 tree.link_mut(link).points_to = points_to; 204 tree.link_mut(link).points_to = points_to;
141 tree.link_mut(link).problem = problem; 205 tree.link_mut(link).problem = problem;
142 } 206 }
@@ -144,10 +208,17 @@ fn build_subtree(
144} 208}
145 209
146fn resolve_submodule( 210fn resolve_submodule(
147 file_id: FileId, 211 source: ModuleSource,
148 name: &SmolStr, 212 name: &SmolStr,
149 file_resolver: &FileResolverImp, 213 file_resolver: &FileResolverImp,
150) -> (Vec<FileId>, Option<Problem>) { 214) -> (Vec<FileId>, Option<Problem>) {
215 let file_id = match source {
216 ModuleSource::File(it) => it,
217 ModuleSource::Inline(..) => {
218 // TODO
219 return (Vec::new(), None);
220 }
221 };
151 let mod_name = file_resolver.file_stem(file_id); 222 let mod_name = file_resolver.file_stem(file_id);
152 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; 223 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
153 224
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index e22489fc1..3d799ba05 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -25,17 +25,17 @@ pub(crate) struct ModuleTree {
25} 25}
26 26
27impl ModuleTree { 27impl ModuleTree {
28 pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec<ModuleId> { 28 pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> {
29 self.mods 29 self.mods
30 .iter() 30 .iter()
31 .enumerate() 31 .enumerate()
32 .filter(|(_idx, it)| it.source.is_file(file_id)) 32 .filter(|(_idx, it)| it.source == source)
33 .map(|(idx, _)| ModuleId(idx as u32)) 33 .map(|(idx, _)| ModuleId(idx as u32))
34 .collect() 34 .collect()
35 } 35 }
36 36
37 pub(crate) fn any_module_for_file(&self, file_id: FileId) -> Option<ModuleId> { 37 pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
38 self.modules_for_file(file_id).pop() 38 self.modules_for_source(source).pop()
39 } 39 }
40} 40}
41 41
@@ -142,9 +142,7 @@ impl LinkId {
142 .1; 142 .1;
143 ast.into() 143 ast.into()
144 } 144 }
145 ModuleSourceNode::Inline(..) => { 145 ModuleSourceNode::Inline(it) => it,
146 unimplemented!("https://github.com/rust-analyzer/rust-analyzer/issues/181")
147 }
148 } 146 }
149 } 147 }
150} 148}
@@ -157,6 +155,12 @@ struct ModuleData {
157} 155}
158 156
159impl ModuleSource { 157impl ModuleSource {
158 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource {
159 assert!(!module.has_semi());
160 let ptr = SyntaxPtr::new(file_id, module.syntax());
161 ModuleSource::Inline(ptr)
162 }
163
160 pub(crate) fn as_file(self) -> Option<FileId> { 164 pub(crate) fn as_file(self) -> Option<FileId> {
161 match self { 165 match self {
162 ModuleSource::File(f) => Some(f), 166 ModuleSource::File(f) => Some(f),
@@ -164,6 +168,13 @@ impl ModuleSource {
164 } 168 }
165 } 169 }
166 170
171 pub(crate) fn file_id(self) -> FileId {
172 match self {
173 ModuleSource::File(f) => f,
174 ModuleSource::Inline(ptr) => ptr.file_id(),
175 }
176 }
177
167 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { 178 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode {
168 match self { 179 match self {
169 ModuleSource::File(file_id) => { 180 ModuleSource::File(file_id) => {
@@ -178,10 +189,6 @@ impl ModuleSource {
178 } 189 }
179 } 190 }
180 } 191 }
181
182 fn is_file(self, file_id: FileId) -> bool {
183 self.as_file() == Some(file_id)
184 }
185} 192}
186 193
187#[derive(Hash, Debug, PartialEq, Eq)] 194#[derive(Hash, Debug, PartialEq, Eq)]
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 4f337d163..704648b59 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -220,27 +220,32 @@ impl AnalysisImpl {
220 let source_root = self.db.file_source_root(file_id); 220 let source_root = self.db.file_source_root(file_id);
221 self.db.module_tree(source_root) 221 self.db.module_tree(source_root)
222 } 222 }
223 pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { 223 pub fn parent_module(
224 &self,
225 file_id: FileId,
226 offset: TextUnit,
227 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
224 let module_tree = self.module_tree(file_id)?; 228 let module_tree = self.module_tree(file_id)?;
229 let file = self.db.file_syntax(file_id);
230 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), offset) {
231 Some(m) if !m.has_semi() => ModuleSource::new_inline(file_id, m),
232 _ => ModuleSource::File(file_id),
233 };
225 234
226 let res = module_tree 235 let res = module_tree
227 .modules_for_file(file_id) 236 .modules_for_source(module_source)
228 .into_iter() 237 .into_iter()
229 .filter_map(|module_id| { 238 .filter_map(|module_id| {
230 let link = module_id.parent_link(&module_tree)?; 239 let link = module_id.parent_link(&module_tree)?;
231 let file_id = match link.owner(&module_tree).source(&module_tree) { 240 let file_id = link.owner(&module_tree).source(&module_tree).file_id();
232 ModuleSource::File(file_id) => file_id,
233 ModuleSource::Inline(..) => {
234 //TODO: https://github.com/rust-analyzer/rust-analyzer/issues/181
235 return None;
236 }
237 };
238 let decl = link.bind_source(&module_tree, &*self.db); 241 let decl = link.bind_source(&module_tree, &*self.db);
239 let decl = decl.ast(); 242 let decl = decl.ast();
240 243
244 let decl_name = decl.name().unwrap();
245
241 let sym = FileSymbol { 246 let sym = FileSymbol {
242 name: decl.name().unwrap().text(), 247 name: decl_name.text(),
243 node_range: decl.syntax().range(), 248 node_range: decl_name.syntax().range(),
244 kind: MODULE, 249 kind: MODULE,
245 }; 250 };
246 Some((file_id, sym)) 251 Some((file_id, sym))
@@ -252,7 +257,7 @@ impl AnalysisImpl {
252 let module_tree = self.module_tree(file_id)?; 257 let module_tree = self.module_tree(file_id)?;
253 let crate_graph = self.db.crate_graph(); 258 let crate_graph = self.db.crate_graph();
254 let res = module_tree 259 let res = module_tree
255 .modules_for_file(file_id) 260 .modules_for_source(ModuleSource::File(file_id))
256 .into_iter() 261 .into_iter()
257 .map(|it| it.root(&module_tree)) 262 .map(|it| it.root(&module_tree))
258 .filter_map(|it| it.source(&module_tree).as_file()) 263 .filter_map(|it| it.source(&module_tree).as_file())
@@ -376,7 +381,7 @@ impl AnalysisImpl {
376 fix: None, 381 fix: None,
377 }) 382 })
378 .collect::<Vec<_>>(); 383 .collect::<Vec<_>>();
379 if let Some(m) = module_tree.any_module_for_file(file_id) { 384 if let Some(m) = module_tree.any_module_for_source(ModuleSource::File(file_id)) {
380 for (name_node, problem) in m.problems(&module_tree, &*self.db) { 385 for (name_node, problem) in m.problems(&module_tree, &*self.db) {
381 let diag = match problem { 386 let diag = match problem {
382 Problem::UnresolvedModule { candidate } => { 387 Problem::UnresolvedModule { candidate } => {
@@ -539,7 +544,7 @@ impl AnalysisImpl {
539 Some(name) => name.text(), 544 Some(name) => name.text(),
540 None => return Vec::new(), 545 None => return Vec::new(),
541 }; 546 };
542 let module_id = match module_tree.any_module_for_file(file_id) { 547 let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) {
543 Some(id) => id, 548 Some(id) => id,
544 None => return Vec::new(), 549 None => return Vec::new(),
545 }; 550 };
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 4e4c65f08..fee382151 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -263,8 +263,12 @@ impl Analysis {
263 ) -> Cancelable<Vec<(FileId, TextRange)>> { 263 ) -> Cancelable<Vec<(FileId, TextRange)>> {
264 Ok(self.imp.find_all_refs(file_id, offset)) 264 Ok(self.imp.find_all_refs(file_id, offset))
265 } 265 }
266 pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { 266 pub fn parent_module(
267 self.imp.parent_module(file_id) 267 &self,
268 file_id: FileId,
269 offset: TextUnit,
270 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
271 self.imp.parent_module(file_id, offset)
268 } 272 }
269 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 273 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
270 self.imp.crate_for(file_id) 274 self.imp.crate_for(file_id)
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs
index 4db1529c2..4afb1fc93 100644
--- a/crates/ra_analysis/src/syntax_ptr.rs
+++ b/crates/ra_analysis/src/syntax_ptr.rs
@@ -22,6 +22,10 @@ impl SyntaxPtr {
22 let local = LocalSyntaxPtr::new(node); 22 let local = LocalSyntaxPtr::new(node);
23 SyntaxPtr { file_id, local } 23 SyntaxPtr { file_id, local }
24 } 24 }
25
26 pub(crate) fn file_id(self) -> FileId {
27 self.file_id
28 }
25} 29}
26 30
27/// A pionter to a syntax node inside a file. 31/// A pionter to a syntax node inside a file.
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index c2754c8e4..7f7bb8e6b 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -92,9 +92,28 @@ fn test_resolve_parent_module() {
92 <|>// empty 92 <|>// empty
93 ", 93 ",
94 ); 94 );
95 let symbols = analysis.parent_module(pos.file_id).unwrap(); 95 let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap();
96 assert_eq_dbg( 96 assert_eq_dbg(
97 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, 97 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [4; 7), kind: MODULE })]"#,
98 &symbols,
99 );
100}
101
102#[test]
103fn test_resolve_parent_module_for_inline() {
104 let (analysis, pos) = analysis_and_position(
105 "
106 //- /lib.rs
107 mod foo {
108 mod bar {
109 mod baz { <|> }
110 }
111 }
112 ",
113 );
114 let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap();
115 assert_eq_dbg(
116 r#"[(FileId(1), FileSymbol { name: "bar", node_range: [18; 21), kind: MODULE })]"#,
98 &symbols, 117 &symbols,
99 ); 118 );
100} 119}