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/item_tree.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/item_tree.rs')
-rw-r--r-- | crates/ra_hir_def/src/item_tree.rs | 697 |
1 files changed, 697 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs new file mode 100644 index 000000000..d7bc64e6c --- /dev/null +++ b/crates/ra_hir_def/src/item_tree.rs | |||
@@ -0,0 +1,697 @@ | |||
1 | //! A simplified AST that only contains items. | ||
2 | |||
3 | mod lower; | ||
4 | #[cfg(test)] | ||
5 | mod tests; | ||
6 | |||
7 | use std::{ | ||
8 | fmt::{self, Debug}, | ||
9 | hash::{Hash, Hasher}, | ||
10 | marker::PhantomData, | ||
11 | ops::{Index, Range}, | ||
12 | sync::Arc, | ||
13 | }; | ||
14 | |||
15 | use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; | ||
16 | use either::Either; | ||
17 | use hir_expand::{ | ||
18 | ast_id_map::FileAstId, | ||
19 | hygiene::Hygiene, | ||
20 | name::{name, AsName, Name}, | ||
21 | HirFileId, InFile, | ||
22 | }; | ||
23 | use ra_arena::{Arena, Idx, RawId}; | ||
24 | use ra_syntax::{ast, match_ast}; | ||
25 | use rustc_hash::FxHashMap; | ||
26 | use smallvec::SmallVec; | ||
27 | use test_utils::mark; | ||
28 | |||
29 | use crate::{ | ||
30 | attr::Attrs, | ||
31 | db::DefDatabase, | ||
32 | generics::GenericParams, | ||
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | ||
34 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
35 | visibility::RawVisibility, | ||
36 | }; | ||
37 | |||
38 | #[derive(Copy, Clone, Eq, PartialEq)] | ||
39 | pub struct RawVisibilityId(u32); | ||
40 | |||
41 | impl RawVisibilityId { | ||
42 | pub const PUB: Self = RawVisibilityId(u32::max_value()); | ||
43 | pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); | ||
44 | pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); | ||
45 | } | ||
46 | |||
47 | impl fmt::Debug for RawVisibilityId { | ||
48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
49 | let mut f = f.debug_tuple("RawVisibilityId"); | ||
50 | match *self { | ||
51 | Self::PUB => f.field(&"pub"), | ||
52 | Self::PRIV => f.field(&"pub(self)"), | ||
53 | Self::PUB_CRATE => f.field(&"pub(crate)"), | ||
54 | _ => f.field(&self.0), | ||
55 | }; | ||
56 | f.finish() | ||
57 | } | ||
58 | } | ||
59 | |||
60 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
61 | pub struct GenericParamsId(u32); | ||
62 | |||
63 | impl GenericParamsId { | ||
64 | pub const EMPTY: Self = GenericParamsId(u32::max_value()); | ||
65 | } | ||
66 | |||
67 | /// The item tree of a source file. | ||
68 | #[derive(Debug, Eq, PartialEq)] | ||
69 | pub struct ItemTree { | ||
70 | top_level: SmallVec<[ModItem; 1]>, | ||
71 | attrs: FxHashMap<AttrOwner, Attrs>, | ||
72 | inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>, | ||
73 | |||
74 | data: Option<Box<ItemTreeData>>, | ||
75 | } | ||
76 | |||
77 | impl ItemTree { | ||
78 | pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { | ||
79 | let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); | ||
80 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { | ||
81 | node | ||
82 | } else { | ||
83 | return Arc::new(Self::empty()); | ||
84 | }; | ||
85 | |||
86 | let hygiene = Hygiene::new(db.upcast(), file_id); | ||
87 | let ctx = lower::Ctx::new(db, hygiene.clone(), file_id); | ||
88 | let mut top_attrs = None; | ||
89 | let mut item_tree = match_ast! { | ||
90 | match syntax { | ||
91 | ast::SourceFile(file) => { | ||
92 | top_attrs = Some(Attrs::new(&file, &hygiene)); | ||
93 | ctx.lower_module_items(&file) | ||
94 | }, | ||
95 | ast::MacroItems(items) => { | ||
96 | ctx.lower_module_items(&items) | ||
97 | }, | ||
98 | // Macros can expand to expressions. We return an empty item tree in this case, but | ||
99 | // still need to collect inner items. | ||
100 | ast::Expr(e) => { | ||
101 | ctx.lower_inner_items(e.syntax()) | ||
102 | }, | ||
103 | _ => { | ||
104 | panic!("cannot create item tree from {:?}", syntax); | ||
105 | }, | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | if let Some(attrs) = top_attrs { | ||
110 | item_tree.attrs.insert(AttrOwner::TopLevel, attrs); | ||
111 | } | ||
112 | item_tree.shrink_to_fit(); | ||
113 | Arc::new(item_tree) | ||
114 | } | ||
115 | |||
116 | fn empty() -> Self { | ||
117 | Self { | ||
118 | top_level: Default::default(), | ||
119 | attrs: Default::default(), | ||
120 | inner_items: Default::default(), | ||
121 | data: Default::default(), | ||
122 | } | ||
123 | } | ||
124 | |||
125 | fn shrink_to_fit(&mut self) { | ||
126 | if let Some(data) = &mut self.data { | ||
127 | let ItemTreeData { | ||
128 | imports, | ||
129 | extern_crates, | ||
130 | functions, | ||
131 | structs, | ||
132 | fields, | ||
133 | unions, | ||
134 | enums, | ||
135 | variants, | ||
136 | consts, | ||
137 | statics, | ||
138 | traits, | ||
139 | impls, | ||
140 | type_aliases, | ||
141 | mods, | ||
142 | macro_calls, | ||
143 | exprs, | ||
144 | vis, | ||
145 | generics, | ||
146 | } = &mut **data; | ||
147 | |||
148 | imports.shrink_to_fit(); | ||
149 | extern_crates.shrink_to_fit(); | ||
150 | functions.shrink_to_fit(); | ||
151 | structs.shrink_to_fit(); | ||
152 | fields.shrink_to_fit(); | ||
153 | unions.shrink_to_fit(); | ||
154 | enums.shrink_to_fit(); | ||
155 | variants.shrink_to_fit(); | ||
156 | consts.shrink_to_fit(); | ||
157 | statics.shrink_to_fit(); | ||
158 | traits.shrink_to_fit(); | ||
159 | impls.shrink_to_fit(); | ||
160 | type_aliases.shrink_to_fit(); | ||
161 | mods.shrink_to_fit(); | ||
162 | macro_calls.shrink_to_fit(); | ||
163 | exprs.shrink_to_fit(); | ||
164 | |||
165 | vis.arena.shrink_to_fit(); | ||
166 | generics.arena.shrink_to_fit(); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /// Returns an iterator over all items located at the top level of the `HirFileId` this | ||
171 | /// `ItemTree` was created from. | ||
172 | pub fn top_level_items(&self) -> &[ModItem] { | ||
173 | &self.top_level | ||
174 | } | ||
175 | |||
176 | /// Returns the inner attributes of the source file. | ||
177 | pub fn top_level_attrs(&self) -> &Attrs { | ||
178 | self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) | ||
179 | } | ||
180 | |||
181 | pub fn attrs(&self, of: ModItem) -> &Attrs { | ||
182 | self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY) | ||
183 | } | ||
184 | |||
185 | /// Returns the lowered inner items that `ast` corresponds to. | ||
186 | /// | ||
187 | /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered | ||
188 | /// to multiple items in the `ItemTree`. | ||
189 | pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] { | ||
190 | &self.inner_items[&ast] | ||
191 | } | ||
192 | |||
193 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { | ||
194 | self.inner_items.values().flatten().copied() | ||
195 | } | ||
196 | |||
197 | pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { | ||
198 | // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty | ||
199 | // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). | ||
200 | let root = | ||
201 | db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree"); | ||
202 | |||
203 | let id = self[of.value].ast_id(); | ||
204 | let map = db.ast_id_map(of.file_id); | ||
205 | let ptr = map.get(id); | ||
206 | ptr.to_node(&root) | ||
207 | } | ||
208 | |||
209 | fn data(&self) -> &ItemTreeData { | ||
210 | self.data.as_ref().expect("attempted to access data of empty ItemTree") | ||
211 | } | ||
212 | |||
213 | fn data_mut(&mut self) -> &mut ItemTreeData { | ||
214 | self.data.get_or_insert_with(Box::default) | ||
215 | } | ||
216 | } | ||
217 | |||
218 | #[derive(Default, Debug, Eq, PartialEq)] | ||
219 | struct ItemVisibilities { | ||
220 | arena: Arena<RawVisibility>, | ||
221 | } | ||
222 | |||
223 | impl ItemVisibilities { | ||
224 | fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { | ||
225 | match &vis { | ||
226 | RawVisibility::Public => RawVisibilityId::PUB, | ||
227 | RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { | ||
228 | PathKind::Super(0) => RawVisibilityId::PRIV, | ||
229 | PathKind::Crate => RawVisibilityId::PUB_CRATE, | ||
230 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
231 | }, | ||
232 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | static VIS_PUB: RawVisibility = RawVisibility::Public; | ||
238 | static VIS_PRIV: RawVisibility = | ||
239 | RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); | ||
240 | static VIS_PUB_CRATE: RawVisibility = | ||
241 | RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); | ||
242 | |||
243 | #[derive(Default, Debug, Eq, PartialEq)] | ||
244 | struct GenericParamsStorage { | ||
245 | arena: Arena<GenericParams>, | ||
246 | } | ||
247 | |||
248 | impl GenericParamsStorage { | ||
249 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | ||
250 | if params.types.is_empty() && params.where_predicates.is_empty() { | ||
251 | return GenericParamsId::EMPTY; | ||
252 | } | ||
253 | |||
254 | GenericParamsId(self.arena.alloc(params).into_raw().into()) | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static EMPTY_GENERICS: GenericParams = | ||
259 | GenericParams { types: Arena::new(), where_predicates: Vec::new() }; | ||
260 | |||
261 | #[derive(Default, Debug, Eq, PartialEq)] | ||
262 | struct ItemTreeData { | ||
263 | imports: Arena<Import>, | ||
264 | extern_crates: Arena<ExternCrate>, | ||
265 | functions: Arena<Function>, | ||
266 | structs: Arena<Struct>, | ||
267 | fields: Arena<Field>, | ||
268 | unions: Arena<Union>, | ||
269 | enums: Arena<Enum>, | ||
270 | variants: Arena<Variant>, | ||
271 | consts: Arena<Const>, | ||
272 | statics: Arena<Static>, | ||
273 | traits: Arena<Trait>, | ||
274 | impls: Arena<Impl>, | ||
275 | type_aliases: Arena<TypeAlias>, | ||
276 | mods: Arena<Mod>, | ||
277 | macro_calls: Arena<MacroCall>, | ||
278 | exprs: Arena<Expr>, | ||
279 | |||
280 | vis: ItemVisibilities, | ||
281 | generics: GenericParamsStorage, | ||
282 | } | ||
283 | |||
284 | #[derive(Debug, Eq, PartialEq, Hash)] | ||
285 | enum AttrOwner { | ||
286 | /// Attributes on an item. | ||
287 | ModItem(ModItem), | ||
288 | /// Inner attributes of the source file. | ||
289 | TopLevel, | ||
290 | // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. | ||
291 | } | ||
292 | |||
293 | /// Trait implemented by all nodes in the item tree. | ||
294 | pub trait ItemTreeNode: Clone { | ||
295 | type Source: AstNode + Into<ast::ModuleItem>; | ||
296 | |||
297 | fn ast_id(&self) -> FileAstId<Self::Source>; | ||
298 | |||
299 | /// Looks up an instance of `Self` in an item tree. | ||
300 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; | ||
301 | |||
302 | /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. | ||
303 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>; | ||
304 | |||
305 | /// Upcasts a `FileItemTreeId` to a generic `ModItem`. | ||
306 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem; | ||
307 | } | ||
308 | |||
309 | pub struct FileItemTreeId<N: ItemTreeNode> { | ||
310 | index: Idx<N>, | ||
311 | _p: PhantomData<N>, | ||
312 | } | ||
313 | |||
314 | impl<N: ItemTreeNode> Clone for FileItemTreeId<N> { | ||
315 | fn clone(&self) -> Self { | ||
316 | Self { index: self.index, _p: PhantomData } | ||
317 | } | ||
318 | } | ||
319 | impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {} | ||
320 | |||
321 | impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> { | ||
322 | fn eq(&self, other: &FileItemTreeId<N>) -> bool { | ||
323 | self.index == other.index | ||
324 | } | ||
325 | } | ||
326 | impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {} | ||
327 | |||
328 | impl<N: ItemTreeNode> Hash for FileItemTreeId<N> { | ||
329 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
330 | self.index.hash(state) | ||
331 | } | ||
332 | } | ||
333 | |||
334 | impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> { | ||
335 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
336 | self.index.fmt(f) | ||
337 | } | ||
338 | } | ||
339 | |||
340 | pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>; | ||
341 | |||
342 | macro_rules! mod_items { | ||
343 | ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { | ||
344 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
345 | pub enum ModItem { | ||
346 | $( | ||
347 | $typ(FileItemTreeId<$typ>), | ||
348 | )+ | ||
349 | } | ||
350 | |||
351 | $( | ||
352 | impl From<FileItemTreeId<$typ>> for ModItem { | ||
353 | fn from(id: FileItemTreeId<$typ>) -> ModItem { | ||
354 | ModItem::$typ(id) | ||
355 | } | ||
356 | } | ||
357 | )+ | ||
358 | |||
359 | $( | ||
360 | impl ItemTreeNode for $typ { | ||
361 | type Source = $ast; | ||
362 | |||
363 | fn ast_id(&self) -> FileAstId<Self::Source> { | ||
364 | self.ast_id | ||
365 | } | ||
366 | |||
367 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { | ||
368 | &tree.data().$fld[index] | ||
369 | } | ||
370 | |||
371 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { | ||
372 | if let ModItem::$typ(id) = mod_item { | ||
373 | Some(id) | ||
374 | } else { | ||
375 | None | ||
376 | } | ||
377 | } | ||
378 | |||
379 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem { | ||
380 | ModItem::$typ(id) | ||
381 | } | ||
382 | } | ||
383 | |||
384 | impl Index<Idx<$typ>> for ItemTree { | ||
385 | type Output = $typ; | ||
386 | |||
387 | fn index(&self, index: Idx<$typ>) -> &Self::Output { | ||
388 | &self.data().$fld[index] | ||
389 | } | ||
390 | } | ||
391 | )+ | ||
392 | }; | ||
393 | } | ||
394 | |||
395 | mod_items! { | ||
396 | Import in imports -> ast::UseItem, | ||
397 | ExternCrate in extern_crates -> ast::ExternCrateItem, | ||
398 | Function in functions -> ast::FnDef, | ||
399 | Struct in structs -> ast::StructDef, | ||
400 | Union in unions -> ast::UnionDef, | ||
401 | Enum in enums -> ast::EnumDef, | ||
402 | Const in consts -> ast::ConstDef, | ||
403 | Static in statics -> ast::StaticDef, | ||
404 | Trait in traits -> ast::TraitDef, | ||
405 | Impl in impls -> ast::ImplDef, | ||
406 | TypeAlias in type_aliases -> ast::TypeAliasDef, | ||
407 | Mod in mods -> ast::Module, | ||
408 | MacroCall in macro_calls -> ast::MacroCall, | ||
409 | } | ||
410 | |||
411 | macro_rules! impl_index { | ||
412 | ( $($fld:ident: $t:ty),+ $(,)? ) => { | ||
413 | $( | ||
414 | impl Index<Idx<$t>> for ItemTree { | ||
415 | type Output = $t; | ||
416 | |||
417 | fn index(&self, index: Idx<$t>) -> &Self::Output { | ||
418 | &self.data().$fld[index] | ||
419 | } | ||
420 | } | ||
421 | )+ | ||
422 | }; | ||
423 | } | ||
424 | |||
425 | impl_index!(fields: Field, variants: Variant, exprs: Expr); | ||
426 | |||
427 | impl Index<RawVisibilityId> for ItemTree { | ||
428 | type Output = RawVisibility; | ||
429 | fn index(&self, index: RawVisibilityId) -> &Self::Output { | ||
430 | match index { | ||
431 | RawVisibilityId::PRIV => &VIS_PRIV, | ||
432 | RawVisibilityId::PUB => &VIS_PUB, | ||
433 | RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, | ||
434 | _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | impl Index<GenericParamsId> for ItemTree { | ||
440 | type Output = GenericParams; | ||
441 | |||
442 | fn index(&self, index: GenericParamsId) -> &Self::Output { | ||
443 | match index { | ||
444 | GenericParamsId::EMPTY => &EMPTY_GENERICS, | ||
445 | _ => &self.data().generics.arena[Idx::from_raw(index.0.into())], | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | ||
451 | type Output = N; | ||
452 | fn index(&self, id: FileItemTreeId<N>) -> &N { | ||
453 | N::lookup(self, id.index) | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /// A desugared `use` import. | ||
458 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
459 | pub struct Import { | ||
460 | pub path: ModPath, | ||
461 | pub alias: Option<ImportAlias>, | ||
462 | pub visibility: RawVisibilityId, | ||
463 | pub is_glob: bool, | ||
464 | pub is_prelude: bool, | ||
465 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many | ||
466 | /// `Import`s can map to the same `use` item. | ||
467 | pub ast_id: FileAstId<ast::UseItem>, | ||
468 | } | ||
469 | |||
470 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
471 | pub struct ExternCrate { | ||
472 | pub path: ModPath, | ||
473 | pub alias: Option<ImportAlias>, | ||
474 | pub visibility: RawVisibilityId, | ||
475 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
476 | pub is_macro_use: bool, | ||
477 | pub ast_id: FileAstId<ast::ExternCrateItem>, | ||
478 | } | ||
479 | |||
480 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
481 | pub struct Function { | ||
482 | pub name: Name, | ||
483 | pub visibility: RawVisibilityId, | ||
484 | pub generic_params: GenericParamsId, | ||
485 | pub has_self_param: bool, | ||
486 | pub is_unsafe: bool, | ||
487 | pub params: Box<[TypeRef]>, | ||
488 | pub ret_type: TypeRef, | ||
489 | pub ast_id: FileAstId<ast::FnDef>, | ||
490 | } | ||
491 | |||
492 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
493 | pub struct Struct { | ||
494 | pub name: Name, | ||
495 | pub visibility: RawVisibilityId, | ||
496 | pub generic_params: GenericParamsId, | ||
497 | pub fields: Fields, | ||
498 | pub ast_id: FileAstId<ast::StructDef>, | ||
499 | pub kind: StructDefKind, | ||
500 | } | ||
501 | |||
502 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
503 | pub enum StructDefKind { | ||
504 | /// `struct S { ... }` - type namespace only. | ||
505 | Record, | ||
506 | /// `struct S(...);` | ||
507 | Tuple, | ||
508 | /// `struct S;` | ||
509 | Unit, | ||
510 | } | ||
511 | |||
512 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
513 | pub struct Union { | ||
514 | pub name: Name, | ||
515 | pub visibility: RawVisibilityId, | ||
516 | pub generic_params: GenericParamsId, | ||
517 | pub fields: Fields, | ||
518 | pub ast_id: FileAstId<ast::UnionDef>, | ||
519 | } | ||
520 | |||
521 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
522 | pub struct Enum { | ||
523 | pub name: Name, | ||
524 | pub visibility: RawVisibilityId, | ||
525 | pub generic_params: GenericParamsId, | ||
526 | pub variants: Range<Idx<Variant>>, | ||
527 | pub ast_id: FileAstId<ast::EnumDef>, | ||
528 | } | ||
529 | |||
530 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
531 | pub struct Const { | ||
532 | /// const _: () = (); | ||
533 | pub name: Option<Name>, | ||
534 | pub visibility: RawVisibilityId, | ||
535 | pub type_ref: TypeRef, | ||
536 | pub ast_id: FileAstId<ast::ConstDef>, | ||
537 | } | ||
538 | |||
539 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
540 | pub struct Static { | ||
541 | pub name: Name, | ||
542 | pub visibility: RawVisibilityId, | ||
543 | pub mutable: bool, | ||
544 | pub type_ref: TypeRef, | ||
545 | pub ast_id: FileAstId<ast::StaticDef>, | ||
546 | } | ||
547 | |||
548 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
549 | pub struct Trait { | ||
550 | pub name: Name, | ||
551 | pub visibility: RawVisibilityId, | ||
552 | pub generic_params: GenericParamsId, | ||
553 | pub auto: bool, | ||
554 | pub items: Box<[AssocItem]>, | ||
555 | pub ast_id: FileAstId<ast::TraitDef>, | ||
556 | } | ||
557 | |||
558 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
559 | pub struct Impl { | ||
560 | pub generic_params: GenericParamsId, | ||
561 | pub target_trait: Option<TypeRef>, | ||
562 | pub target_type: TypeRef, | ||
563 | pub is_negative: bool, | ||
564 | pub items: Box<[AssocItem]>, | ||
565 | pub ast_id: FileAstId<ast::ImplDef>, | ||
566 | } | ||
567 | |||
568 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
569 | pub struct TypeAlias { | ||
570 | pub name: Name, | ||
571 | pub visibility: RawVisibilityId, | ||
572 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | ||
573 | pub bounds: Box<[TypeBound]>, | ||
574 | pub generic_params: GenericParamsId, | ||
575 | pub type_ref: Option<TypeRef>, | ||
576 | pub ast_id: FileAstId<ast::TypeAliasDef>, | ||
577 | } | ||
578 | |||
579 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
580 | pub struct Mod { | ||
581 | pub name: Name, | ||
582 | pub visibility: RawVisibilityId, | ||
583 | pub kind: ModKind, | ||
584 | pub ast_id: FileAstId<ast::Module>, | ||
585 | } | ||
586 | |||
587 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
588 | pub enum ModKind { | ||
589 | /// `mod m { ... }` | ||
590 | Inline { items: Box<[ModItem]> }, | ||
591 | |||
592 | /// `mod m;` | ||
593 | Outline {}, | ||
594 | } | ||
595 | |||
596 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
597 | pub struct MacroCall { | ||
598 | /// For `macro_rules!` declarations, this is the name of the declared macro. | ||
599 | pub name: Option<Name>, | ||
600 | /// Path to the called macro. | ||
601 | pub path: ModPath, | ||
602 | /// Has `#[macro_export]`. | ||
603 | pub is_export: bool, | ||
604 | /// Has `#[macro_export(local_inner_macros)]`. | ||
605 | pub is_local_inner: bool, | ||
606 | /// Has `#[rustc_builtin_macro]`. | ||
607 | pub is_builtin: bool, | ||
608 | pub ast_id: FileAstId<ast::MacroCall>, | ||
609 | } | ||
610 | |||
611 | // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array | ||
612 | // lengths, but we don't do much with them yet. | ||
613 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
614 | pub struct Expr; | ||
615 | |||
616 | macro_rules! impl_froms { | ||
617 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | ||
618 | $( | ||
619 | impl From<$t> for $e { | ||
620 | fn from(it: $t) -> $e { | ||
621 | $e::$v(it) | ||
622 | } | ||
623 | } | ||
624 | )* | ||
625 | } | ||
626 | } | ||
627 | |||
628 | impl ModItem { | ||
629 | pub fn as_assoc_item(&self) -> Option<AssocItem> { | ||
630 | match self { | ||
631 | ModItem::Import(_) | ||
632 | | ModItem::ExternCrate(_) | ||
633 | | ModItem::Struct(_) | ||
634 | | ModItem::Union(_) | ||
635 | | ModItem::Enum(_) | ||
636 | | ModItem::Static(_) | ||
637 | | ModItem::Trait(_) | ||
638 | | ModItem::Impl(_) | ||
639 | | ModItem::Mod(_) => None, | ||
640 | ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), | ||
641 | ModItem::Const(konst) => Some(AssocItem::Const(*konst)), | ||
642 | ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), | ||
643 | ModItem::Function(func) => Some(AssocItem::Function(*func)), | ||
644 | } | ||
645 | } | ||
646 | |||
647 | pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { | ||
648 | N::id_from_mod_item(self) | ||
649 | } | ||
650 | } | ||
651 | |||
652 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
653 | pub enum AssocItem { | ||
654 | Function(FileItemTreeId<Function>), | ||
655 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
656 | Const(FileItemTreeId<Const>), | ||
657 | MacroCall(FileItemTreeId<MacroCall>), | ||
658 | } | ||
659 | |||
660 | impl_froms!(AssocItem { | ||
661 | Function(FileItemTreeId<Function>), | ||
662 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
663 | Const(FileItemTreeId<Const>), | ||
664 | MacroCall(FileItemTreeId<MacroCall>), | ||
665 | }); | ||
666 | |||
667 | impl From<AssocItem> for ModItem { | ||
668 | fn from(item: AssocItem) -> Self { | ||
669 | match item { | ||
670 | AssocItem::Function(it) => it.into(), | ||
671 | AssocItem::TypeAlias(it) => it.into(), | ||
672 | AssocItem::Const(it) => it.into(), | ||
673 | AssocItem::MacroCall(it) => it.into(), | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | |||
678 | #[derive(Debug, Eq, PartialEq)] | ||
679 | pub struct Variant { | ||
680 | pub name: Name, | ||
681 | pub fields: Fields, | ||
682 | } | ||
683 | |||
684 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
685 | pub enum Fields { | ||
686 | Record(Range<Idx<Field>>), | ||
687 | Tuple(Range<Idx<Field>>), | ||
688 | Unit, | ||
689 | } | ||
690 | |||
691 | /// A single field of an enum variant or struct | ||
692 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
693 | pub struct Field { | ||
694 | pub name: Name, | ||
695 | pub type_ref: TypeRef, | ||
696 | pub visibility: RawVisibilityId, | ||
697 | } | ||