aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/module_tree.rs246
-rw-r--r--crates/ra_hir/src/nameres/lower.rs13
-rw-r--r--crates/ra_syntax/src/lib.rs2
-rw-r--r--crates/ra_syntax/src/ptr.rs34
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
136impl ModuleId { 239impl ModuleId {
@@ -198,131 +301,6 @@ impl LinkId {
198 } 301 }
199} 302}
200 303
201impl 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
213fn 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
229fn 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
259fn 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
326fn resolve_submodule( 304fn 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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 SyntaxKind, AstNode, SourceFile, TreeArc, SyntaxNodePtr, 4 SyntaxKind, AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner}, 5 ast::{self, ModuleItemOwner},
6}; 6};
7use ra_db::{SourceRootId}; 7use ra_db::SourceRootId;
8use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 8use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
9 9
10use crate::{ 10use crate::{
@@ -72,13 +72,12 @@ pub struct LoweredModule {
72 72
73#[derive(Debug, Default, PartialEq, Eq)] 73#[derive(Debug, Default, PartialEq, Eq)]
74pub struct ImportSourceMap { 74pub struct ImportSourceMap {
75 map: ArenaMap<ImportId, SyntaxNodePtr>, 75 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
76} 76}
77 77
78impl ImportSourceMap { 78impl 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
49use ra_text_edit::AtomTextEdit; 49use 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 @@
1use std::marker::PhantomData;
2
1use crate::{ 3use 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)]
44pub struct AstPtr<N: AstNode> {
45 ptr: SyntaxNodePtr,
46 _ty: PhantomData<N>,
47}
48
49impl<N: AstNode> Copy for AstPtr<N> {}
50impl<N: AstNode> Clone for AstPtr<N> {
51 fn clone(&self) -> AstPtr<N> {
52 *self
53 }
54}
55
56impl<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]
41fn test_local_syntax_ptr() { 75fn test_local_syntax_ptr() {
42 use crate::{ast, AstNode}; 76 use crate::{ast, AstNode};