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