aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres/raw.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres/raw.rs')
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs400
1 files changed, 400 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
new file mode 100644
index 000000000..86c05d602
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -0,0 +1,400 @@
1//! FIXME: write short doc here
2
3use std::{ops::Index, sync::Arc};
4
5use hir_expand::{
6 ast_id_map::AstIdMap,
7 db::AstDatabase,
8 either::Either,
9 hygiene::Hygiene,
10 name::{AsName, Name},
11};
12use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
13use ra_syntax::{
14 ast::{self, AttrsOwner, NameOwner},
15 AstNode, AstPtr, SourceFile,
16};
17
18use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source};
19
20/// `RawItems` is a set of top-level items in a file (except for impls).
21///
22/// It is the input to name resolution algorithm. `RawItems` are not invalidated
23/// on most edits.
24#[derive(Debug, Default, PartialEq, Eq)]
25pub struct RawItems {
26 modules: Arena<Module, ModuleData>,
27 imports: Arena<ImportId, ImportData>,
28 defs: Arena<Def, DefData>,
29 macros: Arena<Macro, MacroData>,
30 /// items for top-level module
31 items: Vec<RawItem>,
32}
33
34#[derive(Debug, Default, PartialEq, Eq)]
35pub struct ImportSourceMap {
36 map: ArenaMap<ImportId, ImportSourcePtr>,
37}
38
39type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
40type ImportSource = Either<ast::UseTree, ast::ExternCrateItem>;
41
42fn to_node(ptr: ImportSourcePtr, file: &SourceFile) -> ImportSource {
43 ptr.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax()))
44}
45
46impl ImportSourceMap {
47 fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) {
48 self.map.insert(import, ptr)
49 }
50
51 pub fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource {
52 let file = match source {
53 ModuleSource::SourceFile(file) => file.clone(),
54 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
55 };
56
57 to_node(self.map[import], &file)
58 }
59}
60
61impl RawItems {
62 pub(crate) fn raw_items_query(
63 db: &(impl DefDatabase2 + AstDatabase),
64 file_id: HirFileId,
65 ) -> Arc<RawItems> {
66 db.raw_items_with_source_map(file_id).0
67 }
68
69 pub(crate) fn raw_items_with_source_map_query(
70 db: &(impl DefDatabase2 + AstDatabase),
71 file_id: HirFileId,
72 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
73 let mut collector = RawItemsCollector {
74 raw_items: RawItems::default(),
75 source_ast_id_map: db.ast_id_map(file_id),
76 source_map: ImportSourceMap::default(),
77 file_id,
78 hygiene: Hygiene::new(db, file_id),
79 };
80 if let Some(node) = db.parse_or_expand(file_id) {
81 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
82 collector.process_module(None, source_file);
83 } else if let Some(item_list) = ast::MacroItems::cast(node) {
84 collector.process_module(None, item_list);
85 }
86 }
87 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
88 }
89
90 pub fn items(&self) -> &[RawItem] {
91 &self.items
92 }
93}
94
95impl Index<Module> for RawItems {
96 type Output = ModuleData;
97 fn index(&self, idx: Module) -> &ModuleData {
98 &self.modules[idx]
99 }
100}
101
102impl Index<ImportId> for RawItems {
103 type Output = ImportData;
104 fn index(&self, idx: ImportId) -> &ImportData {
105 &self.imports[idx]
106 }
107}
108
109impl Index<Def> for RawItems {
110 type Output = DefData;
111 fn index(&self, idx: Def) -> &DefData {
112 &self.defs[idx]
113 }
114}
115
116impl Index<Macro> for RawItems {
117 type Output = MacroData;
118 fn index(&self, idx: Macro) -> &MacroData {
119 &self.macros[idx]
120 }
121}
122
123// Avoid heap allocation on items without attributes.
124type Attrs = Option<Arc<[Attr]>>;
125
126#[derive(Debug, PartialEq, Eq, Clone)]
127pub struct RawItem {
128 attrs: Attrs,
129 pub kind: RawItemKind,
130}
131
132impl RawItem {
133 pub fn attrs(&self) -> &[Attr] {
134 self.attrs.as_ref().map_or(&[], |it| &*it)
135 }
136}
137
138#[derive(Debug, PartialEq, Eq, Clone, Copy)]
139pub enum RawItemKind {
140 Module(Module),
141 Import(ImportId),
142 Def(Def),
143 Macro(Macro),
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
147pub struct Module(RawId);
148impl_arena_id!(Module);
149
150#[derive(Debug, PartialEq, Eq)]
151pub enum ModuleData {
152 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
153 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157pub struct ImportId(RawId);
158impl_arena_id!(ImportId);
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct ImportData {
162 pub path: Path,
163 pub alias: Option<Name>,
164 pub is_glob: bool,
165 pub is_prelude: bool,
166 pub is_extern_crate: bool,
167 pub is_macro_use: bool,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub struct Def(RawId);
172impl_arena_id!(Def);
173
174#[derive(Debug, PartialEq, Eq)]
175pub struct DefData {
176 pub name: Name,
177 pub kind: DefKind,
178}
179
180#[derive(Debug, PartialEq, Eq, Clone, Copy)]
181pub enum DefKind {
182 Function(FileAstId<ast::FnDef>),
183 Struct(FileAstId<ast::StructDef>),
184 Union(FileAstId<ast::StructDef>),
185 Enum(FileAstId<ast::EnumDef>),
186 Const(FileAstId<ast::ConstDef>),
187 Static(FileAstId<ast::StaticDef>),
188 Trait(FileAstId<ast::TraitDef>),
189 TypeAlias(FileAstId<ast::TypeAliasDef>),
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
193pub struct Macro(RawId);
194impl_arena_id!(Macro);
195
196#[derive(Debug, PartialEq, Eq)]
197pub struct MacroData {
198 pub ast_id: FileAstId<ast::MacroCall>,
199 pub path: Path,
200 pub name: Option<Name>,
201 pub export: bool,
202}
203
204struct RawItemsCollector {
205 raw_items: RawItems,
206 source_ast_id_map: Arc<AstIdMap>,
207 source_map: ImportSourceMap,
208 file_id: HirFileId,
209 hygiene: Hygiene,
210}
211
212impl RawItemsCollector {
213 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) {
214 for item_or_macro in body.items_with_macros() {
215 match item_or_macro {
216 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
217 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
218 }
219 }
220 }
221
222 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
223 let attrs = self.parse_attrs(&item);
224 let (kind, name) = match item {
225 ast::ModuleItem::Module(module) => {
226 self.add_module(current_module, module);
227 return;
228 }
229 ast::ModuleItem::UseItem(use_item) => {
230 self.add_use_item(current_module, use_item);
231 return;
232 }
233 ast::ModuleItem::ExternCrateItem(extern_crate) => {
234 self.add_extern_crate_item(current_module, extern_crate);
235 return;
236 }
237 ast::ModuleItem::ImplBlock(_) => {
238 // impls don't participate in name resolution
239 return;
240 }
241 ast::ModuleItem::StructDef(it) => {
242 let id = self.source_ast_id_map.ast_id(&it);
243 let name = it.name();
244 if it.is_union() {
245 (DefKind::Union(id), name)
246 } else {
247 (DefKind::Struct(id), name)
248 }
249 }
250 ast::ModuleItem::EnumDef(it) => {
251 (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name())
252 }
253 ast::ModuleItem::FnDef(it) => {
254 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
255 }
256 ast::ModuleItem::TraitDef(it) => {
257 (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name())
258 }
259 ast::ModuleItem::TypeAliasDef(it) => {
260 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name())
261 }
262 ast::ModuleItem::ConstDef(it) => {
263 (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name())
264 }
265 ast::ModuleItem::StaticDef(it) => {
266 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
267 }
268 };
269 if let Some(name) = name {
270 let name = name.as_name();
271 let def = self.raw_items.defs.alloc(DefData { name, kind });
272 self.push_item(current_module, attrs, RawItemKind::Def(def));
273 }
274 }
275
276 fn add_module(&mut self, current_module: Option<Module>, module: ast::Module) {
277 let name = match module.name() {
278 Some(it) => it.as_name(),
279 None => return,
280 };
281 let attrs = self.parse_attrs(&module);
282
283 let ast_id = self.source_ast_id_map.ast_id(&module);
284 if module.has_semi() {
285 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
286 self.push_item(current_module, attrs, RawItemKind::Module(item));
287 return;
288 }
289
290 if let Some(item_list) = module.item_list() {
291 let item = self.raw_items.modules.alloc(ModuleData::Definition {
292 name,
293 ast_id,
294 items: Vec::new(),
295 });
296 self.process_module(Some(item), item_list);
297 self.push_item(current_module, attrs, RawItemKind::Module(item));
298 return;
299 }
300 // FIXME: restore this mark once we complete hir splitting
301 // tested_by!(name_res_works_for_broken_modules);
302 }
303
304 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
305 // FIXME: cfg_attr
306 let is_prelude = use_item.has_atom_attr("prelude_import");
307 let attrs = self.parse_attrs(&use_item);
308
309 let mut buf = Vec::new();
310 Path::expand_use_item(
311 Source { ast: use_item, file_id: self.file_id },
312 &self.hygiene,
313 |path, use_tree, is_glob, alias| {
314 let import_data = ImportData {
315 path,
316 alias,
317 is_glob,
318 is_prelude,
319 is_extern_crate: false,
320 is_macro_use: false,
321 };
322 buf.push((import_data, Either::A(AstPtr::new(use_tree))));
323 },
324 );
325 for (import_data, ptr) in buf {
326 self.push_import(current_module, attrs.clone(), import_data, ptr);
327 }
328 }
329
330 fn add_extern_crate_item(
331 &mut self,
332 current_module: Option<Module>,
333 extern_crate: ast::ExternCrateItem,
334 ) {
335 if let Some(name_ref) = extern_crate.name_ref() {
336 let path = Path::from_name_ref(&name_ref);
337 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
338 let attrs = self.parse_attrs(&extern_crate);
339 // FIXME: cfg_attr
340 let is_macro_use = extern_crate.has_atom_attr("macro_use");
341 let import_data = ImportData {
342 path,
343 alias,
344 is_glob: false,
345 is_prelude: false,
346 is_extern_crate: true,
347 is_macro_use,
348 };
349 self.push_import(
350 current_module,
351 attrs,
352 import_data,
353 Either::B(AstPtr::new(&extern_crate)),
354 );
355 }
356 }
357
358 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
359 let attrs = self.parse_attrs(&m);
360 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) {
361 Some(it) => it,
362 _ => return,
363 };
364
365 let name = m.name().map(|it| it.as_name());
366 let ast_id = self.source_ast_id_map.ast_id(&m);
367 // FIXME: cfg_attr
368 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
369
370 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
371 self.push_item(current_module, attrs, RawItemKind::Macro(m));
372 }
373
374 fn push_import(
375 &mut self,
376 current_module: Option<Module>,
377 attrs: Attrs,
378 data: ImportData,
379 source: ImportSourcePtr,
380 ) {
381 let import = self.raw_items.imports.alloc(data);
382 self.source_map.insert(import, source);
383 self.push_item(current_module, attrs, RawItemKind::Import(import))
384 }
385
386 fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) {
387 match current_module {
388 Some(module) => match &mut self.raw_items.modules[module] {
389 ModuleData::Definition { items, .. } => items,
390 ModuleData::Declaration { .. } => unreachable!(),
391 },
392 None => &mut self.raw_items.items,
393 }
394 .push(RawItem { attrs, kind })
395 }
396
397 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
398 Attr::from_attrs_owner(item, &self.hygiene)
399 }
400}