diff options
Diffstat (limited to 'crates/ra_hir/src/module/imp.rs')
-rw-r--r-- | crates/ra_hir/src/module/imp.rs | 190 |
1 files changed, 0 insertions, 190 deletions
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs deleted file mode 100644 index 3849026db..000000000 --- a/crates/ra_hir/src/module/imp.rs +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_syntax::ast::{self, NameOwner}; | ||
4 | use relative_path::RelativePathBuf; | ||
5 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
6 | use arrayvec::ArrayVec; | ||
7 | use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; | ||
8 | |||
9 | use crate::{ | ||
10 | HirDatabase, Name, AsName, | ||
11 | }; | ||
12 | |||
13 | use super::{ | ||
14 | LinkData, LinkId, ModuleData, ModuleId, ModuleSource, | ||
15 | ModuleTree, Problem, | ||
16 | }; | ||
17 | |||
18 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] | ||
19 | pub enum Submodule { | ||
20 | Declaration(Name), | ||
21 | Definition(Name, ModuleSource), | ||
22 | } | ||
23 | |||
24 | impl Submodule { | ||
25 | fn name(&self) -> &Name { | ||
26 | match self { | ||
27 | Submodule::Declaration(name) => name, | ||
28 | Submodule::Definition(name, _) => name, | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | pub(crate) fn modules<'a>( | ||
34 | root: impl ast::ModuleItemOwner<'a>, | ||
35 | ) -> impl Iterator<Item = (Name, ast::Module<'a>)> { | ||
36 | root.items() | ||
37 | .filter_map(|item| match item { | ||
38 | ast::ModuleItem::Module(m) => Some(m), | ||
39 | _ => None, | ||
40 | }) | ||
41 | .filter_map(|module| { | ||
42 | let name = module.name()?.as_name(); | ||
43 | Some((name, module)) | ||
44 | }) | ||
45 | } | ||
46 | |||
47 | pub(crate) fn module_tree( | ||
48 | db: &impl HirDatabase, | ||
49 | source_root: SourceRootId, | ||
50 | ) -> Cancelable<Arc<ModuleTree>> { | ||
51 | db.check_canceled()?; | ||
52 | let res = create_module_tree(db, source_root)?; | ||
53 | Ok(Arc::new(res)) | ||
54 | } | ||
55 | |||
56 | fn create_module_tree<'a>( | ||
57 | db: &impl HirDatabase, | ||
58 | source_root: SourceRootId, | ||
59 | ) -> Cancelable<ModuleTree> { | ||
60 | let mut tree = ModuleTree::default(); | ||
61 | |||
62 | let mut roots = FxHashMap::default(); | ||
63 | let mut visited = FxHashSet::default(); | ||
64 | |||
65 | let source_root = db.source_root(source_root); | ||
66 | for &file_id in source_root.files.values() { | ||
67 | let source = ModuleSource::new_file(file_id.into()); | ||
68 | if visited.contains(&source) { | ||
69 | continue; // TODO: use explicit crate_roots here | ||
70 | } | ||
71 | assert!(!roots.contains_key(&file_id)); | ||
72 | let module_id = build_subtree( | ||
73 | db, | ||
74 | &source_root, | ||
75 | &mut tree, | ||
76 | &mut visited, | ||
77 | &mut roots, | ||
78 | None, | ||
79 | source, | ||
80 | )?; | ||
81 | roots.insert(file_id, module_id); | ||
82 | } | ||
83 | Ok(tree) | ||
84 | } | ||
85 | |||
86 | fn build_subtree( | ||
87 | db: &impl HirDatabase, | ||
88 | source_root: &SourceRoot, | ||
89 | tree: &mut ModuleTree, | ||
90 | visited: &mut FxHashSet<ModuleSource>, | ||
91 | roots: &mut FxHashMap<FileId, ModuleId>, | ||
92 | parent: Option<LinkId>, | ||
93 | source: ModuleSource, | ||
94 | ) -> Cancelable<ModuleId> { | ||
95 | visited.insert(source); | ||
96 | let id = tree.push_mod(ModuleData { | ||
97 | source, | ||
98 | parent, | ||
99 | children: Vec::new(), | ||
100 | }); | ||
101 | for sub in db.submodules(source)?.iter() { | ||
102 | let link = tree.push_link(LinkData { | ||
103 | name: sub.name().clone(), | ||
104 | owner: id, | ||
105 | points_to: Vec::new(), | ||
106 | problem: None, | ||
107 | }); | ||
108 | |||
109 | let (points_to, problem) = match sub { | ||
110 | Submodule::Declaration(name) => { | ||
111 | let (points_to, problem) = resolve_submodule(db, source, &name); | ||
112 | let points_to = points_to | ||
113 | .into_iter() | ||
114 | .map(|file_id| match roots.remove(&file_id) { | ||
115 | Some(module_id) => { | ||
116 | tree.mods[module_id].parent = Some(link); | ||
117 | Ok(module_id) | ||
118 | } | ||
119 | None => build_subtree( | ||
120 | db, | ||
121 | source_root, | ||
122 | tree, | ||
123 | visited, | ||
124 | roots, | ||
125 | Some(link), | ||
126 | ModuleSource::new_file(file_id.into()), | ||
127 | ), | ||
128 | }) | ||
129 | .collect::<Cancelable<Vec<_>>>()?; | ||
130 | (points_to, problem) | ||
131 | } | ||
132 | Submodule::Definition(_name, submodule_source) => { | ||
133 | let points_to = build_subtree( | ||
134 | db, | ||
135 | source_root, | ||
136 | tree, | ||
137 | visited, | ||
138 | roots, | ||
139 | Some(link), | ||
140 | *submodule_source, | ||
141 | )?; | ||
142 | (vec![points_to], None) | ||
143 | } | ||
144 | }; | ||
145 | |||
146 | tree.links[link].points_to = points_to; | ||
147 | tree.links[link].problem = problem; | ||
148 | } | ||
149 | Ok(id) | ||
150 | } | ||
151 | |||
152 | fn resolve_submodule( | ||
153 | db: &impl HirDatabase, | ||
154 | source: ModuleSource, | ||
155 | name: &Name, | ||
156 | ) -> (Vec<FileId>, Option<Problem>) { | ||
157 | // FIXME: handle submodules of inline modules properly | ||
158 | let file_id = source.file_id().original_file(db); | ||
159 | let source_root_id = db.file_source_root(file_id); | ||
160 | let path = db.file_relative_path(file_id); | ||
161 | let root = RelativePathBuf::default(); | ||
162 | let dir_path = path.parent().unwrap_or(&root); | ||
163 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
164 | let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; | ||
165 | |||
166 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
167 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
168 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
169 | let mut candidates = ArrayVec::<[_; 2]>::new(); | ||
170 | if is_dir_owner { | ||
171 | candidates.push(file_mod.clone()); | ||
172 | candidates.push(dir_mod); | ||
173 | } else { | ||
174 | candidates.push(file_dir_mod.clone()); | ||
175 | }; | ||
176 | let sr = db.source_root(source_root_id); | ||
177 | let points_to = candidates | ||
178 | .into_iter() | ||
179 | .filter_map(|path| sr.files.get(&path)) | ||
180 | .map(|&it| it) | ||
181 | .collect::<Vec<_>>(); | ||
182 | let problem = if points_to.is_empty() { | ||
183 | Some(Problem::UnresolvedModule { | ||
184 | candidate: if is_dir_owner { file_mod } else { file_dir_mod }, | ||
185 | }) | ||
186 | } else { | ||
187 | None | ||
188 | }; | ||
189 | (points_to, problem) | ||
190 | } | ||