diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-06-24 16:07:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-24 16:07:37 +0100 |
commit | e9bdb05e9676e85bdd8fa5008e3ada3812b36fd9 (patch) | |
tree | a21d348fbfa2d06f1fba77622c5417383938e6fe /crates/ra_hir_def/src/nameres/raw.rs | |
parent | 1a3b507a007d0373a83bde203d780b860ea55ce1 (diff) | |
parent | 2928600374a8356c2c2bffee080c47cb0f463fb9 (diff) |
Merge #4990
4990: Introduce an ItemTree layer to avoid reparsing files r=matklad a=jonas-schievink
This reduces the latency of "go to definition" in a simple benchmark on rust-analyzer by around 30%.
cc https://github.com/rust-analyzer/rust-analyzer/issues/1650
Closes https://github.com/rust-analyzer/rust-analyzer/issues/3485
Co-authored-by: Aleksey Kladov <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/ra_hir_def/src/nameres/raw.rs')
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 482 |
1 files changed, 0 insertions, 482 deletions
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs deleted file mode 100644 index f44baa579..000000000 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ /dev/null | |||
@@ -1,482 +0,0 @@ | |||
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 | hygiene::Hygiene, | ||
13 | name::{AsName, Name}, | ||
14 | }; | ||
15 | use ra_arena::{Arena, Idx}; | ||
16 | use ra_prof::profile; | ||
17 | use ra_syntax::{ | ||
18 | ast::{self, AttrsOwner, NameOwner, VisibilityOwner}, | ||
19 | AstNode, | ||
20 | }; | ||
21 | use test_utils::mark; | ||
22 | |||
23 | use crate::{ | ||
24 | attr::Attrs, | ||
25 | db::DefDatabase, | ||
26 | path::{ImportAlias, ModPath}, | ||
27 | visibility::RawVisibility, | ||
28 | FileAstId, HirFileId, InFile, | ||
29 | }; | ||
30 | |||
31 | /// `RawItems` is a set of top-level items in a file (except for impls). | ||
32 | /// | ||
33 | /// It is the input to name resolution algorithm. `RawItems` are not invalidated | ||
34 | /// on most edits. | ||
35 | #[derive(Debug, Default, PartialEq, Eq)] | ||
36 | pub struct RawItems { | ||
37 | modules: Arena<ModuleData>, | ||
38 | imports: Arena<ImportData>, | ||
39 | defs: Arena<DefData>, | ||
40 | macros: Arena<MacroData>, | ||
41 | impls: Arena<ImplData>, | ||
42 | /// items for top-level module | ||
43 | items: Vec<RawItem>, | ||
44 | } | ||
45 | |||
46 | impl RawItems { | ||
47 | pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<RawItems> { | ||
48 | let _p = profile("raw_items_query"); | ||
49 | let mut collector = RawItemsCollector { | ||
50 | raw_items: RawItems::default(), | ||
51 | source_ast_id_map: db.ast_id_map(file_id), | ||
52 | file_id, | ||
53 | hygiene: Hygiene::new(db.upcast(), file_id), | ||
54 | }; | ||
55 | if let Some(node) = db.parse_or_expand(file_id) { | ||
56 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { | ||
57 | collector.process_module(None, source_file); | ||
58 | } else if let Some(item_list) = ast::MacroItems::cast(node) { | ||
59 | collector.process_module(None, item_list); | ||
60 | } | ||
61 | } | ||
62 | let raw_items = collector.raw_items; | ||
63 | Arc::new(raw_items) | ||
64 | } | ||
65 | |||
66 | pub(super) fn items(&self) -> &[RawItem] { | ||
67 | &self.items | ||
68 | } | ||
69 | } | ||
70 | |||
71 | impl Index<Idx<ModuleData>> for RawItems { | ||
72 | type Output = ModuleData; | ||
73 | fn index(&self, idx: Idx<ModuleData>) -> &ModuleData { | ||
74 | &self.modules[idx] | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl Index<Import> for RawItems { | ||
79 | type Output = ImportData; | ||
80 | fn index(&self, idx: Import) -> &ImportData { | ||
81 | &self.imports[idx] | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl Index<Idx<DefData>> for RawItems { | ||
86 | type Output = DefData; | ||
87 | fn index(&self, idx: Idx<DefData>) -> &DefData { | ||
88 | &self.defs[idx] | ||
89 | } | ||
90 | } | ||
91 | |||
92 | impl Index<Idx<MacroData>> for RawItems { | ||
93 | type Output = MacroData; | ||
94 | fn index(&self, idx: Idx<MacroData>) -> &MacroData { | ||
95 | &self.macros[idx] | ||
96 | } | ||
97 | } | ||
98 | |||
99 | impl Index<Idx<ImplData>> for RawItems { | ||
100 | type Output = ImplData; | ||
101 | fn index(&self, idx: Idx<ImplData>) -> &ImplData { | ||
102 | &self.impls[idx] | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
107 | pub(super) struct RawItem { | ||
108 | pub(super) attrs: Attrs, | ||
109 | pub(super) kind: RawItemKind, | ||
110 | } | ||
111 | |||
112 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
113 | pub(super) enum RawItemKind { | ||
114 | Module(Idx<ModuleData>), | ||
115 | Import(Import), | ||
116 | Def(Idx<DefData>), | ||
117 | Macro(Idx<MacroData>), | ||
118 | Impl(Idx<ImplData>), | ||
119 | } | ||
120 | |||
121 | #[derive(Debug, PartialEq, Eq)] | ||
122 | pub(super) enum ModuleData { | ||
123 | Declaration { | ||
124 | name: Name, | ||
125 | visibility: RawVisibility, | ||
126 | ast_id: FileAstId<ast::Module>, | ||
127 | }, | ||
128 | Definition { | ||
129 | name: Name, | ||
130 | visibility: RawVisibility, | ||
131 | ast_id: FileAstId<ast::Module>, | ||
132 | items: Vec<RawItem>, | ||
133 | }, | ||
134 | } | ||
135 | |||
136 | pub(crate) type Import = Idx<ImportData>; | ||
137 | |||
138 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
139 | pub struct ImportData { | ||
140 | pub(super) path: ModPath, | ||
141 | pub(super) alias: Option<ImportAlias>, | ||
142 | pub(super) is_glob: bool, | ||
143 | pub(super) is_prelude: bool, | ||
144 | pub(super) is_extern_crate: bool, | ||
145 | pub(super) is_macro_use: bool, | ||
146 | pub(super) visibility: RawVisibility, | ||
147 | } | ||
148 | |||
149 | // type Def = Idx<DefData>; | ||
150 | |||
151 | #[derive(Debug, PartialEq, Eq)] | ||
152 | pub(super) struct DefData { | ||
153 | pub(super) name: Name, | ||
154 | pub(super) kind: DefKind, | ||
155 | pub(super) visibility: RawVisibility, | ||
156 | } | ||
157 | |||
158 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
159 | pub(super) enum StructDefKind { | ||
160 | Record, | ||
161 | Tuple, | ||
162 | Unit, | ||
163 | } | ||
164 | |||
165 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
166 | pub(super) enum DefKind { | ||
167 | Function(FileAstId<ast::FnDef>), | ||
168 | Struct(FileAstId<ast::StructDef>, StructDefKind), | ||
169 | Union(FileAstId<ast::UnionDef>), | ||
170 | Enum(FileAstId<ast::EnumDef>), | ||
171 | Const(FileAstId<ast::ConstDef>), | ||
172 | Static(FileAstId<ast::StaticDef>), | ||
173 | Trait(FileAstId<ast::TraitDef>), | ||
174 | TypeAlias(FileAstId<ast::TypeAliasDef>), | ||
175 | } | ||
176 | |||
177 | impl DefKind { | ||
178 | pub fn ast_id(self) -> FileAstId<ast::ModuleItem> { | ||
179 | match self { | ||
180 | DefKind::Function(it) => it.upcast(), | ||
181 | DefKind::Struct(it, _) => it.upcast(), | ||
182 | DefKind::Union(it) => it.upcast(), | ||
183 | DefKind::Enum(it) => it.upcast(), | ||
184 | DefKind::Const(it) => it.upcast(), | ||
185 | DefKind::Static(it) => it.upcast(), | ||
186 | DefKind::Trait(it) => it.upcast(), | ||
187 | DefKind::TypeAlias(it) => it.upcast(), | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | #[derive(Debug, PartialEq, Eq)] | ||
193 | pub(super) struct MacroData { | ||
194 | pub(super) ast_id: FileAstId<ast::MacroCall>, | ||
195 | pub(super) path: ModPath, | ||
196 | pub(super) name: Option<Name>, | ||
197 | pub(super) export: bool, | ||
198 | pub(super) local_inner: bool, | ||
199 | pub(super) builtin: bool, | ||
200 | } | ||
201 | |||
202 | #[derive(Debug, PartialEq, Eq)] | ||
203 | pub(super) struct ImplData { | ||
204 | pub(super) ast_id: FileAstId<ast::ImplDef>, | ||
205 | } | ||
206 | |||
207 | struct RawItemsCollector { | ||
208 | raw_items: RawItems, | ||
209 | source_ast_id_map: Arc<AstIdMap>, | ||
210 | file_id: HirFileId, | ||
211 | hygiene: Hygiene, | ||
212 | } | ||
213 | |||
214 | impl RawItemsCollector { | ||
215 | fn process_module( | ||
216 | &mut self, | ||
217 | current_module: Option<Idx<ModuleData>>, | ||
218 | body: impl ast::ModuleItemOwner, | ||
219 | ) { | ||
220 | for item in body.items() { | ||
221 | self.add_item(current_module, item) | ||
222 | } | ||
223 | } | ||
224 | |||
225 | fn add_item(&mut self, current_module: Option<Idx<ModuleData>>, item: ast::ModuleItem) { | ||
226 | let attrs = self.parse_attrs(&item); | ||
227 | let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); | ||
228 | let (kind, name) = match item { | ||
229 | ast::ModuleItem::Module(module) => { | ||
230 | self.add_module(current_module, module); | ||
231 | return; | ||
232 | } | ||
233 | ast::ModuleItem::UseItem(use_item) => { | ||
234 | self.add_use_item(current_module, use_item); | ||
235 | return; | ||
236 | } | ||
237 | ast::ModuleItem::ExternCrateItem(extern_crate) => { | ||
238 | self.add_extern_crate_item(current_module, extern_crate); | ||
239 | return; | ||
240 | } | ||
241 | ast::ModuleItem::ImplDef(it) => { | ||
242 | self.add_impl(current_module, it); | ||
243 | return; | ||
244 | } | ||
245 | ast::ModuleItem::StructDef(it) => { | ||
246 | let kind = match it.kind() { | ||
247 | ast::StructKind::Record(_) => StructDefKind::Record, | ||
248 | ast::StructKind::Tuple(_) => StructDefKind::Tuple, | ||
249 | ast::StructKind::Unit => StructDefKind::Unit, | ||
250 | }; | ||
251 | let id = self.source_ast_id_map.ast_id(&it); | ||
252 | let name = it.name(); | ||
253 | (DefKind::Struct(id, kind), name) | ||
254 | } | ||
255 | ast::ModuleItem::UnionDef(it) => { | ||
256 | let id = self.source_ast_id_map.ast_id(&it); | ||
257 | let name = it.name(); | ||
258 | (DefKind::Union(id), name) | ||
259 | } | ||
260 | ast::ModuleItem::EnumDef(it) => { | ||
261 | (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
262 | } | ||
263 | ast::ModuleItem::FnDef(it) => { | ||
264 | (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
265 | } | ||
266 | ast::ModuleItem::TraitDef(it) => { | ||
267 | (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
268 | } | ||
269 | ast::ModuleItem::TypeAliasDef(it) => { | ||
270 | (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
271 | } | ||
272 | ast::ModuleItem::ConstDef(it) => { | ||
273 | (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
274 | } | ||
275 | ast::ModuleItem::StaticDef(it) => { | ||
276 | (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
277 | } | ||
278 | ast::ModuleItem::MacroCall(it) => { | ||
279 | self.add_macro(current_module, it); | ||
280 | return; | ||
281 | } | ||
282 | ast::ModuleItem::ExternBlock(it) => { | ||
283 | self.add_extern_block(current_module, it); | ||
284 | return; | ||
285 | } | ||
286 | }; | ||
287 | if let Some(name) = name { | ||
288 | let name = name.as_name(); | ||
289 | let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); | ||
290 | self.push_item(current_module, attrs, RawItemKind::Def(def)); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | fn add_extern_block( | ||
295 | &mut self, | ||
296 | current_module: Option<Idx<ModuleData>>, | ||
297 | block: ast::ExternBlock, | ||
298 | ) { | ||
299 | if let Some(items) = block.extern_item_list() { | ||
300 | for item in items.extern_items() { | ||
301 | let attrs = self.parse_attrs(&item); | ||
302 | let visibility = | ||
303 | RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); | ||
304 | let (kind, name) = match item { | ||
305 | ast::ExternItem::FnDef(it) => { | ||
306 | (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
307 | } | ||
308 | ast::ExternItem::StaticDef(it) => { | ||
309 | (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
310 | } | ||
311 | }; | ||
312 | |||
313 | if let Some(name) = name { | ||
314 | let name = name.as_name(); | ||
315 | let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); | ||
316 | self.push_item(current_module, attrs, RawItemKind::Def(def)); | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) { | ||
323 | let name = match module.name() { | ||
324 | Some(it) => it.as_name(), | ||
325 | None => return, | ||
326 | }; | ||
327 | let attrs = self.parse_attrs(&module); | ||
328 | let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); | ||
329 | |||
330 | let ast_id = self.source_ast_id_map.ast_id(&module); | ||
331 | if module.semicolon_token().is_some() { | ||
332 | let item = | ||
333 | self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); | ||
334 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if let Some(item_list) = module.item_list() { | ||
339 | let item = self.raw_items.modules.alloc(ModuleData::Definition { | ||
340 | name, | ||
341 | visibility, | ||
342 | ast_id, | ||
343 | items: Vec::new(), | ||
344 | }); | ||
345 | self.process_module(Some(item), item_list); | ||
346 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
347 | return; | ||
348 | } | ||
349 | mark::hit!(name_res_works_for_broken_modules); | ||
350 | } | ||
351 | |||
352 | fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) { | ||
353 | // FIXME: cfg_attr | ||
354 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
355 | let attrs = self.parse_attrs(&use_item); | ||
356 | let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene); | ||
357 | |||
358 | let mut buf = Vec::new(); | ||
359 | ModPath::expand_use_item( | ||
360 | InFile { value: use_item, file_id: self.file_id }, | ||
361 | &self.hygiene, | ||
362 | |path, _use_tree, is_glob, alias| { | ||
363 | let import_data = ImportData { | ||
364 | path, | ||
365 | alias, | ||
366 | is_glob, | ||
367 | is_prelude, | ||
368 | is_extern_crate: false, | ||
369 | is_macro_use: false, | ||
370 | visibility: visibility.clone(), | ||
371 | }; | ||
372 | buf.push(import_data); | ||
373 | }, | ||
374 | ); | ||
375 | for import_data in buf { | ||
376 | self.push_import(current_module, attrs.clone(), import_data); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | fn add_extern_crate_item( | ||
381 | &mut self, | ||
382 | current_module: Option<Idx<ModuleData>>, | ||
383 | extern_crate: ast::ExternCrateItem, | ||
384 | ) { | ||
385 | if let Some(name_ref) = extern_crate.name_ref() { | ||
386 | let path = ModPath::from_name_ref(&name_ref); | ||
387 | let visibility = | ||
388 | RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene); | ||
389 | let alias = extern_crate.alias().map(|a| { | ||
390 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
391 | }); | ||
392 | let attrs = self.parse_attrs(&extern_crate); | ||
393 | // FIXME: cfg_attr | ||
394 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
395 | let import_data = ImportData { | ||
396 | path, | ||
397 | alias, | ||
398 | is_glob: false, | ||
399 | is_prelude: false, | ||
400 | is_extern_crate: true, | ||
401 | is_macro_use, | ||
402 | visibility, | ||
403 | }; | ||
404 | self.push_import(current_module, attrs, import_data); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | fn add_macro(&mut self, current_module: Option<Idx<ModuleData>>, m: ast::MacroCall) { | ||
409 | let attrs = self.parse_attrs(&m); | ||
410 | let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) { | ||
411 | Some(it) => it, | ||
412 | _ => return, | ||
413 | }; | ||
414 | |||
415 | let name = m.name().map(|it| it.as_name()); | ||
416 | let ast_id = self.source_ast_id_map.ast_id(&m); | ||
417 | |||
418 | // FIXME: cfg_attr | ||
419 | let export_attr = attrs.by_key("macro_export"); | ||
420 | |||
421 | let export = export_attr.exists(); | ||
422 | let local_inner = if export { | ||
423 | export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { | ||
424 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { | ||
425 | ident.text.contains("local_inner_macros") | ||
426 | } | ||
427 | _ => false, | ||
428 | }) | ||
429 | } else { | ||
430 | false | ||
431 | }; | ||
432 | |||
433 | let builtin = attrs.by_key("rustc_builtin_macro").exists(); | ||
434 | |||
435 | let m = self.raw_items.macros.alloc(MacroData { | ||
436 | ast_id, | ||
437 | path, | ||
438 | name, | ||
439 | export, | ||
440 | local_inner, | ||
441 | builtin, | ||
442 | }); | ||
443 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | ||
444 | } | ||
445 | |||
446 | fn add_impl(&mut self, current_module: Option<Idx<ModuleData>>, imp: ast::ImplDef) { | ||
447 | let attrs = self.parse_attrs(&imp); | ||
448 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
449 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
450 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
451 | } | ||
452 | |||
453 | fn push_import( | ||
454 | &mut self, | ||
455 | current_module: Option<Idx<ModuleData>>, | ||
456 | attrs: Attrs, | ||
457 | data: ImportData, | ||
458 | ) { | ||
459 | let import = self.raw_items.imports.alloc(data); | ||
460 | self.push_item(current_module, attrs, RawItemKind::Import(import)) | ||
461 | } | ||
462 | |||
463 | fn push_item( | ||
464 | &mut self, | ||
465 | current_module: Option<Idx<ModuleData>>, | ||
466 | attrs: Attrs, | ||
467 | kind: RawItemKind, | ||
468 | ) { | ||
469 | match current_module { | ||
470 | Some(module) => match &mut self.raw_items.modules[module] { | ||
471 | ModuleData::Definition { items, .. } => items, | ||
472 | ModuleData::Declaration { .. } => unreachable!(), | ||
473 | }, | ||
474 | None => &mut self.raw_items.items, | ||
475 | } | ||
476 | .push(RawItem { attrs, kind }) | ||
477 | } | ||
478 | |||
479 | fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { | ||
480 | Attrs::new(item, &self.hygiene) | ||
481 | } | ||
482 | } | ||