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