aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/crate_def_map/raw.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres/crate_def_map/raw.rs')
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map/raw.rs278
1 files changed, 278 insertions, 0 deletions
diff --git a/crates/ra_hir/src/nameres/crate_def_map/raw.rs b/crates/ra_hir/src/nameres/crate_def_map/raw.rs
new file mode 100644
index 000000000..cec2484eb
--- /dev/null
+++ b/crates/ra_hir/src/nameres/crate_def_map/raw.rs
@@ -0,0 +1,278 @@
1use std::{
2 sync::Arc,
3 ops::Index,
4};
5
6use ra_db::FileId;
7use ra_arena::{Arena, impl_arena_id, RawId};
8use ra_syntax::{
9 AstNode, SourceFile,
10 ast::{self, NameOwner, AttrsOwner},
11};
12
13use crate::{
14 PersistentHirDatabase, Name, AsName, Path, HirFileId,
15 ids::{SourceFileItemId, SourceFileItems},
16};
17
18#[derive(Default, PartialEq, Eq)]
19pub(crate) struct RawItems {
20 modules: Arena<Module, ModuleData>,
21 imports: Arena<Import, ImportData>,
22 defs: Arena<Def, DefData>,
23 macros: Arena<Macro, MacroData>,
24 /// items for top-level module
25 items: Vec<RawItem>,
26}
27
28impl RawItems {
29 pub(crate) fn items(&self) -> &[RawItem] {
30 &self.items
31 }
32
33 pub(crate) fn raw_items_query(db: &impl PersistentHirDatabase, file_id: FileId) -> RawItems {
34 let mut collector = RawItemsCollector {
35 raw_items: RawItems::default(),
36 source_file_items: db.file_items(file_id.into()),
37 };
38 let source_file = db.parse(file_id);
39 collector.process_module(None, &*source_file);
40 collector.raw_items
41 }
42
43 // We can't use queries during name resolution for fear of cycles, so this
44 // is a query-less variant of the above function.
45 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
46 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
47 let mut collector = RawItemsCollector {
48 raw_items: RawItems::default(),
49 source_file_items: Arc::new(source_file_items),
50 };
51 collector.process_module(None, &*source_file);
52 collector.raw_items
53 }
54}
55
56impl Index<Module> for RawItems {
57 type Output = ModuleData;
58 fn index(&self, idx: Module) -> &ModuleData {
59 &self.modules[idx]
60 }
61}
62
63impl Index<Import> for RawItems {
64 type Output = ImportData;
65 fn index(&self, idx: Import) -> &ImportData {
66 &self.imports[idx]
67 }
68}
69
70impl Index<Def> for RawItems {
71 type Output = DefData;
72 fn index(&self, idx: Def) -> &DefData {
73 &self.defs[idx]
74 }
75}
76
77impl Index<Macro> for RawItems {
78 type Output = MacroData;
79 fn index(&self, idx: Macro) -> &MacroData {
80 &self.macros[idx]
81 }
82}
83
84#[derive(PartialEq, Eq, Clone, Copy)]
85pub(crate) enum RawItem {
86 Module(Module),
87 Import(Import),
88 Def(Def),
89 Macro(Macro),
90}
91
92#[derive(Clone, Copy, PartialEq, Eq, Hash)]
93pub(crate) struct Module(RawId);
94impl_arena_id!(Module);
95
96#[derive(PartialEq, Eq)]
97pub(crate) enum ModuleData {
98 Declaration { name: Name },
99 Definition { name: Name, items: Vec<RawItem> },
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
103pub(crate) struct Import(RawId);
104impl_arena_id!(Import);
105
106#[derive(PartialEq, Eq)]
107pub(crate) struct ImportData {
108 path: Path,
109 alias: Option<Name>,
110 is_glob: bool,
111 is_prelude: bool,
112 is_extern_crate: bool,
113}
114
115#[derive(Clone, Copy, PartialEq, Eq, Hash)]
116pub(crate) struct Def(RawId);
117impl_arena_id!(Def);
118
119#[derive(PartialEq, Eq)]
120pub(crate) struct DefData {
121 pub(crate) source_item_id: SourceFileItemId,
122 pub(crate) name: Name,
123 pub(crate) kind: DefKind,
124}
125
126#[derive(Debug, PartialEq, Eq, Clone, Copy)]
127pub(crate) enum DefKind {
128 Function,
129 Struct,
130 Enum,
131 Const,
132 Static,
133 Trait,
134 TypeAlias,
135}
136
137#[derive(Clone, Copy, PartialEq, Eq, Hash)]
138pub(crate) struct Macro(RawId);
139impl_arena_id!(Macro);
140
141#[derive(PartialEq, Eq)]
142pub(crate) struct MacroData {
143 pub(crate) source_item_id: SourceFileItemId,
144 pub(crate) path: Path,
145 pub(crate) name: Option<Name>,
146 pub(crate) arg: tt::Subtree,
147}
148
149struct RawItemsCollector {
150 raw_items: RawItems,
151 source_file_items: Arc<SourceFileItems>,
152}
153
154impl RawItemsCollector {
155 fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
156 for item_or_macro in body.items_with_macros() {
157 match item_or_macro {
158 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
159 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
160 }
161 }
162 }
163
164 fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
165 let (kind, name) = match item.kind() {
166 ast::ModuleItemKind::Module(module) => {
167 self.add_module(current_module, module);
168 return;
169 }
170 ast::ModuleItemKind::UseItem(use_item) => {
171 self.add_use_item(current_module, use_item);
172 return;
173 }
174 ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
175 self.add_extern_crate_item(current_module, extern_crate);
176 return;
177 }
178 ast::ModuleItemKind::ImplBlock(_) => {
179 // impls don't participate in name resolution
180 return;
181 }
182 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
183 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
184 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
185 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
186 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
187 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
188 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
189 };
190 if let Some(name) = name {
191 let name = name.as_name();
192 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
193 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
194 self.push_item(current_module, RawItem::Def(def))
195 }
196 }
197
198 fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
199 let name = match module.name() {
200 Some(it) => it.as_name(),
201 None => return,
202 };
203 if module.has_semi() {
204 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name });
205 self.push_item(current_module, RawItem::Module(item));
206 return;
207 }
208
209 if let Some(item_list) = module.item_list() {
210 let item =
211 self.raw_items.modules.alloc(ModuleData::Definition { name, items: Vec::new() });
212 self.process_module(Some(item), item_list);
213 self.push_item(current_module, RawItem::Module(item));
214 }
215 }
216
217 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
218 let is_prelude = use_item
219 .attrs()
220 .any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
221
222 Path::expand_use_item(use_item, |path, segment, alias| {
223 let import = self.raw_items.imports.alloc(ImportData {
224 path,
225 alias,
226 is_glob: segment.is_none(),
227 is_prelude,
228 is_extern_crate: false,
229 });
230 self.push_item(current_module, RawItem::Import(import))
231 })
232 }
233
234 fn add_extern_crate_item(
235 &mut self,
236 current_module: Option<Module>,
237 extern_crate: &ast::ExternCrateItem,
238 ) {
239 if let Some(name_ref) = extern_crate.name_ref() {
240 let path = Path::from_name_ref(name_ref);
241 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
242 let import = self.raw_items.imports.alloc(ImportData {
243 path,
244 alias,
245 is_glob: false,
246 is_prelude: false,
247 is_extern_crate: true,
248 });
249 self.push_item(current_module, RawItem::Import(import))
250 }
251 }
252
253 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
254 let (path, arg) = match (
255 m.path().and_then(Path::from_ast),
256 m.token_tree().and_then(mbe::ast_to_token_tree),
257 ) {
258 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
259 _ => return,
260 };
261
262 let name = m.name().map(|it| it.as_name());
263 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
264 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name });
265 self.push_item(current_module, RawItem::Macro(m));
266 }
267
268 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
269 match current_module {
270 Some(module) => match &mut self.raw_items.modules[module] {
271 ModuleData::Definition { items, .. } => items,
272 ModuleData::Declaration { .. } => unreachable!(),
273 },
274 None => &mut self.raw_items.items,
275 }
276 .push(item)
277 }
278}