1 //! A simplified AST that only contains items. 2 //! 3 //! This is the primary IR used throughout `hir_def`. It is the input to the name resolution 4 //! algorithm, as well as to the queries defined in `adt.rs`, `data.rs`, and most things in 5 //! `attr.rs`. 6 //! 7 //! `ItemTree`s are built per `HirFileId`, from the syntax tree of the parsed file. This means that 8 //! they are crate-independent: they don't know which `#[cfg]`s are active or which module they 9 //! belong to, since those concepts don't exist at this level (a single `ItemTree` might be part of 10 //! multiple crates, or might be included into the same crate twice via `#[path]`). 11 //! 12 //! One important purpose of this layer is to provide an "invalidation barrier" for incremental 13 //! computations: when typing inside an item body, the `ItemTree` of the modified file is typically 14 //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`). 15 //! 16 //! The `ItemTree` for the currently open file can be displayed by using the VS Code command 17 //! "rust-analyzer: Debug ItemTree". 18 //! 19 //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many 20 //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name 21 //! resolution has not yet been performed. `ItemTree`s are per-file, while rustc's AST and HIR are 22 //! per-crate, because we are interested in incrementally computing it. 23 //! 24 //! The representation of items in the `ItemTree` should generally mirror the surface syntax: it is 25 //! usually a bad idea to desugar a syntax-level construct to something that is structurally 26 //! different here. Name resolution needs to be able to process attributes and expand macros 27 //! (including attribute macros), and having a 1-to-1 mapping between syntax and the `ItemTree` 28 //! avoids introducing subtle bugs. 29 //! 30 //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its 31 //! surface syntax. 32 33 mod lower; 34 mod pretty; 35 #[cfg(test)] 36 mod tests; 37 38 use std::{ 39 fmt::{self, Debug}, 40 hash::{Hash, Hasher}, 41 marker::PhantomData, 42 ops::Index, 43 }; 44 45 use ast::{AstNode, HasName, StructKind}; 46 use base_db::CrateId; 47 use either::Either; 48 use hir_expand::{ 49 ast_id_map::FileAstId, 50 attrs::RawAttrs, 51 hygiene::Hygiene, 52 name::{name, AsName, Name}, 53 ExpandTo, HirFileId, InFile, 54 }; 55 use intern::Interned; 56 use la_arena::{Arena, Idx, IdxRange, RawIdx}; 57 use profile::Count; 58 use rustc_hash::FxHashMap; 59 use smallvec::SmallVec; 60 use stdx::never; 61 use syntax::{ast, match_ast, SyntaxKind}; 62 use triomphe::Arc; 63 64 use crate::{ 65 attr::Attrs, 66 db::DefDatabase, 67 generics::GenericParams, 68 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, 69 type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, 70 visibility::RawVisibility, 71 BlockId, 72 }; 73 74 #[derive(Copy, Clone, Eq, PartialEq)] 75 pub struct RawVisibilityId(u32); 76 77 impl RawVisibilityId { 78 pub const PUB: Self = RawVisibilityId(u32::max_value()); 79 pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); 80 pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); 81 } 82 83 impl fmt::Debug for RawVisibilityId { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 85 let mut f = f.debug_tuple("RawVisibilityId"); 86 match *self { 87 Self::PUB => f.field(&"pub"), 88 Self::PRIV => f.field(&"pub(self)"), 89 Self::PUB_CRATE => f.field(&"pub(crate)"), 90 _ => f.field(&self.0), 91 }; 92 f.finish() 93 } 94 } 95 96 /// The item tree of a source file. 97 #[derive(Debug, Default, Eq, PartialEq)] 98 pub struct ItemTree { 99 _c: Count<Self>, 100 101 top_level: SmallVec<[ModItem; 1]>, 102 attrs: FxHashMap<AttrOwner, RawAttrs>, 103 104 data: Option<Box<ItemTreeData>>, 105 } 106 107 impl ItemTree { file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree>108 pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { 109 let _p = profile::span("file_item_tree_query").detail(|| format!("{file_id:?}")); 110 let syntax = db.parse_or_expand(file_id); 111 if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) 112 { 113 // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic 114 return Default::default(); 115 } 116 117 let ctx = lower::Ctx::new(db, file_id); 118 let mut top_attrs = None; 119 let mut item_tree = match_ast! { 120 match syntax { 121 ast::SourceFile(file) => { 122 top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.hygiene())); 123 ctx.lower_module_items(&file) 124 }, 125 ast::MacroItems(items) => { 126 ctx.lower_module_items(&items) 127 }, 128 ast::MacroStmts(stmts) => { 129 // The produced statements can include items, which should be added as top-level 130 // items. 131 ctx.lower_macro_stmts(stmts) 132 }, 133 _ => { 134 panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}"); 135 }, 136 } 137 }; 138 139 if let Some(attrs) = top_attrs { 140 item_tree.attrs.insert(AttrOwner::TopLevel, attrs); 141 } 142 item_tree.shrink_to_fit(); 143 Arc::new(item_tree) 144 } 145 146 /// Returns an iterator over all items located at the top level of the `HirFileId` this 147 /// `ItemTree` was created from. top_level_items(&self) -> &[ModItem]148 pub fn top_level_items(&self) -> &[ModItem] { 149 &self.top_level 150 } 151 152 /// Returns the inner attributes of the source file. top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs153 pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { 154 Attrs::filter( 155 db, 156 krate, 157 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(), 158 ) 159 } 160 raw_attrs(&self, of: AttrOwner) -> &RawAttrs161 pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs { 162 self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY) 163 } 164 attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs165 pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs { 166 Attrs::filter(db, krate, self.raw_attrs(of).clone()) 167 } 168 pretty_print(&self, db: &dyn DefDatabase) -> String169 pub fn pretty_print(&self, db: &dyn DefDatabase) -> String { 170 pretty::print_item_tree(db.upcast(), self) 171 } 172 data(&self) -> &ItemTreeData173 fn data(&self) -> &ItemTreeData { 174 self.data.as_ref().expect("attempted to access data of empty ItemTree") 175 } 176 data_mut(&mut self) -> &mut ItemTreeData177 fn data_mut(&mut self) -> &mut ItemTreeData { 178 self.data.get_or_insert_with(Box::default) 179 } 180 block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree>181 fn block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> { 182 let loc = db.lookup_intern_block(block); 183 let block = loc.ast_id.to_node(db.upcast()); 184 let ctx = lower::Ctx::new(db, loc.ast_id.file_id); 185 Arc::new(ctx.lower_block(&block)) 186 } 187 shrink_to_fit(&mut self)188 fn shrink_to_fit(&mut self) { 189 if let Some(data) = &mut self.data { 190 let ItemTreeData { 191 imports, 192 extern_crates, 193 extern_blocks, 194 functions, 195 params, 196 structs, 197 fields, 198 unions, 199 enums, 200 variants, 201 consts, 202 statics, 203 traits, 204 trait_aliases, 205 impls, 206 type_aliases, 207 mods, 208 macro_calls, 209 macro_rules, 210 macro_defs, 211 vis, 212 } = &mut **data; 213 214 imports.shrink_to_fit(); 215 extern_crates.shrink_to_fit(); 216 extern_blocks.shrink_to_fit(); 217 functions.shrink_to_fit(); 218 params.shrink_to_fit(); 219 structs.shrink_to_fit(); 220 fields.shrink_to_fit(); 221 unions.shrink_to_fit(); 222 enums.shrink_to_fit(); 223 variants.shrink_to_fit(); 224 consts.shrink_to_fit(); 225 statics.shrink_to_fit(); 226 traits.shrink_to_fit(); 227 trait_aliases.shrink_to_fit(); 228 impls.shrink_to_fit(); 229 type_aliases.shrink_to_fit(); 230 mods.shrink_to_fit(); 231 macro_calls.shrink_to_fit(); 232 macro_rules.shrink_to_fit(); 233 macro_defs.shrink_to_fit(); 234 235 vis.arena.shrink_to_fit(); 236 } 237 } 238 } 239 240 #[derive(Default, Debug, Eq, PartialEq)] 241 struct ItemVisibilities { 242 arena: Arena<RawVisibility>, 243 } 244 245 impl ItemVisibilities { alloc(&mut self, vis: RawVisibility) -> RawVisibilityId246 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { 247 match &vis { 248 RawVisibility::Public => RawVisibilityId::PUB, 249 RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind { 250 PathKind::Super(0) => RawVisibilityId::PRIV, 251 PathKind::Crate => RawVisibilityId::PUB_CRATE, 252 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), 253 }, 254 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), 255 } 256 } 257 } 258 259 static VIS_PUB: RawVisibility = RawVisibility::Public; 260 static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))); 261 static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); 262 263 #[derive(Default, Debug, Eq, PartialEq)] 264 struct ItemTreeData { 265 imports: Arena<Import>, 266 extern_crates: Arena<ExternCrate>, 267 extern_blocks: Arena<ExternBlock>, 268 functions: Arena<Function>, 269 params: Arena<Param>, 270 structs: Arena<Struct>, 271 fields: Arena<Field>, 272 unions: Arena<Union>, 273 enums: Arena<Enum>, 274 variants: Arena<Variant>, 275 consts: Arena<Const>, 276 statics: Arena<Static>, 277 traits: Arena<Trait>, 278 trait_aliases: Arena<TraitAlias>, 279 impls: Arena<Impl>, 280 type_aliases: Arena<TypeAlias>, 281 mods: Arena<Mod>, 282 macro_calls: Arena<MacroCall>, 283 macro_rules: Arena<MacroRules>, 284 macro_defs: Arena<MacroDef>, 285 286 vis: ItemVisibilities, 287 } 288 289 #[derive(Debug, Eq, PartialEq, Hash)] 290 pub enum AttrOwner { 291 /// Attributes on an item. 292 ModItem(ModItem), 293 /// Inner attributes of the source file. 294 TopLevel, 295 296 Variant(Idx<Variant>), 297 Field(Idx<Field>), 298 Param(Idx<Param>), 299 } 300 301 macro_rules! from_attrs { 302 ( $( $var:ident($t:ty) ),+ ) => { 303 $( 304 impl From<$t> for AttrOwner { 305 fn from(t: $t) -> AttrOwner { 306 AttrOwner::$var(t) 307 } 308 } 309 )+ 310 }; 311 } 312 313 from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>)); 314 315 /// Trait implemented by all item nodes in the item tree. 316 pub trait ItemTreeNode: Clone { 317 type Source: AstNode + Into<ast::Item>; 318 ast_id(&self) -> FileAstId<Self::Source>319 fn ast_id(&self) -> FileAstId<Self::Source>; 320 321 /// Looks up an instance of `Self` in an item tree. lookup(tree: &ItemTree, index: Idx<Self>) -> &Self322 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; 323 324 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>325 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>; 326 327 /// Upcasts a `FileItemTreeId` to a generic `ModItem`. id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem328 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem; 329 } 330 331 pub struct FileItemTreeId<N: ItemTreeNode> { 332 index: Idx<N>, 333 _p: PhantomData<N>, 334 } 335 336 impl<N: ItemTreeNode> Clone for FileItemTreeId<N> { clone(&self) -> Self337 fn clone(&self) -> Self { 338 Self { index: self.index, _p: PhantomData } 339 } 340 } 341 impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {} 342 343 impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> { eq(&self, other: &FileItemTreeId<N>) -> bool344 fn eq(&self, other: &FileItemTreeId<N>) -> bool { 345 self.index == other.index 346 } 347 } 348 impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {} 349 350 impl<N: ItemTreeNode> Hash for FileItemTreeId<N> { hash<H: Hasher>(&self, state: &mut H)351 fn hash<H: Hasher>(&self, state: &mut H) { 352 self.index.hash(state) 353 } 354 } 355 356 impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 358 self.index.fmt(f) 359 } 360 } 361 362 /// Identifies a particular [`ItemTree`]. 363 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 364 pub struct TreeId { 365 file: HirFileId, 366 block: Option<BlockId>, 367 } 368 369 impl TreeId { new(file: HirFileId, block: Option<BlockId>) -> Self370 pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self { 371 Self { file, block } 372 } 373 item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree>374 pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> { 375 match self.block { 376 Some(block) => ItemTree::block_item_tree(db, block), 377 None => db.file_item_tree(self.file), 378 } 379 } 380 file_id(self) -> HirFileId381 pub(crate) fn file_id(self) -> HirFileId { 382 self.file 383 } 384 is_block(self) -> bool385 pub(crate) fn is_block(self) -> bool { 386 self.block.is_some() 387 } 388 } 389 390 #[derive(Debug)] 391 pub struct ItemTreeId<N: ItemTreeNode> { 392 tree: TreeId, 393 pub value: FileItemTreeId<N>, 394 } 395 396 impl<N: ItemTreeNode> ItemTreeId<N> { new(tree: TreeId, idx: FileItemTreeId<N>) -> Self397 pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self { 398 Self { tree, value: idx } 399 } 400 file_id(self) -> HirFileId401 pub fn file_id(self) -> HirFileId { 402 self.tree.file 403 } 404 tree_id(self) -> TreeId405 pub fn tree_id(self) -> TreeId { 406 self.tree 407 } 408 item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree>409 pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> { 410 self.tree.item_tree(db) 411 } 412 } 413 414 impl<N: ItemTreeNode> Copy for ItemTreeId<N> {} 415 impl<N: ItemTreeNode> Clone for ItemTreeId<N> { clone(&self) -> Self416 fn clone(&self) -> Self { 417 *self 418 } 419 } 420 421 impl<N: ItemTreeNode> PartialEq for ItemTreeId<N> { eq(&self, other: &Self) -> bool422 fn eq(&self, other: &Self) -> bool { 423 self.tree == other.tree && self.value == other.value 424 } 425 } 426 427 impl<N: ItemTreeNode> Eq for ItemTreeId<N> {} 428 429 impl<N: ItemTreeNode> Hash for ItemTreeId<N> { hash<H: Hasher>(&self, state: &mut H)430 fn hash<H: Hasher>(&self, state: &mut H) { 431 self.tree.hash(state); 432 self.value.hash(state); 433 } 434 } 435 436 macro_rules! mod_items { 437 ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { 438 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 439 pub enum ModItem { 440 $( 441 $typ(FileItemTreeId<$typ>), 442 )+ 443 } 444 445 $( 446 impl From<FileItemTreeId<$typ>> for ModItem { 447 fn from(id: FileItemTreeId<$typ>) -> ModItem { 448 ModItem::$typ(id) 449 } 450 } 451 )+ 452 453 $( 454 impl ItemTreeNode for $typ { 455 type Source = $ast; 456 457 fn ast_id(&self) -> FileAstId<Self::Source> { 458 self.ast_id 459 } 460 461 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { 462 &tree.data().$fld[index] 463 } 464 465 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { 466 match mod_item { 467 ModItem::$typ(id) => Some(id), 468 _ => None, 469 } 470 } 471 472 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem { 473 ModItem::$typ(id) 474 } 475 } 476 477 impl Index<Idx<$typ>> for ItemTree { 478 type Output = $typ; 479 480 fn index(&self, index: Idx<$typ>) -> &Self::Output { 481 &self.data().$fld[index] 482 } 483 } 484 )+ 485 }; 486 } 487 488 mod_items! { 489 Import in imports -> ast::Use, 490 ExternCrate in extern_crates -> ast::ExternCrate, 491 ExternBlock in extern_blocks -> ast::ExternBlock, 492 Function in functions -> ast::Fn, 493 Struct in structs -> ast::Struct, 494 Union in unions -> ast::Union, 495 Enum in enums -> ast::Enum, 496 Const in consts -> ast::Const, 497 Static in statics -> ast::Static, 498 Trait in traits -> ast::Trait, 499 TraitAlias in trait_aliases -> ast::TraitAlias, 500 Impl in impls -> ast::Impl, 501 TypeAlias in type_aliases -> ast::TypeAlias, 502 Mod in mods -> ast::Module, 503 MacroCall in macro_calls -> ast::MacroCall, 504 MacroRules in macro_rules -> ast::MacroRules, 505 MacroDef in macro_defs -> ast::MacroDef, 506 } 507 508 macro_rules! impl_index { 509 ( $($fld:ident: $t:ty),+ $(,)? ) => { 510 $( 511 impl Index<Idx<$t>> for ItemTree { 512 type Output = $t; 513 514 fn index(&self, index: Idx<$t>) -> &Self::Output { 515 &self.data().$fld[index] 516 } 517 } 518 )+ 519 }; 520 } 521 522 impl_index!(fields: Field, variants: Variant, params: Param); 523 524 impl Index<RawVisibilityId> for ItemTree { 525 type Output = RawVisibility; index(&self, index: RawVisibilityId) -> &Self::Output526 fn index(&self, index: RawVisibilityId) -> &Self::Output { 527 match index { 528 RawVisibilityId::PRIV => &VIS_PRIV, 529 RawVisibilityId::PUB => &VIS_PUB, 530 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, 531 _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], 532 } 533 } 534 } 535 536 impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 537 type Output = N; index(&self, id: FileItemTreeId<N>) -> &N538 fn index(&self, id: FileItemTreeId<N>) -> &N { 539 N::lookup(self, id.index) 540 } 541 } 542 543 #[derive(Debug, Clone, Eq, PartialEq)] 544 pub struct Import { 545 pub visibility: RawVisibilityId, 546 pub ast_id: FileAstId<ast::Use>, 547 pub use_tree: UseTree, 548 } 549 550 #[derive(Debug, Clone, Eq, PartialEq)] 551 pub struct UseTree { 552 pub index: Idx<ast::UseTree>, 553 kind: UseTreeKind, 554 } 555 556 #[derive(Debug, Clone, Eq, PartialEq)] 557 pub enum UseTreeKind { 558 /// ``` 559 /// use path::to::Item; 560 /// use path::to::Item as Renamed; 561 /// use path::to::Trait as _; 562 /// ``` 563 Single { path: Interned<ModPath>, alias: Option<ImportAlias> }, 564 565 /// ``` 566 /// use *; // (invalid, but can occur in nested tree) 567 /// use path::*; 568 /// ``` 569 Glob { path: Option<Interned<ModPath>> }, 570 571 /// ``` 572 /// use prefix::{self, Item, ...}; 573 /// ``` 574 Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> }, 575 } 576 577 #[derive(Debug, Clone, Eq, PartialEq)] 578 pub struct ExternCrate { 579 pub name: Name, 580 pub alias: Option<ImportAlias>, 581 pub visibility: RawVisibilityId, 582 pub ast_id: FileAstId<ast::ExternCrate>, 583 } 584 585 #[derive(Debug, Clone, Eq, PartialEq)] 586 pub struct ExternBlock { 587 pub abi: Option<Interned<str>>, 588 pub ast_id: FileAstId<ast::ExternBlock>, 589 pub children: Box<[ModItem]>, 590 } 591 592 #[derive(Debug, Clone, Eq, PartialEq)] 593 pub struct Function { 594 pub name: Name, 595 pub visibility: RawVisibilityId, 596 pub explicit_generic_params: Interned<GenericParams>, 597 pub abi: Option<Interned<str>>, 598 pub params: IdxRange<Param>, 599 pub ret_type: Interned<TypeRef>, 600 pub ast_id: FileAstId<ast::Fn>, 601 pub(crate) flags: FnFlags, 602 } 603 604 #[derive(Debug, Clone, Eq, PartialEq)] 605 pub enum Param { 606 Normal(Interned<TypeRef>), 607 Varargs, 608 } 609 610 bitflags::bitflags! { 611 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] 612 pub(crate) struct FnFlags: u8 { 613 const HAS_SELF_PARAM = 1 << 0; 614 const HAS_BODY = 1 << 1; 615 const HAS_DEFAULT_KW = 1 << 2; 616 const HAS_CONST_KW = 1 << 3; 617 const HAS_ASYNC_KW = 1 << 4; 618 const HAS_UNSAFE_KW = 1 << 5; 619 const IS_VARARGS = 1 << 6; 620 } 621 } 622 623 #[derive(Debug, Clone, Eq, PartialEq)] 624 pub struct Struct { 625 pub name: Name, 626 pub visibility: RawVisibilityId, 627 pub generic_params: Interned<GenericParams>, 628 pub fields: Fields, 629 pub ast_id: FileAstId<ast::Struct>, 630 } 631 632 #[derive(Debug, Clone, Eq, PartialEq)] 633 pub struct Union { 634 pub name: Name, 635 pub visibility: RawVisibilityId, 636 pub generic_params: Interned<GenericParams>, 637 pub fields: Fields, 638 pub ast_id: FileAstId<ast::Union>, 639 } 640 641 #[derive(Debug, Clone, Eq, PartialEq)] 642 pub struct Enum { 643 pub name: Name, 644 pub visibility: RawVisibilityId, 645 pub generic_params: Interned<GenericParams>, 646 pub variants: IdxRange<Variant>, 647 pub ast_id: FileAstId<ast::Enum>, 648 } 649 650 #[derive(Debug, Clone, Eq, PartialEq)] 651 pub struct Const { 652 /// `None` for `const _: () = ();` 653 pub name: Option<Name>, 654 pub visibility: RawVisibilityId, 655 pub type_ref: Interned<TypeRef>, 656 pub ast_id: FileAstId<ast::Const>, 657 } 658 659 #[derive(Debug, Clone, Eq, PartialEq)] 660 pub struct Static { 661 pub name: Name, 662 pub visibility: RawVisibilityId, 663 pub mutable: bool, 664 pub type_ref: Interned<TypeRef>, 665 pub ast_id: FileAstId<ast::Static>, 666 } 667 668 #[derive(Debug, Clone, Eq, PartialEq)] 669 pub struct Trait { 670 pub name: Name, 671 pub visibility: RawVisibilityId, 672 pub generic_params: Interned<GenericParams>, 673 pub is_auto: bool, 674 pub is_unsafe: bool, 675 pub items: Box<[AssocItem]>, 676 pub ast_id: FileAstId<ast::Trait>, 677 } 678 679 #[derive(Debug, Clone, Eq, PartialEq)] 680 pub struct TraitAlias { 681 pub name: Name, 682 pub visibility: RawVisibilityId, 683 pub generic_params: Interned<GenericParams>, 684 pub ast_id: FileAstId<ast::TraitAlias>, 685 } 686 687 #[derive(Debug, Clone, Eq, PartialEq)] 688 pub struct Impl { 689 pub generic_params: Interned<GenericParams>, 690 pub target_trait: Option<Interned<TraitRef>>, 691 pub self_ty: Interned<TypeRef>, 692 pub is_negative: bool, 693 pub items: Box<[AssocItem]>, 694 pub ast_id: FileAstId<ast::Impl>, 695 } 696 697 #[derive(Debug, Clone, PartialEq, Eq)] 698 pub struct TypeAlias { 699 pub name: Name, 700 pub visibility: RawVisibilityId, 701 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 702 pub bounds: Box<[Interned<TypeBound>]>, 703 pub generic_params: Interned<GenericParams>, 704 pub type_ref: Option<Interned<TypeRef>>, 705 pub ast_id: FileAstId<ast::TypeAlias>, 706 } 707 708 #[derive(Debug, Clone, Eq, PartialEq)] 709 pub struct Mod { 710 pub name: Name, 711 pub visibility: RawVisibilityId, 712 pub kind: ModKind, 713 pub ast_id: FileAstId<ast::Module>, 714 } 715 716 #[derive(Debug, Clone, Eq, PartialEq)] 717 pub enum ModKind { 718 /// `mod m { ... }` 719 Inline { items: Box<[ModItem]> }, 720 /// `mod m;` 721 Outline, 722 } 723 724 #[derive(Debug, Clone, Eq, PartialEq)] 725 pub struct MacroCall { 726 /// Path to the called macro. 727 pub path: Interned<ModPath>, 728 pub ast_id: FileAstId<ast::MacroCall>, 729 pub expand_to: ExpandTo, 730 } 731 732 #[derive(Debug, Clone, Eq, PartialEq)] 733 pub struct MacroRules { 734 /// The name of the declared macro. 735 pub name: Name, 736 pub ast_id: FileAstId<ast::MacroRules>, 737 } 738 739 /// "Macros 2.0" macro definition. 740 #[derive(Debug, Clone, Eq, PartialEq)] 741 pub struct MacroDef { 742 pub name: Name, 743 pub visibility: RawVisibilityId, 744 pub ast_id: FileAstId<ast::MacroDef>, 745 } 746 747 impl Import { 748 /// Maps a `UseTree` contained in this import back to its AST node. use_tree_to_ast( &self, db: &dyn DefDatabase, file_id: HirFileId, index: Idx<ast::UseTree>, ) -> ast::UseTree749 pub fn use_tree_to_ast( 750 &self, 751 db: &dyn DefDatabase, 752 file_id: HirFileId, 753 index: Idx<ast::UseTree>, 754 ) -> ast::UseTree { 755 // Re-lower the AST item and get the source map. 756 // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. 757 let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); 758 let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); 759 let hygiene = Hygiene::new(db.upcast(), file_id); 760 let (_, source_map) = 761 lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree"); 762 source_map[index].clone() 763 } 764 } 765 766 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 767 pub enum ImportKind { 768 /// The `ModPath` is imported normally. 769 Plain, 770 /// This is a glob-import of all names in the `ModPath`. 771 Glob, 772 /// This is a `some::path::self` import, which imports `some::path` only in type namespace. 773 TypeOnly, 774 } 775 776 impl UseTree { 777 /// Expands the `UseTree` into individually imported `ModPath`s. expand( &self, mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>), )778 pub fn expand( 779 &self, 780 mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>), 781 ) { 782 self.expand_impl(None, &mut cb) 783 } 784 expand_impl( &self, prefix: Option<ModPath>, cb: &mut dyn FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>), )785 fn expand_impl( 786 &self, 787 prefix: Option<ModPath>, 788 cb: &mut dyn FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>), 789 ) { 790 fn concat_mod_paths( 791 prefix: Option<ModPath>, 792 path: &ModPath, 793 ) -> Option<(ModPath, ImportKind)> { 794 match (prefix, &path.kind) { 795 (None, _) => Some((path.clone(), ImportKind::Plain)), 796 (Some(mut prefix), PathKind::Plain) => { 797 for segment in path.segments() { 798 prefix.push_segment(segment.clone()); 799 } 800 Some((prefix, ImportKind::Plain)) 801 } 802 (Some(mut prefix), PathKind::Super(n)) 803 if *n > 0 && prefix.segments().is_empty() => 804 { 805 // `super::super` + `super::rest` 806 match &mut prefix.kind { 807 PathKind::Super(m) => { 808 cov_mark::hit!(concat_super_mod_paths); 809 *m += *n; 810 for segment in path.segments() { 811 prefix.push_segment(segment.clone()); 812 } 813 Some((prefix, ImportKind::Plain)) 814 } 815 _ => None, 816 } 817 } 818 (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => { 819 // `some::path::self` == `some::path` 820 Some((prefix, ImportKind::TypeOnly)) 821 } 822 (Some(_), _) => None, 823 } 824 } 825 826 match &self.kind { 827 UseTreeKind::Single { path, alias } => { 828 if let Some((path, kind)) = concat_mod_paths(prefix, path) { 829 cb(self.index, path, kind, alias.clone()); 830 } 831 } 832 UseTreeKind::Glob { path: Some(path) } => { 833 if let Some((path, _)) = concat_mod_paths(prefix, path) { 834 cb(self.index, path, ImportKind::Glob, None); 835 } 836 } 837 UseTreeKind::Glob { path: None } => { 838 if let Some(prefix) = prefix { 839 cb(self.index, prefix, ImportKind::Glob, None); 840 } 841 } 842 UseTreeKind::Prefixed { prefix: additional_prefix, list } => { 843 let prefix = match additional_prefix { 844 Some(path) => match concat_mod_paths(prefix, path) { 845 Some((path, ImportKind::Plain)) => Some(path), 846 _ => return, 847 }, 848 None => prefix, 849 }; 850 for tree in &**list { 851 tree.expand_impl(prefix.clone(), cb); 852 } 853 } 854 } 855 } 856 } 857 858 macro_rules! impl_froms { 859 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { 860 $( 861 impl From<$t> for $e { 862 fn from(it: $t) -> $e { 863 $e::$v(it) 864 } 865 } 866 )* 867 } 868 } 869 870 impl ModItem { as_assoc_item(&self) -> Option<AssocItem>871 pub fn as_assoc_item(&self) -> Option<AssocItem> { 872 match self { 873 ModItem::Import(_) 874 | ModItem::ExternCrate(_) 875 | ModItem::ExternBlock(_) 876 | ModItem::Struct(_) 877 | ModItem::Union(_) 878 | ModItem::Enum(_) 879 | ModItem::Static(_) 880 | ModItem::Trait(_) 881 | ModItem::TraitAlias(_) 882 | ModItem::Impl(_) 883 | ModItem::Mod(_) 884 | ModItem::MacroRules(_) 885 | ModItem::MacroDef(_) => None, 886 ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), 887 ModItem::Const(konst) => Some(AssocItem::Const(*konst)), 888 ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), 889 ModItem::Function(func) => Some(AssocItem::Function(*func)), 890 } 891 } 892 ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item>893 pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> { 894 match self { 895 ModItem::Import(it) => tree[it.index].ast_id().upcast(), 896 ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), 897 ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(), 898 ModItem::Function(it) => tree[it.index].ast_id().upcast(), 899 ModItem::Struct(it) => tree[it.index].ast_id().upcast(), 900 ModItem::Union(it) => tree[it.index].ast_id().upcast(), 901 ModItem::Enum(it) => tree[it.index].ast_id().upcast(), 902 ModItem::Const(it) => tree[it.index].ast_id().upcast(), 903 ModItem::Static(it) => tree[it.index].ast_id().upcast(), 904 ModItem::Trait(it) => tree[it.index].ast_id().upcast(), 905 ModItem::TraitAlias(it) => tree[it.index].ast_id().upcast(), 906 ModItem::Impl(it) => tree[it.index].ast_id().upcast(), 907 ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(), 908 ModItem::Mod(it) => tree[it.index].ast_id().upcast(), 909 ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(), 910 ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(), 911 ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(), 912 } 913 } 914 } 915 916 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 917 pub enum AssocItem { 918 Function(FileItemTreeId<Function>), 919 TypeAlias(FileItemTreeId<TypeAlias>), 920 Const(FileItemTreeId<Const>), 921 MacroCall(FileItemTreeId<MacroCall>), 922 } 923 924 impl_froms!(AssocItem { 925 Function(FileItemTreeId<Function>), 926 TypeAlias(FileItemTreeId<TypeAlias>), 927 Const(FileItemTreeId<Const>), 928 MacroCall(FileItemTreeId<MacroCall>), 929 }); 930 931 impl From<AssocItem> for ModItem { from(item: AssocItem) -> Self932 fn from(item: AssocItem) -> Self { 933 match item { 934 AssocItem::Function(it) => it.into(), 935 AssocItem::TypeAlias(it) => it.into(), 936 AssocItem::Const(it) => it.into(), 937 AssocItem::MacroCall(it) => it.into(), 938 } 939 } 940 } 941 942 impl AssocItem { ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem>943 pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> { 944 match self { 945 AssocItem::Function(id) => tree[id].ast_id.upcast(), 946 AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(), 947 AssocItem::Const(id) => tree[id].ast_id.upcast(), 948 AssocItem::MacroCall(id) => tree[id].ast_id.upcast(), 949 } 950 } 951 } 952 953 #[derive(Debug, Eq, PartialEq)] 954 pub struct Variant { 955 pub name: Name, 956 pub fields: Fields, 957 pub ast_id: FileAstId<ast::Variant>, 958 } 959 960 #[derive(Debug, Clone, PartialEq, Eq)] 961 pub enum Fields { 962 Record(IdxRange<Field>), 963 Tuple(IdxRange<Field>), 964 Unit, 965 } 966 967 #[derive(Debug, Clone, PartialEq, Eq)] 968 pub enum FieldAstId { 969 Record(FileAstId<ast::RecordField>), 970 Tuple(FileAstId<ast::TupleField>), 971 } 972 973 /// A single field of an enum variant or struct 974 #[derive(Debug, Clone, PartialEq, Eq)] 975 pub struct Field { 976 pub name: Name, 977 pub type_ref: Interned<TypeRef>, 978 pub visibility: RawVisibilityId, 979 pub ast_id: FieldAstId, 980 } 981