aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/raw.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-17 09:59:04 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-17 09:59:04 +0000
commit7d3f48cdaf20d718e711f999573adf3303e9396a (patch)
treedf584fbb044cad23e196da5ae0b3636b06bfeeff /crates/ra_hir/src/nameres/raw.rs
parent65e763fa84ae70ec9cee13f434acaae5371ad8e5 (diff)
parent3a770233652cbf3e48688dd5f1d9f3c363eda5a8 (diff)
Merge #968
968: Macro aware name resoltion r=matklad a=matklad The first commit lays the ground work for new name resolution, including * extracting position-indendent items from parse trees * walking the tree of modules * old-style macro_rules resolve cc @pnkfelix: this looks like an API name resolution should interact with. Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres/raw.rs')
-rw-r--r--crates/ra_hir/src/nameres/raw.rs322
1 files changed, 322 insertions, 0 deletions
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
new file mode 100644
index 000000000..3226bbf0d
--- /dev/null
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -0,0 +1,322 @@
1use std::{
2 sync::Arc,
3 ops::Index,
4};
5
6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc,
11 ast::{self, NameOwner, AttrsOwner},
12};
13
14use crate::{
15 PersistentHirDatabase, Name, AsName, Path, HirFileId, ModuleSource,
16 ids::{SourceFileItemId, SourceFileItems},
17};
18
19#[derive(Debug, Default, PartialEq, Eq)]
20pub struct RawItems {
21 modules: Arena<Module, ModuleData>,
22 imports: Arena<ImportId, ImportData>,
23 defs: Arena<Def, DefData>,
24 macros: Arena<Macro, MacroData>,
25 /// items for top-level module
26 items: Vec<RawItem>,
27}
28
29#[derive(Debug, Default, PartialEq, Eq)]
30pub struct ImportSourceMap {
31 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
32}
33
34impl ImportSourceMap {
35 pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
36 self.map.insert(import, AstPtr::new(segment))
37 }
38
39 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
40 let file = match source {
41 ModuleSource::SourceFile(file) => &*file,
42 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
43 };
44
45 self.map[import].to_node(file).to_owned()
46 }
47}
48
49impl RawItems {
50 pub(crate) fn raw_items_query(
51 db: &impl PersistentHirDatabase,
52 file_id: FileId,
53 ) -> Arc<RawItems> {
54 db.raw_items_with_source_map(file_id).0
55 }
56
57 pub(crate) fn raw_items_with_source_map_query(
58 db: &impl PersistentHirDatabase,
59 file_id: FileId,
60 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
61 let mut collector = RawItemsCollector {
62 raw_items: RawItems::default(),
63 source_file_items: db.file_items(file_id.into()),
64 source_map: ImportSourceMap::default(),
65 };
66 let source_file = db.parse(file_id);
67 collector.process_module(None, &*source_file);
68 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
69 }
70
71 pub(crate) fn items(&self) -> &[RawItem] {
72 &self.items
73 }
74
75 // We can't use queries during name resolution for fear of cycles, so this
76 // is a query-less variant of the above function.
77 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
78 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
79 let mut collector = RawItemsCollector {
80 raw_items: RawItems::default(),
81 source_file_items: Arc::new(source_file_items),
82 source_map: ImportSourceMap::default(),
83 };
84 collector.process_module(None, &*source_file);
85 collector.raw_items
86 }
87}
88
89impl Index<Module> for RawItems {
90 type Output = ModuleData;
91 fn index(&self, idx: Module) -> &ModuleData {
92 &self.modules[idx]
93 }
94}
95
96impl Index<ImportId> for RawItems {
97 type Output = ImportData;
98 fn index(&self, idx: ImportId) -> &ImportData {
99 &self.imports[idx]
100 }
101}
102
103impl Index<Def> for RawItems {
104 type Output = DefData;
105 fn index(&self, idx: Def) -> &DefData {
106 &self.defs[idx]
107 }
108}
109
110impl Index<Macro> for RawItems {
111 type Output = MacroData;
112 fn index(&self, idx: Macro) -> &MacroData {
113 &self.macros[idx]
114 }
115}
116
117#[derive(Debug, PartialEq, Eq, Clone, Copy)]
118pub(crate) enum RawItem {
119 Module(Module),
120 Import(ImportId),
121 Def(Def),
122 Macro(Macro),
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub(crate) struct Module(RawId);
127impl_arena_id!(Module);
128
129#[derive(Debug, PartialEq, Eq)]
130pub(crate) enum ModuleData {
131 Declaration { name: Name, source_item_id: SourceFileItemId },
132 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136pub struct ImportId(RawId);
137impl_arena_id!(ImportId);
138
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct ImportData {
141 pub(crate) path: Path,
142 pub(crate) alias: Option<Name>,
143 pub(crate) is_glob: bool,
144 pub(crate) is_prelude: bool,
145 pub(crate) is_extern_crate: bool,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149pub(crate) struct Def(RawId);
150impl_arena_id!(Def);
151
152#[derive(Debug, PartialEq, Eq)]
153pub(crate) struct DefData {
154 pub(crate) source_item_id: SourceFileItemId,
155 pub(crate) name: Name,
156 pub(crate) kind: DefKind,
157}
158
159#[derive(Debug, PartialEq, Eq, Clone, Copy)]
160pub(crate) enum DefKind {
161 Function,
162 Struct,
163 Enum,
164 Const,
165 Static,
166 Trait,
167 TypeAlias,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub(crate) struct Macro(RawId);
172impl_arena_id!(Macro);
173
174#[derive(Debug, PartialEq, Eq)]
175pub(crate) struct MacroData {
176 pub(crate) source_item_id: SourceFileItemId,
177 pub(crate) path: Path,
178 pub(crate) name: Option<Name>,
179 pub(crate) arg: tt::Subtree,
180 pub(crate) export: bool,
181}
182
183struct RawItemsCollector {
184 raw_items: RawItems,
185 source_file_items: Arc<SourceFileItems>,
186 source_map: ImportSourceMap,
187}
188
189impl RawItemsCollector {
190 fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
191 for item_or_macro in body.items_with_macros() {
192 match item_or_macro {
193 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
194 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
195 }
196 }
197 }
198
199 fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
200 let (kind, name) = match item.kind() {
201 ast::ModuleItemKind::Module(module) => {
202 self.add_module(current_module, module);
203 return;
204 }
205 ast::ModuleItemKind::UseItem(use_item) => {
206 self.add_use_item(current_module, use_item);
207 return;
208 }
209 ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
210 self.add_extern_crate_item(current_module, extern_crate);
211 return;
212 }
213 ast::ModuleItemKind::ImplBlock(_) => {
214 // impls don't participate in name resolution
215 return;
216 }
217 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
218 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
219 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
220 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
221 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
222 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
223 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
224 };
225 if let Some(name) = name {
226 let name = name.as_name();
227 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
228 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
229 self.push_item(current_module, RawItem::Def(def))
230 }
231 }
232
233 fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
234 let name = match module.name() {
235 Some(it) => it.as_name(),
236 None => return,
237 };
238 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
239 if module.has_semi() {
240 let item =
241 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
242 self.push_item(current_module, RawItem::Module(item));
243 return;
244 }
245
246 if let Some(item_list) = module.item_list() {
247 let item = self.raw_items.modules.alloc(ModuleData::Definition {
248 name,
249 source_item_id,
250 items: Vec::new(),
251 });
252 self.process_module(Some(item), item_list);
253 self.push_item(current_module, RawItem::Module(item));
254 return;
255 }
256 tested_by!(name_res_works_for_broken_modules);
257 }
258
259 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
260 let is_prelude = use_item.has_atom_attr("prelude_import");
261
262 Path::expand_use_item(use_item, |path, segment, alias| {
263 let import = self.raw_items.imports.alloc(ImportData {
264 path,
265 alias,
266 is_glob: segment.is_none(),
267 is_prelude,
268 is_extern_crate: false,
269 });
270 if let Some(segment) = segment {
271 self.source_map.insert(import, segment)
272 }
273 self.push_item(current_module, RawItem::Import(import))
274 })
275 }
276
277 fn add_extern_crate_item(
278 &mut self,
279 current_module: Option<Module>,
280 extern_crate: &ast::ExternCrateItem,
281 ) {
282 if let Some(name_ref) = extern_crate.name_ref() {
283 let path = Path::from_name_ref(name_ref);
284 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
285 let import = self.raw_items.imports.alloc(ImportData {
286 path,
287 alias,
288 is_glob: false,
289 is_prelude: false,
290 is_extern_crate: true,
291 });
292 self.push_item(current_module, RawItem::Import(import))
293 }
294 }
295
296 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
297 let (path, arg) = match (
298 m.path().and_then(Path::from_ast),
299 m.token_tree().and_then(mbe::ast_to_token_tree),
300 ) {
301 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
302 _ => return,
303 };
304
305 let name = m.name().map(|it| it.as_name());
306 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
307 let export = m.has_atom_attr("macro_export");
308 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export });
309 self.push_item(current_module, RawItem::Macro(m));
310 }
311
312 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
313 match current_module {
314 Some(module) => match &mut self.raw_items.modules[module] {
315 ModuleData::Definition { items, .. } => items,
316 ModuleData::Declaration { .. } => unreachable!(),
317 },
318 None => &mut self.raw_items.items,
319 }
320 .push(item)
321 }
322}