aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/item_tree.rs
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-06-22 14:07:06 +0100
committerJonas Schievink <[email protected]>2020-06-24 15:53:16 +0100
commit4b03b39d5b4b00daffb120a4d2d9ea4a55a9a7ac (patch)
tree85431e53ce86bbcf16ba9b38fcc5f2ad27378722 /crates/ra_hir_def/src/item_tree.rs
parentb94caeb88b4aab7219d4b2f5c8c6c668199247fb (diff)
draw the rest of the owl
Diffstat (limited to 'crates/ra_hir_def/src/item_tree.rs')
-rw-r--r--crates/ra_hir_def/src/item_tree.rs133
1 files changed, 116 insertions, 17 deletions
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index aca2503a0..9a5dd701e 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -1,6 +1,8 @@
1//! A simplified AST that only contains items. 1//! A simplified AST that only contains items.
2 2
3mod lower; 3mod lower;
4#[cfg(test)]
5mod tests;
4 6
5use std::{ 7use std::{
6 fmt::{self, Debug}, 8 fmt::{self, Debug},
@@ -31,16 +33,20 @@ use crate::{
31 type_ref::{Mutability, TypeBound, TypeRef}, 33 type_ref::{Mutability, TypeBound, TypeRef},
32 visibility::RawVisibility, 34 visibility::RawVisibility,
33}; 35};
36use smallvec::SmallVec;
34 37
35/// The item tree of a source file. 38/// The item tree of a source file.
36#[derive(Debug, Default, Eq, PartialEq)] 39#[derive(Debug, Eq, PartialEq)]
37pub struct ItemTree { 40pub struct ItemTree {
41 file_id: HirFileId,
38 top_level: Vec<ModItem>, 42 top_level: Vec<ModItem>,
39 top_attrs: Attrs, 43 top_attrs: Attrs,
40 attrs: FxHashMap<ModItem, Attrs>, 44 attrs: FxHashMap<ModItem, Attrs>,
41 empty_attrs: Attrs, 45 empty_attrs: Attrs,
46 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
42 47
43 imports: Arena<Import>, 48 imports: Arena<Import>,
49 extern_crates: Arena<ExternCrate>,
44 functions: Arena<Function>, 50 functions: Arena<Function>,
45 structs: Arena<Struct>, 51 structs: Arena<Struct>,
46 fields: Arena<Field>, 52 fields: Arena<Field>,
@@ -63,7 +69,7 @@ impl ItemTree {
63 let syntax = if let Some(node) = db.parse_or_expand(file_id) { 69 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
64 node 70 node
65 } else { 71 } else {
66 return Default::default(); 72 return Arc::new(Self::empty(file_id));
67 }; 73 };
68 74
69 let hygiene = Hygiene::new(db.upcast(), file_id); 75 let hygiene = Hygiene::new(db.upcast(), file_id);
@@ -80,20 +86,41 @@ impl ItemTree {
80 file_storage = file; 86 file_storage = file;
81 &file_storage 87 &file_storage
82 }, 88 },
83 _ => return Default::default(), 89 _ => return Arc::new(Self::empty(file_id)),
84 } 90 }
85 }; 91 };
86 92
87 let map = db.ast_id_map(file_id); 93 let ctx = lower::Ctx::new(db, hygiene, file_id);
88 let mut ctx = lower::Ctx { 94 let mut item_tree = ctx.lower(item_owner);
89 tree: ItemTree::default(), 95 item_tree.top_attrs = top_attrs.unwrap_or_default();
90 hygiene, 96 Arc::new(item_tree)
91 file: file_id, 97 }
92 source_ast_id_map: map, 98
93 body_ctx: crate::body::LowerCtx::new(db, file_id), 99 fn empty(file_id: HirFileId) -> Self {
94 }; 100 Self {
95 ctx.tree.top_attrs = top_attrs.unwrap_or_default(); 101 file_id,
96 Arc::new(ctx.lower(item_owner)) 102 top_level: Default::default(),
103 top_attrs: Default::default(),
104 attrs: Default::default(),
105 empty_attrs: Default::default(),
106 inner_items: Default::default(),
107 imports: Default::default(),
108 extern_crates: Default::default(),
109 functions: Default::default(),
110 structs: Default::default(),
111 fields: Default::default(),
112 unions: Default::default(),
113 enums: Default::default(),
114 variants: Default::default(),
115 consts: Default::default(),
116 statics: Default::default(),
117 traits: Default::default(),
118 impls: Default::default(),
119 type_aliases: Default::default(),
120 mods: Default::default(),
121 macro_calls: Default::default(),
122 exprs: Default::default(),
123 }
97 } 124 }
98 125
99 /// Returns an iterator over all items located at the top level of the `HirFileId` this 126 /// Returns an iterator over all items located at the top level of the `HirFileId` this
@@ -110,17 +137,49 @@ impl ItemTree {
110 pub fn attrs(&self, of: ModItem) -> &Attrs { 137 pub fn attrs(&self, of: ModItem) -> &Attrs {
111 self.attrs.get(&of).unwrap_or(&self.empty_attrs) 138 self.attrs.get(&of).unwrap_or(&self.empty_attrs)
112 } 139 }
140
141 /// Returns the lowered inner items that `ast` corresponds to.
142 ///
143 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
144 /// to multiple items in the `ItemTree`.
145 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] {
146 &self.inner_items[&ast]
147 }
148
149 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
150 self.inner_items.values().flatten().copied()
151 }
152
153 pub fn source<S: ItemTreeSource>(
154 &self,
155 db: &dyn DefDatabase,
156 of: FileItemTreeId<S>,
157 ) -> S::Source {
158 // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
159 // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).
160 let root = db
161 .parse_or_expand(self.file_id)
162 .expect("parse_or_expand failed on constructed ItemTree");
163
164 let id = self[of].ast_id();
165 let map = db.ast_id_map(self.file_id);
166 let ptr = map.get(id);
167 ptr.to_node(&root)
168 }
113} 169}
114 170
115/// Trait implemented by all nodes in the item tree. 171/// Trait implemented by all nodes in the item tree.
116pub trait ItemTreeNode: Clone { 172pub trait ItemTreeNode: Clone {
117 /// Looks up an instance of `Self` in an item tree. 173 /// Looks up an instance of `Self` in an item tree.
118 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; 174 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
175
176 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
177 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
119} 178}
120 179
121/// Trait for item tree nodes that allow accessing the original AST node. 180/// Trait for item tree nodes that allow accessing the original AST node.
122pub trait ItemTreeSource: ItemTreeNode { 181pub trait ItemTreeSource: ItemTreeNode {
123 type Source: AstNode; 182 type Source: AstNode + Into<ast::ModuleItem>;
124 183
125 fn ast_id(&self) -> FileAstId<Self::Source>; 184 fn ast_id(&self) -> FileAstId<Self::Source>;
126} 185}
@@ -164,12 +223,22 @@ macro_rules! nodes {
164 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { 223 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
165 &tree.$fld[index] 224 &tree.$fld[index]
166 } 225 }
226
227
228 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
229 if let ModItem::$node(id) = mod_item {
230 Some(id)
231 } else {
232 None
233 }
234 }
167 } 235 }
168 )+ }; 236 )+ };
169} 237}
170 238
171nodes!( 239nodes!(
172 Import in imports, 240 Import in imports,
241 ExternCrate in extern_crates,
173 Function in functions, 242 Function in functions,
174 Struct in structs, 243 Struct in structs,
175 Union in unions, 244 Union in unions,
@@ -196,6 +265,8 @@ macro_rules! source {
196} 265}
197 266
198source! { 267source! {
268 Import -> ast::UseItem,
269 ExternCrate -> ast::ExternCrateItem,
199 Function -> ast::FnDef, 270 Function -> ast::FnDef,
200 Struct -> ast::StructDef, 271 Struct -> ast::StructDef,
201 Union -> ast::UnionDef, 272 Union -> ast::UnionDef,
@@ -248,7 +319,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
248 } 319 }
249} 320}
250 321
251/// A desugared `extern crate` or `use` import. 322/// A desugared `use` import.
252#[derive(Debug, Clone, Eq, PartialEq)] 323#[derive(Debug, Clone, Eq, PartialEq)]
253pub struct Import { 324pub struct Import {
254 pub path: ModPath, 325 pub path: ModPath,
@@ -256,8 +327,19 @@ pub struct Import {
256 pub visibility: RawVisibility, 327 pub visibility: RawVisibility,
257 pub is_glob: bool, 328 pub is_glob: bool,
258 pub is_prelude: bool, 329 pub is_prelude: bool,
259 pub is_extern_crate: bool, 330 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
331 /// `Import`s can map to the same `use` item.
332 pub ast_id: FileAstId<ast::UseItem>,
333}
334
335#[derive(Debug, Clone, Eq, PartialEq)]
336pub struct ExternCrate {
337 pub path: ModPath,
338 pub alias: Option<ImportAlias>,
339 pub visibility: RawVisibility,
340 /// Whether this is a `#[macro_use] extern crate ...`.
260 pub is_macro_use: bool, 341 pub is_macro_use: bool,
342 pub ast_id: FileAstId<ast::ExternCrateItem>,
261} 343}
262 344
263#[derive(Debug, Clone, Eq, PartialEq)] 345#[derive(Debug, Clone, Eq, PartialEq)]
@@ -270,7 +352,6 @@ pub struct Function {
270 pub params: Vec<TypeRef>, 352 pub params: Vec<TypeRef>,
271 pub ret_type: TypeRef, 353 pub ret_type: TypeRef,
272 pub ast_id: FileAstId<ast::FnDef>, 354 pub ast_id: FileAstId<ast::FnDef>,
273 // FIXME inner items
274} 355}
275 356
276#[derive(Debug, Clone, Eq, PartialEq)] 357#[derive(Debug, Clone, Eq, PartialEq)]
@@ -412,6 +493,7 @@ macro_rules! impl_froms {
412#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 493#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
413pub enum ModItem { 494pub enum ModItem {
414 Import(FileItemTreeId<Import>), 495 Import(FileItemTreeId<Import>),
496 ExternCrate(FileItemTreeId<ExternCrate>),
415 Function(FileItemTreeId<Function>), 497 Function(FileItemTreeId<Function>),
416 Struct(FileItemTreeId<Struct>), 498 Struct(FileItemTreeId<Struct>),
417 Union(FileItemTreeId<Union>), 499 Union(FileItemTreeId<Union>),
@@ -429,6 +511,7 @@ impl ModItem {
429 pub fn as_assoc_item(&self) -> Option<AssocItem> { 511 pub fn as_assoc_item(&self) -> Option<AssocItem> {
430 match self { 512 match self {
431 ModItem::Import(_) 513 ModItem::Import(_)
514 | ModItem::ExternCrate(_)
432 | ModItem::Struct(_) 515 | ModItem::Struct(_)
433 | ModItem::Union(_) 516 | ModItem::Union(_)
434 | ModItem::Enum(_) 517 | ModItem::Enum(_)
@@ -442,10 +525,15 @@ impl ModItem {
442 ModItem::Function(func) => Some(AssocItem::Function(*func)), 525 ModItem::Function(func) => Some(AssocItem::Function(*func)),
443 } 526 }
444 } 527 }
528
529 pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
530 N::id_from_mod_item(self)
531 }
445} 532}
446 533
447impl_froms!(ModItem { 534impl_froms!(ModItem {
448 Import(FileItemTreeId<Import>), 535 Import(FileItemTreeId<Import>),
536 ExternCrate(FileItemTreeId<ExternCrate>),
449 Function(FileItemTreeId<Function>), 537 Function(FileItemTreeId<Function>),
450 Struct(FileItemTreeId<Struct>), 538 Struct(FileItemTreeId<Struct>),
451 Union(FileItemTreeId<Union>), 539 Union(FileItemTreeId<Union>),
@@ -474,6 +562,17 @@ impl_froms!(AssocItem {
474 MacroCall(FileItemTreeId<MacroCall>), 562 MacroCall(FileItemTreeId<MacroCall>),
475}); 563});
476 564
565impl From<AssocItem> for ModItem {
566 fn from(item: AssocItem) -> Self {
567 match item {
568 AssocItem::Function(it) => it.into(),
569 AssocItem::TypeAlias(it) => it.into(),
570 AssocItem::Const(it) => it.into(),
571 AssocItem::MacroCall(it) => it.into(),
572 }
573 }
574}
575
477#[derive(Debug, Eq, PartialEq)] 576#[derive(Debug, Eq, PartialEq)]
478pub struct Variant { 577pub struct Variant {
479 pub name: Name, 578 pub name: Name,