diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/module_tree.rs | 246 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 13 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ptr.rs | 34 |
4 files changed, 152 insertions, 143 deletions
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index 47c14af35..b201bf69b 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs | |||
@@ -62,14 +62,26 @@ impl Submodule { | |||
62 | file_items: &SourceFileItems, | 62 | file_items: &SourceFileItems, |
63 | root: &impl ast::ModuleItemOwner, | 63 | root: &impl ast::ModuleItemOwner, |
64 | ) -> Vec<Submodule> { | 64 | ) -> Vec<Submodule> { |
65 | modules(root) | 65 | root.items() |
66 | .map(|(name, m)| Submodule { | 66 | .filter_map(|item| match item.kind() { |
67 | name, | 67 | ast::ModuleItemKind::Module(m) => Some(m), |
68 | is_declaration: m.has_semi(), | 68 | _ => None, |
69 | source: SourceItemId { | 69 | }) |
70 | file_id, | 70 | .filter_map(|module| { |
71 | item_id: Some(file_items.id_of(file_id, m.syntax())), | 71 | let name = module.name()?.as_name(); |
72 | }, | 72 | if !module.has_semi() && module.item_list().is_none() { |
73 | tested_by!(name_res_works_for_broken_modules); | ||
74 | return None; | ||
75 | } | ||
76 | let sub = Submodule { | ||
77 | name, | ||
78 | is_declaration: module.has_semi(), | ||
79 | source: SourceItemId { | ||
80 | file_id, | ||
81 | item_id: Some(file_items.id_of(file_id, module.syntax())), | ||
82 | }, | ||
83 | }; | ||
84 | Some(sub) | ||
73 | }) | 85 | }) |
74 | .collect() | 86 | .collect() |
75 | } | 87 | } |
@@ -119,7 +131,8 @@ impl ModuleTree { | |||
119 | source_root: SourceRootId, | 131 | source_root: SourceRootId, |
120 | ) -> Arc<ModuleTree> { | 132 | ) -> Arc<ModuleTree> { |
121 | db.check_canceled(); | 133 | db.check_canceled(); |
122 | let res = create_module_tree(db, source_root); | 134 | let mut res = ModuleTree::default(); |
135 | res.init(db, source_root); | ||
123 | Arc::new(res) | 136 | Arc::new(res) |
124 | } | 137 | } |
125 | 138 | ||
@@ -131,6 +144,96 @@ impl ModuleTree { | |||
131 | let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?; | 144 | let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?; |
132 | Some(res) | 145 | Some(res) |
133 | } | 146 | } |
147 | |||
148 | fn init(&mut self, db: &impl HirDatabase, source_root: SourceRootId) { | ||
149 | let mut roots = FxHashMap::default(); | ||
150 | let mut visited = FxHashSet::default(); | ||
151 | |||
152 | let source_root = db.source_root(source_root); | ||
153 | for &file_id in source_root.files.values() { | ||
154 | let source = SourceItemId { | ||
155 | file_id: file_id.into(), | ||
156 | item_id: None, | ||
157 | }; | ||
158 | if visited.contains(&source) { | ||
159 | continue; // TODO: use explicit crate_roots here | ||
160 | } | ||
161 | assert!(!roots.contains_key(&file_id)); | ||
162 | let module_id = | ||
163 | self.init_subtree(db, &source_root, &mut visited, &mut roots, None, source); | ||
164 | roots.insert(file_id, module_id); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | fn init_subtree( | ||
169 | &mut self, | ||
170 | db: &impl HirDatabase, | ||
171 | source_root: &SourceRoot, | ||
172 | visited: &mut FxHashSet<SourceItemId>, | ||
173 | roots: &mut FxHashMap<FileId, ModuleId>, | ||
174 | parent: Option<LinkId>, | ||
175 | source: SourceItemId, | ||
176 | ) -> ModuleId { | ||
177 | visited.insert(source); | ||
178 | let id = self.alloc_mod(ModuleData { | ||
179 | source, | ||
180 | parent, | ||
181 | children: Vec::new(), | ||
182 | }); | ||
183 | for sub in db.submodules(source).iter() { | ||
184 | let link = self.alloc_link(LinkData { | ||
185 | source: sub.source, | ||
186 | name: sub.name.clone(), | ||
187 | owner: id, | ||
188 | points_to: Vec::new(), | ||
189 | problem: None, | ||
190 | }); | ||
191 | |||
192 | let (points_to, problem) = if sub.is_declaration { | ||
193 | let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); | ||
194 | let points_to = points_to | ||
195 | .into_iter() | ||
196 | .map(|file_id| match roots.remove(&file_id) { | ||
197 | Some(module_id) => { | ||
198 | self.mods[module_id].parent = Some(link); | ||
199 | module_id | ||
200 | } | ||
201 | None => self.init_subtree( | ||
202 | db, | ||
203 | source_root, | ||
204 | visited, | ||
205 | roots, | ||
206 | Some(link), | ||
207 | SourceItemId { | ||
208 | file_id: file_id.into(), | ||
209 | item_id: None, | ||
210 | }, | ||
211 | ), | ||
212 | }) | ||
213 | .collect::<Vec<_>>(); | ||
214 | (points_to, problem) | ||
215 | } else { | ||
216 | let points_to = | ||
217 | self.init_subtree(db, source_root, visited, roots, Some(link), sub.source); | ||
218 | (vec![points_to], None) | ||
219 | }; | ||
220 | |||
221 | self.links[link].points_to = points_to; | ||
222 | self.links[link].problem = problem; | ||
223 | } | ||
224 | id | ||
225 | } | ||
226 | |||
227 | fn alloc_mod(&mut self, data: ModuleData) -> ModuleId { | ||
228 | self.mods.alloc(data) | ||
229 | } | ||
230 | |||
231 | fn alloc_link(&mut self, data: LinkData) -> LinkId { | ||
232 | let owner = data.owner; | ||
233 | let id = self.links.alloc(data); | ||
234 | self.mods[owner].children.push(id); | ||
235 | id | ||
236 | } | ||
134 | } | 237 | } |
135 | 238 | ||
136 | impl ModuleId { | 239 | impl ModuleId { |
@@ -198,131 +301,6 @@ impl LinkId { | |||
198 | } | 301 | } |
199 | } | 302 | } |
200 | 303 | ||
201 | impl ModuleTree { | ||
202 | fn push_mod(&mut self, data: ModuleData) -> ModuleId { | ||
203 | self.mods.alloc(data) | ||
204 | } | ||
205 | fn push_link(&mut self, data: LinkData) -> LinkId { | ||
206 | let owner = data.owner; | ||
207 | let id = self.links.alloc(data); | ||
208 | self.mods[owner].children.push(id); | ||
209 | id | ||
210 | } | ||
211 | } | ||
212 | |||
213 | fn modules(root: &impl ast::ModuleItemOwner) -> impl Iterator<Item = (Name, &ast::Module)> { | ||
214 | root.items() | ||
215 | .filter_map(|item| match item.kind() { | ||
216 | ast::ModuleItemKind::Module(m) => Some(m), | ||
217 | _ => None, | ||
218 | }) | ||
219 | .filter_map(|module| { | ||
220 | let name = module.name()?.as_name(); | ||
221 | if !module.has_semi() && module.item_list().is_none() { | ||
222 | tested_by!(name_res_works_for_broken_modules); | ||
223 | return None; | ||
224 | } | ||
225 | Some((name, module)) | ||
226 | }) | ||
227 | } | ||
228 | |||
229 | fn create_module_tree<'a>(db: &impl HirDatabase, source_root: SourceRootId) -> ModuleTree { | ||
230 | let mut tree = ModuleTree::default(); | ||
231 | |||
232 | let mut roots = FxHashMap::default(); | ||
233 | let mut visited = FxHashSet::default(); | ||
234 | |||
235 | let source_root = db.source_root(source_root); | ||
236 | for &file_id in source_root.files.values() { | ||
237 | let source = SourceItemId { | ||
238 | file_id: file_id.into(), | ||
239 | item_id: None, | ||
240 | }; | ||
241 | if visited.contains(&source) { | ||
242 | continue; // TODO: use explicit crate_roots here | ||
243 | } | ||
244 | assert!(!roots.contains_key(&file_id)); | ||
245 | let module_id = build_subtree( | ||
246 | db, | ||
247 | &source_root, | ||
248 | &mut tree, | ||
249 | &mut visited, | ||
250 | &mut roots, | ||
251 | None, | ||
252 | source, | ||
253 | ); | ||
254 | roots.insert(file_id, module_id); | ||
255 | } | ||
256 | tree | ||
257 | } | ||
258 | |||
259 | fn build_subtree( | ||
260 | db: &impl HirDatabase, | ||
261 | source_root: &SourceRoot, | ||
262 | tree: &mut ModuleTree, | ||
263 | visited: &mut FxHashSet<SourceItemId>, | ||
264 | roots: &mut FxHashMap<FileId, ModuleId>, | ||
265 | parent: Option<LinkId>, | ||
266 | source: SourceItemId, | ||
267 | ) -> ModuleId { | ||
268 | visited.insert(source); | ||
269 | let id = tree.push_mod(ModuleData { | ||
270 | source, | ||
271 | parent, | ||
272 | children: Vec::new(), | ||
273 | }); | ||
274 | for sub in db.submodules(source).iter() { | ||
275 | let link = tree.push_link(LinkData { | ||
276 | source: sub.source, | ||
277 | name: sub.name.clone(), | ||
278 | owner: id, | ||
279 | points_to: Vec::new(), | ||
280 | problem: None, | ||
281 | }); | ||
282 | |||
283 | let (points_to, problem) = if sub.is_declaration { | ||
284 | let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); | ||
285 | let points_to = points_to | ||
286 | .into_iter() | ||
287 | .map(|file_id| match roots.remove(&file_id) { | ||
288 | Some(module_id) => { | ||
289 | tree.mods[module_id].parent = Some(link); | ||
290 | module_id | ||
291 | } | ||
292 | None => build_subtree( | ||
293 | db, | ||
294 | source_root, | ||
295 | tree, | ||
296 | visited, | ||
297 | roots, | ||
298 | Some(link), | ||
299 | SourceItemId { | ||
300 | file_id: file_id.into(), | ||
301 | item_id: None, | ||
302 | }, | ||
303 | ), | ||
304 | }) | ||
305 | .collect::<Vec<_>>(); | ||
306 | (points_to, problem) | ||
307 | } else { | ||
308 | let points_to = build_subtree( | ||
309 | db, | ||
310 | source_root, | ||
311 | tree, | ||
312 | visited, | ||
313 | roots, | ||
314 | Some(link), | ||
315 | sub.source, | ||
316 | ); | ||
317 | (vec![points_to], None) | ||
318 | }; | ||
319 | |||
320 | tree.links[link].points_to = points_to; | ||
321 | tree.links[link].problem = problem; | ||
322 | } | ||
323 | id | ||
324 | } | ||
325 | |||
326 | fn resolve_submodule( | 304 | fn resolve_submodule( |
327 | db: &impl HirDatabase, | 305 | db: &impl HirDatabase, |
328 | file_id: HirFileId, | 306 | file_id: HirFileId, |
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index ab6f3a9bc..921ba3c98 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | SyntaxKind, AstNode, SourceFile, TreeArc, SyntaxNodePtr, | 4 | SyntaxKind, AstNode, SourceFile, TreeArc, AstPtr, |
5 | ast::{self, ModuleItemOwner}, | 5 | ast::{self, ModuleItemOwner}, |
6 | }; | 6 | }; |
7 | use ra_db::{SourceRootId}; | 7 | use ra_db::SourceRootId; |
8 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 8 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
@@ -72,13 +72,12 @@ pub struct LoweredModule { | |||
72 | 72 | ||
73 | #[derive(Debug, Default, PartialEq, Eq)] | 73 | #[derive(Debug, Default, PartialEq, Eq)] |
74 | pub struct ImportSourceMap { | 74 | pub struct ImportSourceMap { |
75 | map: ArenaMap<ImportId, SyntaxNodePtr>, | 75 | map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>, |
76 | } | 76 | } |
77 | 77 | ||
78 | impl ImportSourceMap { | 78 | impl ImportSourceMap { |
79 | fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { | 79 | fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { |
80 | self.map | 80 | self.map.insert(import, AstPtr::new(segment)) |
81 | .insert(import, SyntaxNodePtr::new(segment.syntax())) | ||
82 | } | 81 | } |
83 | 82 | ||
84 | pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { | 83 | pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { |
@@ -87,9 +86,7 @@ impl ImportSourceMap { | |||
87 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | 86 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), |
88 | }; | 87 | }; |
89 | 88 | ||
90 | ast::PathSegment::cast(self.map[import].to_node(file)) | 89 | self.map[import].to_node(file).to_owned() |
91 | .unwrap() | ||
92 | .to_owned() | ||
93 | } | 90 | } |
94 | } | 91 | } |
95 | 92 | ||
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 97b196118..104f32851 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -43,7 +43,7 @@ pub use crate::{ | |||
43 | lexer::{tokenize, Token}, | 43 | lexer::{tokenize, Token}, |
44 | syntax_kinds::SyntaxKind, | 44 | syntax_kinds::SyntaxKind, |
45 | yellow::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc}, | 45 | yellow::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc}, |
46 | ptr::SyntaxNodePtr, | 46 | ptr::{SyntaxNodePtr, AstPtr}, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | use ra_text_edit::AtomTextEdit; | 49 | use ra_text_edit::AtomTextEdit; |
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs index e8c40e5d3..b50cd8a52 100644 --- a/crates/ra_syntax/src/ptr.rs +++ b/crates/ra_syntax/src/ptr.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::marker::PhantomData; | ||
2 | |||
1 | use crate::{ | 3 | use crate::{ |
2 | AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, | 4 | AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, |
3 | algo::generate, | 5 | algo::generate, |
@@ -37,6 +39,38 @@ impl SyntaxNodePtr { | |||
37 | } | 39 | } |
38 | } | 40 | } |
39 | 41 | ||
42 | /// Like `SyntaxNodePtr`, but remembers the type of node | ||
43 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
44 | pub struct AstPtr<N: AstNode> { | ||
45 | ptr: SyntaxNodePtr, | ||
46 | _ty: PhantomData<N>, | ||
47 | } | ||
48 | |||
49 | impl<N: AstNode> Copy for AstPtr<N> {} | ||
50 | impl<N: AstNode> Clone for AstPtr<N> { | ||
51 | fn clone(&self) -> AstPtr<N> { | ||
52 | *self | ||
53 | } | ||
54 | } | ||
55 | |||
56 | impl<N: AstNode> AstPtr<N> { | ||
57 | pub fn new(node: &N) -> AstPtr<N> { | ||
58 | AstPtr { | ||
59 | ptr: SyntaxNodePtr::new(node.syntax()), | ||
60 | _ty: PhantomData, | ||
61 | } | ||
62 | } | ||
63 | |||
64 | pub fn to_node(self, source_file: &SourceFile) -> &N { | ||
65 | let syntax_node = self.ptr.to_node(source_file); | ||
66 | N::cast(syntax_node).unwrap() | ||
67 | } | ||
68 | |||
69 | pub fn syntax_node_ptr(self) -> SyntaxNodePtr { | ||
70 | self.ptr | ||
71 | } | ||
72 | } | ||
73 | |||
40 | #[test] | 74 | #[test] |
41 | fn test_local_syntax_ptr() { | 75 | fn test_local_syntax_ptr() { |
42 | use crate::{ast, AstNode}; | 76 | use crate::{ast, AstNode}; |