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