diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors')
-rw-r--r-- | crates/ra_analysis/src/descriptors/mod.rs | 8 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/imp.rs | 149 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 29 |
3 files changed, 132 insertions, 54 deletions
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 | ||
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | ast::{self, AstNode, FnDefNode}, | 7 | ast::{self, AstNode, FnDefNode}, |
8 | SmolStr, TextRange, | 8 | TextRange, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use 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 | ||
20 | salsa::query_group! { | 20 | salsa::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)] | ||
23 | pub(crate) enum Submodule { | ||
24 | Declaration(SmolStr), | ||
25 | Definition(SmolStr, ModuleSource), | ||
26 | } | ||
27 | |||
28 | impl Submodule { | ||
29 | fn name(&self) -> &SmolStr { | ||
30 | match self { | ||
31 | Submodule::Declaration(name) => name, | ||
32 | Submodule::Definition(name, _) => name, | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
22 | pub(crate) fn submodules( | 37 | pub(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 | ||
33 | pub(crate) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { | 70 | pub(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 | ||
43 | pub(crate) fn module_scope( | 84 | pub(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)] | ||
70 | pub struct Submodule { | ||
71 | pub name: SmolStr, | ||
72 | } | ||
73 | |||
74 | fn create_module_tree<'a>( | 110 | fn 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 | ||
146 | fn resolve_submodule( | 210 | fn 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 | ||
27 | impl ModuleTree { | 27 | impl 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 | ||
159 | impl ModuleSource { | 157 | impl 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)] |