aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/module.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-06 14:33:27 +0000
committerAleksey Kladov <[email protected]>2019-01-06 14:36:10 +0000
commitfd4456d0ec88e3433a7a8be6f27d8af9afedefe5 (patch)
tree37f1225b085e22756cbfd65875595c60205cc93a /crates/ra_hir/src/module.rs
parent5a505189a8f7ed274893a45aed0d0249083d1277 (diff)
flatten module structure
Diffstat (limited to 'crates/ra_hir/src/module.rs')
-rw-r--r--crates/ra_hir/src/module.rs209
1 files changed, 0 insertions, 209 deletions
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
deleted file mode 100644
index ebaf5f47a..000000000
--- a/crates/ra_hir/src/module.rs
+++ /dev/null
@@ -1,209 +0,0 @@
1pub(super) mod imp;
2pub(super) mod nameres;
3
4use ra_syntax::{
5 algo::generate,
6 ast::{self, AstNode, NameOwner},
7 SyntaxNode,
8};
9use ra_arena::{Arena, RawId, impl_arena_id};
10use relative_path::RelativePathBuf;
11
12use crate::{Name, HirDatabase, SourceItemId, SourceFileItemId, HirFileId};
13
14pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct ModuleId(RawId);
18impl_arena_id!(ModuleId);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct LinkId(RawId);
22impl_arena_id!(LinkId);
23
24/// Physically, rust source is organized as a set of files, but logically it is
25/// organized as a tree of modules. Usually, a single file corresponds to a
26/// single module, but it is not nessary the case.
27///
28/// Module encapsulate the logic of transitioning from the fuzzy world of files
29/// (which can have multiple parents) to the precise world of modules (which
30/// always have one parent).
31#[derive(Default, Debug, PartialEq, Eq)]
32pub struct ModuleTree {
33 mods: Arena<ModuleId, ModuleData>,
34 links: Arena<LinkId, LinkData>,
35}
36
37impl ModuleTree {
38 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
39 self.mods.iter().map(|(id, _)| id)
40 }
41
42 pub(crate) fn modules_with_sources<'a>(
43 &'a self,
44 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
45 self.mods.iter().map(|(id, m)| (id, m.source))
46 }
47}
48
49/// `ModuleSource` is the syntax tree element that produced this module:
50/// either a file, or an inlinde module.
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
52pub struct ModuleSource(pub(crate) SourceItemId);
53
54/// An owned syntax node for a module. Unlike `ModuleSource`,
55/// this holds onto the AST for the whole file.
56pub(crate) enum ModuleSourceNode {
57 SourceFile(ast::SourceFileNode),
58 Module(ast::ModuleNode),
59}
60
61#[derive(Clone, Debug, Hash, PartialEq, Eq)]
62pub enum Problem {
63 UnresolvedModule {
64 candidate: RelativePathBuf,
65 },
66 NotDirOwner {
67 move_to: RelativePathBuf,
68 candidate: RelativePathBuf,
69 },
70}
71
72impl ModuleId {
73 pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
74 tree.mods[self].source
75 }
76 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
77 tree.mods[self].parent
78 }
79 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
80 let link = self.parent_link(tree)?;
81 Some(tree.links[link].owner)
82 }
83 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
84 generate(Some(self), move |it| it.parent(tree))
85 .last()
86 .unwrap()
87 }
88 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
89 let link = tree.mods[self]
90 .children
91 .iter()
92 .map(|&it| &tree.links[it])
93 .find(|it| it.name == *name)?;
94 Some(*link.points_to.first()?)
95 }
96 fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
97 tree.mods[self].children.iter().filter_map(move |&it| {
98 let link = &tree.links[it];
99 let module = *link.points_to.first()?;
100 Some((link.name.clone(), module))
101 })
102 }
103 pub(crate) fn problems(
104 self,
105 tree: &ModuleTree,
106 db: &impl HirDatabase,
107 ) -> Vec<(SyntaxNode, Problem)> {
108 tree.mods[self]
109 .children
110 .iter()
111 .filter_map(|&it| {
112 let p = tree.links[it].problem.clone()?;
113 let s = it.bind_source(tree, db);
114 let s = s.borrowed().name().unwrap().syntax().owned();
115 Some((s, p))
116 })
117 .collect()
118 }
119}
120
121impl LinkId {
122 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
123 tree.links[self].owner
124 }
125 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
126 &tree.links[self].name
127 }
128 pub(crate) fn bind_source<'a>(
129 self,
130 tree: &ModuleTree,
131 db: &impl HirDatabase,
132 ) -> ast::ModuleNode {
133 let owner = self.owner(tree);
134 match owner.source(tree).resolve(db) {
135 ModuleSourceNode::SourceFile(root) => {
136 let ast = imp::modules(root.borrowed())
137 .find(|(name, _)| name == &tree.links[self].name)
138 .unwrap()
139 .1;
140 ast.owned()
141 }
142 ModuleSourceNode::Module(it) => it,
143 }
144 }
145}
146
147#[derive(Debug, PartialEq, Eq, Hash)]
148pub struct ModuleData {
149 source: ModuleSource,
150 parent: Option<LinkId>,
151 children: Vec<LinkId>,
152}
153
154impl ModuleSource {
155 // precondition: item_id **must** point to module
156 fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
157 let source_item_id = SourceItemId { file_id, item_id };
158 ModuleSource(source_item_id)
159 }
160
161 pub(crate) fn new_file(file_id: HirFileId) -> ModuleSource {
162 ModuleSource::new(file_id, None)
163 }
164
165 pub(crate) fn new_inline(
166 db: &impl HirDatabase,
167 file_id: HirFileId,
168 m: ast::Module,
169 ) -> ModuleSource {
170 assert!(!m.has_semi());
171 let file_items = db.file_items(file_id);
172 let item_id = file_items.id_of(file_id, m.syntax());
173 ModuleSource::new(file_id, Some(item_id))
174 }
175
176 pub(crate) fn file_id(self) -> HirFileId {
177 self.0.file_id
178 }
179
180 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
181 let syntax_node = db.file_item(self.0);
182 let syntax_node = syntax_node.borrowed();
183 if let Some(file) = ast::SourceFile::cast(syntax_node) {
184 return ModuleSourceNode::SourceFile(file.owned());
185 }
186 let module = ast::Module::cast(syntax_node).unwrap();
187 ModuleSourceNode::Module(module.owned())
188 }
189}
190
191#[derive(Hash, Debug, PartialEq, Eq)]
192struct LinkData {
193 owner: ModuleId,
194 name: Name,
195 points_to: Vec<ModuleId>,
196 problem: Option<Problem>,
197}
198
199impl ModuleTree {
200 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
201 self.mods.alloc(data)
202 }
203 fn push_link(&mut self, data: LinkData) -> LinkId {
204 let owner = data.owner;
205 let id = self.links.alloc(data);
206 self.mods[owner].children.push(id);
207 id
208 }
209}