diff options
Diffstat (limited to 'crates/ra_hir_def')
21 files changed, 2760 insertions, 1069 deletions
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index ef1f65ee0..6d43924e3 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml | |||
@@ -17,6 +17,7 @@ drop_bomb = "0.1.4" | |||
17 | fst = { version = "0.4", default-features = false } | 17 | fst = { version = "0.4", default-features = false } |
18 | itertools = "0.9.0" | 18 | itertools = "0.9.0" |
19 | indexmap = "1.4.0" | 19 | indexmap = "1.4.0" |
20 | smallvec = "1.4.0" | ||
20 | 21 | ||
21 | stdx = { path = "../stdx" } | 22 | stdx = { path = "../stdx" } |
22 | 23 | ||
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 2bc34d449..4994a2125 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -8,12 +8,12 @@ use hir_expand::{ | |||
8 | InFile, | 8 | InFile, |
9 | }; | 9 | }; |
10 | use ra_arena::{map::ArenaMap, Arena}; | 10 | use ra_arena::{map::ArenaMap, Arena}; |
11 | use ra_prof::profile; | ||
12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 11 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | body::{CfgExpander, LowerCtx}, | 14 | body::{CfgExpander, LowerCtx}, |
16 | db::DefDatabase, | 15 | db::DefDatabase, |
16 | item_tree::{Field, Fields, ItemTree}, | ||
17 | src::HasChildSource, | 17 | src::HasChildSource, |
18 | src::HasSource, | 18 | src::HasSource, |
19 | trace::Trace, | 19 | trace::Trace, |
@@ -22,6 +22,7 @@ use crate::{ | |||
22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, | 22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, |
23 | VariantId, | 23 | VariantId, |
24 | }; | 24 | }; |
25 | use ra_cfg::CfgOptions; | ||
25 | 26 | ||
26 | /// Note that we use `StructData` for unions as well! | 27 | /// Note that we use `StructData` for unions as well! |
27 | #[derive(Debug, Clone, PartialEq, Eq)] | 28 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -59,39 +60,48 @@ pub struct FieldData { | |||
59 | 60 | ||
60 | impl StructData { | 61 | impl StructData { |
61 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { | 62 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { |
62 | let src = id.lookup(db).source(db); | 63 | let loc = id.lookup(db); |
64 | let item_tree = db.item_tree(loc.id.file_id); | ||
65 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
63 | 66 | ||
64 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 67 | let strukt = &item_tree[loc.id.value]; |
65 | let variant_data = | 68 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); |
66 | VariantData::new(db, src.map(|s| s.kind()), id.lookup(db).container.module(db)); | 69 | |
67 | let variant_data = Arc::new(variant_data); | 70 | Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) |
68 | Arc::new(StructData { name, variant_data }) | ||
69 | } | 71 | } |
70 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { | 72 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { |
71 | let src = id.lookup(db).source(db); | 73 | let loc = id.lookup(db); |
72 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 74 | let item_tree = db.item_tree(loc.id.file_id); |
73 | let variant_data = VariantData::new( | 75 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
74 | db, | 76 | |
75 | src.map(|s| { | 77 | let union = &item_tree[loc.id.value]; |
76 | s.record_field_def_list() | 78 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); |
77 | .map(ast::StructKind::Record) | 79 | |
78 | .unwrap_or(ast::StructKind::Unit) | 80 | Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) |
79 | }), | ||
80 | id.lookup(db).container.module(db), | ||
81 | ); | ||
82 | let variant_data = Arc::new(variant_data); | ||
83 | Arc::new(StructData { name, variant_data }) | ||
84 | } | 81 | } |
85 | } | 82 | } |
86 | 83 | ||
87 | impl EnumData { | 84 | impl EnumData { |
88 | pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { | 85 | pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { |
89 | let _p = profile("enum_data_query"); | 86 | let loc = e.lookup(db); |
90 | let src = e.lookup(db).source(db); | 87 | let item_tree = db.item_tree(loc.id.file_id); |
91 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 88 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
92 | let mut trace = Trace::new_for_arena(); | 89 | |
93 | lower_enum(db, &mut trace, &src, e.lookup(db).container.module(db)); | 90 | let enum_ = &item_tree[loc.id.value]; |
94 | Arc::new(EnumData { name, variants: trace.into_arena() }) | 91 | let mut variants = Arena::new(); |
92 | for var_id in enum_.variants.clone() { | ||
93 | if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { | ||
94 | let var = &item_tree[var_id]; | ||
95 | let var_data = lower_fields(&item_tree, &cfg_options, &var.fields); | ||
96 | |||
97 | variants.alloc(EnumVariantData { | ||
98 | name: var.name.clone(), | ||
99 | variant_data: Arc::new(var_data), | ||
100 | }); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | Arc::new(EnumData { name: enum_.name.clone(), variants }) | ||
95 | } | 105 | } |
96 | 106 | ||
97 | pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { | 107 | pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { |
@@ -251,3 +261,35 @@ fn lower_struct( | |||
251 | ast::StructKind::Unit => StructKind::Unit, | 261 | ast::StructKind::Unit => StructKind::Unit, |
252 | } | 262 | } |
253 | } | 263 | } |
264 | |||
265 | fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData { | ||
266 | match fields { | ||
267 | Fields::Record(flds) => { | ||
268 | let mut arena = Arena::new(); | ||
269 | for field_id in flds.clone() { | ||
270 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
271 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
272 | } | ||
273 | } | ||
274 | VariantData::Record(arena) | ||
275 | } | ||
276 | Fields::Tuple(flds) => { | ||
277 | let mut arena = Arena::new(); | ||
278 | for field_id in flds.clone() { | ||
279 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
280 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
281 | } | ||
282 | } | ||
283 | VariantData::Tuple(arena) | ||
284 | } | ||
285 | Fields::Unit => VariantData::Unit, | ||
286 | } | ||
287 | } | ||
288 | |||
289 | fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData { | ||
290 | FieldData { | ||
291 | name: field.name.clone(), | ||
292 | type_ref: field.type_ref.clone(), | ||
293 | visibility: item_tree[field.visibility].clone(), | ||
294 | } | ||
295 | } | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 2eeba0572..e228e2145 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -13,7 +13,11 @@ use ra_syntax::{ | |||
13 | use tt::Subtree; | 13 | use tt::Subtree; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, | 16 | db::DefDatabase, |
17 | item_tree::{ItemTreeId, ItemTreeNode}, | ||
18 | nameres::ModuleSource, | ||
19 | path::ModPath, | ||
20 | src::HasChildSource, | ||
17 | AdtId, AttrDefId, Lookup, | 21 | AdtId, AttrDefId, Lookup, |
18 | }; | 22 | }; |
19 | 23 | ||
@@ -34,6 +38,8 @@ impl ops::Deref for Attrs { | |||
34 | } | 38 | } |
35 | 39 | ||
36 | impl Attrs { | 40 | impl Attrs { |
41 | pub const EMPTY: Attrs = Attrs { entries: None }; | ||
42 | |||
37 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | 43 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { |
38 | match def { | 44 | match def { |
39 | AttrDefId::ModuleId(module) => { | 45 | AttrDefId::ModuleId(module) => { |
@@ -65,19 +71,19 @@ impl Attrs { | |||
65 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | 71 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) |
66 | } | 72 | } |
67 | AttrDefId::AdtId(it) => match it { | 73 | AttrDefId::AdtId(it) => match it { |
68 | AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), | 74 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
69 | AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), | 75 | AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
70 | AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), | 76 | AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
71 | }, | 77 | }, |
72 | AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), | 78 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
73 | AttrDefId::MacroDefId(it) => { | 79 | AttrDefId::MacroDefId(it) => { |
74 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | 80 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) |
75 | } | 81 | } |
76 | AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), | 82 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
77 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), | 83 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
78 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), | 84 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
79 | AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), | 85 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
80 | AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), | 86 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
81 | } | 87 | } |
82 | } | 88 | } |
83 | 89 | ||
@@ -103,6 +109,18 @@ impl Attrs { | |||
103 | Attrs { entries } | 109 | Attrs { entries } |
104 | } | 110 | } |
105 | 111 | ||
112 | pub fn merge(&self, other: Attrs) -> Attrs { | ||
113 | match (&self.entries, &other.entries) { | ||
114 | (None, None) => Attrs { entries: None }, | ||
115 | (Some(entries), None) | (None, Some(entries)) => { | ||
116 | Attrs { entries: Some(entries.clone()) } | ||
117 | } | ||
118 | (Some(a), Some(b)) => { | ||
119 | Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
106 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 124 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
107 | AttrQuery { attrs: self, key } | 125 | AttrQuery { attrs: self, key } |
108 | } | 126 | } |
@@ -187,11 +205,8 @@ where | |||
187 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | 205 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) |
188 | } | 206 | } |
189 | 207 | ||
190 | fn attrs_from_loc<T>(node: T, db: &dyn DefDatabase) -> Attrs | 208 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { |
191 | where | 209 | let tree = db.item_tree(id.file_id); |
192 | T: HasSource, | 210 | let mod_item = N::id_to_mod_item(id.value); |
193 | T::Value: ast::AttrsOwner, | 211 | tree.attrs(mod_item.into()).clone() |
194 | { | ||
195 | let src = node.source(db); | ||
196 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
197 | } | 212 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f159f80af..a7e2e0982 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -27,6 +27,7 @@ use crate::{ | |||
27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
28 | }, | 28 | }, |
29 | item_scope::BuiltinShadowMode, | 29 | item_scope::BuiltinShadowMode, |
30 | item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, | ||
30 | path::{GenericArgs, Path}, | 31 | path::{GenericArgs, Path}, |
31 | type_ref::{Mutability, Rawness, TypeRef}, | 32 | type_ref::{Mutability, Rawness, TypeRef}, |
32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 33 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
@@ -35,6 +36,8 @@ use crate::{ | |||
35 | 36 | ||
36 | use super::{ExprSource, PatSource}; | 37 | use super::{ExprSource, PatSource}; |
37 | use ast::AstChildren; | 38 | use ast::AstChildren; |
39 | use rustc_hash::FxHashMap; | ||
40 | use std::{any::type_name, sync::Arc}; | ||
38 | 41 | ||
39 | pub(crate) struct LowerCtx { | 42 | pub(crate) struct LowerCtx { |
40 | hygiene: Hygiene, | 43 | hygiene: Hygiene, |
@@ -60,10 +63,10 @@ pub(super) fn lower( | |||
60 | params: Option<ast::ParamList>, | 63 | params: Option<ast::ParamList>, |
61 | body: Option<ast::Expr>, | 64 | body: Option<ast::Expr>, |
62 | ) -> (Body, BodySourceMap) { | 65 | ) -> (Body, BodySourceMap) { |
66 | let item_tree = db.item_tree(expander.current_file_id); | ||
63 | ExprCollector { | 67 | ExprCollector { |
64 | db, | 68 | db, |
65 | def, | 69 | def, |
66 | expander, | ||
67 | source_map: BodySourceMap::default(), | 70 | source_map: BodySourceMap::default(), |
68 | body: Body { | 71 | body: Body { |
69 | exprs: Arena::default(), | 72 | exprs: Arena::default(), |
@@ -72,6 +75,12 @@ pub(super) fn lower( | |||
72 | body_expr: dummy_expr_id(), | 75 | body_expr: dummy_expr_id(), |
73 | item_scope: Default::default(), | 76 | item_scope: Default::default(), |
74 | }, | 77 | }, |
78 | item_trees: { | ||
79 | let mut map = FxHashMap::default(); | ||
80 | map.insert(expander.current_file_id, item_tree); | ||
81 | map | ||
82 | }, | ||
83 | expander, | ||
75 | } | 84 | } |
76 | .collect(params, body) | 85 | .collect(params, body) |
77 | } | 86 | } |
@@ -82,6 +91,8 @@ struct ExprCollector<'a> { | |||
82 | expander: Expander, | 91 | expander: Expander, |
83 | body: Body, | 92 | body: Body, |
84 | source_map: BodySourceMap, | 93 | source_map: BodySourceMap, |
94 | |||
95 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, | ||
85 | } | 96 | } |
86 | 97 | ||
87 | impl ExprCollector<'_> { | 98 | impl ExprCollector<'_> { |
@@ -533,6 +544,9 @@ impl ExprCollector<'_> { | |||
533 | self.source_map | 544 | self.source_map |
534 | .expansions | 545 | .expansions |
535 | .insert(macro_call, self.expander.current_file_id); | 546 | .insert(macro_call, self.expander.current_file_id); |
547 | |||
548 | let item_tree = self.db.item_tree(self.expander.current_file_id); | ||
549 | self.item_trees.insert(self.expander.current_file_id, item_tree); | ||
536 | let id = self.collect_expr(expansion); | 550 | let id = self.collect_expr(expansion); |
537 | self.expander.exit(self.db, mark); | 551 | self.expander.exit(self.db, mark); |
538 | id | 552 | id |
@@ -547,6 +561,32 @@ impl ExprCollector<'_> { | |||
547 | } | 561 | } |
548 | } | 562 | } |
549 | 563 | ||
564 | fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> { | ||
565 | let id = self.expander.ast_id(ast); | ||
566 | let tree = &self.item_trees[&id.file_id]; | ||
567 | |||
568 | // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes | ||
569 | |||
570 | // Root file (non-macro). | ||
571 | let item_tree_id = tree | ||
572 | .all_inner_items() | ||
573 | .chain(tree.top_level_items().iter().copied()) | ||
574 | .filter_map(|mod_item| mod_item.downcast::<N>()) | ||
575 | .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast()) | ||
576 | .or_else(|| { | ||
577 | log::debug!( | ||
578 | "couldn't find inner {} item for {:?} (AST: `{}` - {:?})", | ||
579 | type_name::<N>(), | ||
580 | id, | ||
581 | ast.syntax(), | ||
582 | ast.syntax(), | ||
583 | ); | ||
584 | None | ||
585 | })?; | ||
586 | |||
587 | Some(ItemTreeId::new(id.file_id, item_tree_id)) | ||
588 | } | ||
589 | |||
550 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | 590 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { |
551 | if let Some(expr) = expr { | 591 | if let Some(expr) = expr { |
552 | self.collect_expr(expr) | 592 | self.collect_expr(expr) |
@@ -578,56 +618,65 @@ impl ExprCollector<'_> { | |||
578 | 618 | ||
579 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | 619 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
580 | let container = ContainerId::DefWithBodyId(self.def); | 620 | let container = ContainerId::DefWithBodyId(self.def); |
581 | for item in block.items() { | 621 | |
582 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | 622 | let items = block |
583 | ast::ModuleItem::FnDef(def) => { | 623 | .items() |
584 | let ast_id = self.expander.ast_id(&def); | 624 | .filter_map(|item| { |
585 | ( | 625 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { |
586 | FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), | 626 | ast::ModuleItem::FnDef(def) => { |
587 | def.name(), | 627 | let id = self.find_inner_item(&def)?; |
588 | ) | 628 | ( |
589 | } | 629 | FunctionLoc { container: container.into(), id }.intern(self.db).into(), |
590 | ast::ModuleItem::TypeAliasDef(def) => { | 630 | def.name(), |
591 | let ast_id = self.expander.ast_id(&def); | 631 | ) |
592 | ( | 632 | } |
593 | TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), | 633 | ast::ModuleItem::TypeAliasDef(def) => { |
594 | def.name(), | 634 | let id = self.find_inner_item(&def)?; |
595 | ) | 635 | ( |
596 | } | 636 | TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), |
597 | ast::ModuleItem::ConstDef(def) => { | 637 | def.name(), |
598 | let ast_id = self.expander.ast_id(&def); | 638 | ) |
599 | ( | 639 | } |
600 | ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), | 640 | ast::ModuleItem::ConstDef(def) => { |
601 | def.name(), | 641 | let id = self.find_inner_item(&def)?; |
602 | ) | 642 | ( |
603 | } | 643 | ConstLoc { container: container.into(), id }.intern(self.db).into(), |
604 | ast::ModuleItem::StaticDef(def) => { | 644 | def.name(), |
605 | let ast_id = self.expander.ast_id(&def); | 645 | ) |
606 | (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) | 646 | } |
607 | } | 647 | ast::ModuleItem::StaticDef(def) => { |
608 | ast::ModuleItem::StructDef(def) => { | 648 | let id = self.find_inner_item(&def)?; |
609 | let ast_id = self.expander.ast_id(&def); | 649 | (StaticLoc { container, id }.intern(self.db).into(), def.name()) |
610 | (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) | 650 | } |
611 | } | 651 | ast::ModuleItem::StructDef(def) => { |
612 | ast::ModuleItem::EnumDef(def) => { | 652 | let id = self.find_inner_item(&def)?; |
613 | let ast_id = self.expander.ast_id(&def); | 653 | (StructLoc { container, id }.intern(self.db).into(), def.name()) |
614 | (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) | 654 | } |
615 | } | 655 | ast::ModuleItem::EnumDef(def) => { |
616 | ast::ModuleItem::UnionDef(def) => { | 656 | let id = self.find_inner_item(&def)?; |
617 | let ast_id = self.expander.ast_id(&def); | 657 | (EnumLoc { container, id }.intern(self.db).into(), def.name()) |
618 | (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) | 658 | } |
619 | } | 659 | ast::ModuleItem::UnionDef(def) => { |
620 | ast::ModuleItem::TraitDef(def) => { | 660 | let id = self.find_inner_item(&def)?; |
621 | let ast_id = self.expander.ast_id(&def); | 661 | (UnionLoc { container, id }.intern(self.db).into(), def.name()) |
622 | (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) | 662 | } |
623 | } | 663 | ast::ModuleItem::TraitDef(def) => { |
624 | ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks | 664 | let id = self.find_inner_item(&def)?; |
625 | ast::ModuleItem::ImplDef(_) | 665 | (TraitLoc { container, id }.intern(self.db).into(), def.name()) |
626 | | ast::ModuleItem::UseItem(_) | 666 | } |
627 | | ast::ModuleItem::ExternCrateItem(_) | 667 | ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks |
628 | | ast::ModuleItem::Module(_) | 668 | ast::ModuleItem::ImplDef(_) |
629 | | ast::ModuleItem::MacroCall(_) => continue, | 669 | | ast::ModuleItem::UseItem(_) |
630 | }; | 670 | | ast::ModuleItem::ExternCrateItem(_) |
671 | | ast::ModuleItem::Module(_) | ||
672 | | ast::ModuleItem::MacroCall(_) => return None, | ||
673 | }; | ||
674 | |||
675 | Some((def, name)) | ||
676 | }) | ||
677 | .collect::<Vec<_>>(); | ||
678 | |||
679 | for (def, name) in items { | ||
631 | self.body.item_scope.define_def(def); | 680 | self.body.item_scope.define_def(def); |
632 | if let Some(name) = name { | 681 | if let Some(name) = name { |
633 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly | 682 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 0b74199d9..99e876683 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -317,6 +317,39 @@ fn foo() { | |||
317 | ); | 317 | ); |
318 | } | 318 | } |
319 | 319 | ||
320 | #[test] | ||
321 | fn macro_inner_item() { | ||
322 | do_check( | ||
323 | r" | ||
324 | macro_rules! mac { | ||
325 | () => {{ | ||
326 | fn inner() {} | ||
327 | inner(); | ||
328 | }}; | ||
329 | } | ||
330 | |||
331 | fn foo() { | ||
332 | mac!(); | ||
333 | <|> | ||
334 | } | ||
335 | ", | ||
336 | &[], | ||
337 | ); | ||
338 | } | ||
339 | |||
340 | #[test] | ||
341 | fn broken_inner_item() { | ||
342 | do_check( | ||
343 | r" | ||
344 | fn foo() { | ||
345 | trait {} | ||
346 | <|> | ||
347 | } | ||
348 | ", | ||
349 | &[], | ||
350 | ); | ||
351 | } | ||
352 | |||
320 | fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { | 353 | fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { |
321 | let (db, position) = TestDB::with_position(ra_fixture); | 354 | let (db, position) = TestDB::with_position(ra_fixture); |
322 | let file_id = position.file_id; | 355 | let file_id = position.file_id; |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 53599e74a..282ade2a3 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -2,27 +2,19 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::{ | 5 | use hir_expand::{name::Name, InFile}; |
6 | hygiene::Hygiene, | ||
7 | name::{name, AsName, Name}, | ||
8 | AstId, InFile, | ||
9 | }; | ||
10 | use ra_prof::profile; | 6 | use ra_prof::profile; |
11 | use ra_syntax::ast::{ | 7 | use ra_syntax::ast; |
12 | self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, | ||
13 | VisibilityOwner, | ||
14 | }; | ||
15 | 8 | ||
16 | use crate::{ | 9 | use crate::{ |
17 | attr::Attrs, | 10 | attr::Attrs, |
18 | body::LowerCtx, | 11 | body::Expander, |
19 | db::DefDatabase, | 12 | db::DefDatabase, |
20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 13 | item_tree::{AssocItem, ItemTreeId, ModItem}, |
21 | src::HasSource, | 14 | type_ref::{TypeBound, TypeRef}, |
22 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
23 | visibility::RawVisibility, | 15 | visibility::RawVisibility, |
24 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
25 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
26 | }; | 18 | }; |
27 | 19 | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -41,82 +33,27 @@ pub struct FunctionData { | |||
41 | impl FunctionData { | 33 | impl FunctionData { |
42 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 34 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
43 | let loc = func.lookup(db); | 35 | let loc = func.lookup(db); |
44 | let src = loc.source(db); | 36 | let item_tree = db.item_tree(loc.id.file_id); |
45 | let ctx = LowerCtx::new(db, src.file_id); | 37 | let func = &item_tree[loc.id.value]; |
46 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 38 | |
47 | let mut params = Vec::new(); | 39 | Arc::new(FunctionData { |
48 | let mut has_self_param = false; | 40 | name: func.name.clone(), |
49 | if let Some(param_list) = src.value.param_list() { | 41 | params: func.params.to_vec(), |
50 | if let Some(self_param) = param_list.self_param() { | 42 | ret_type: func.ret_type.clone(), |
51 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 43 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), |
52 | TypeRef::from_ast(&ctx, type_ref) | 44 | has_self_param: func.has_self_param, |
53 | } else { | 45 | is_unsafe: func.is_unsafe, |
54 | let self_type = TypeRef::Path(name![Self].into()); | 46 | visibility: item_tree[func.visibility].clone(), |
55 | match self_param.kind() { | 47 | }) |
56 | ast::SelfParamKind::Owned => self_type, | ||
57 | ast::SelfParamKind::Ref => { | ||
58 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
59 | } | ||
60 | ast::SelfParamKind::MutRef => { | ||
61 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
62 | } | ||
63 | } | ||
64 | }; | ||
65 | params.push(self_type); | ||
66 | has_self_param = true; | ||
67 | } | ||
68 | for param in param_list.params() { | ||
69 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); | ||
70 | params.push(type_ref); | ||
71 | } | ||
72 | } | ||
73 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); | ||
74 | |||
75 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | ||
76 | TypeRef::from_ast(&ctx, type_ref) | ||
77 | } else { | ||
78 | TypeRef::unit() | ||
79 | }; | ||
80 | |||
81 | let ret_type = if src.value.async_token().is_some() { | ||
82 | let future_impl = desugar_future_path(ret_type); | ||
83 | let ty_bound = TypeBound::Path(future_impl); | ||
84 | TypeRef::ImplTrait(vec![ty_bound]) | ||
85 | } else { | ||
86 | ret_type | ||
87 | }; | ||
88 | |||
89 | let is_unsafe = src.value.unsafe_token().is_some(); | ||
90 | |||
91 | let vis_default = RawVisibility::default_for_container(loc.container); | ||
92 | let visibility = | ||
93 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | ||
94 | |||
95 | let sig = | ||
96 | FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; | ||
97 | Arc::new(sig) | ||
98 | } | 48 | } |
99 | } | 49 | } |
100 | 50 | ||
101 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
102 | let path = path![core::future::Future]; | ||
103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
104 | let mut last = GenericArgs::empty(); | ||
105 | last.bindings.push(AssociatedTypeBinding { | ||
106 | name: name![Output], | ||
107 | type_ref: Some(orig), | ||
108 | bounds: Vec::new(), | ||
109 | }); | ||
110 | generic_args.push(Some(Arc::new(last))); | ||
111 | |||
112 | Path::from_known_path(path, generic_args) | ||
113 | } | ||
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | 51 | #[derive(Debug, Clone, PartialEq, Eq)] |
116 | pub struct TypeAliasData { | 52 | pub struct TypeAliasData { |
117 | pub name: Name, | 53 | pub name: Name, |
118 | pub type_ref: Option<TypeRef>, | 54 | pub type_ref: Option<TypeRef>, |
119 | pub visibility: RawVisibility, | 55 | pub visibility: RawVisibility, |
56 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
120 | pub bounds: Vec<TypeBound>, | 57 | pub bounds: Vec<TypeBound>, |
121 | } | 58 | } |
122 | 59 | ||
@@ -126,22 +63,15 @@ impl TypeAliasData { | |||
126 | typ: TypeAliasId, | 63 | typ: TypeAliasId, |
127 | ) -> Arc<TypeAliasData> { | 64 | ) -> Arc<TypeAliasData> { |
128 | let loc = typ.lookup(db); | 65 | let loc = typ.lookup(db); |
129 | let node = loc.source(db); | 66 | let item_tree = db.item_tree(loc.id.file_id); |
130 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 67 | let typ = &item_tree[loc.id.value]; |
131 | let lower_ctx = LowerCtx::new(db, node.file_id); | 68 | |
132 | let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 69 | Arc::new(TypeAliasData { |
133 | let vis_default = RawVisibility::default_for_container(loc.container); | 70 | name: typ.name.clone(), |
134 | let visibility = RawVisibility::from_ast_with_default( | 71 | type_ref: typ.type_ref.clone(), |
135 | db, | 72 | visibility: item_tree[typ.visibility].clone(), |
136 | vis_default, | 73 | bounds: typ.bounds.to_vec(), |
137 | node.as_ref().map(|n| n.visibility()), | 74 | }) |
138 | ); | ||
139 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { | ||
140 | bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() | ||
141 | } else { | ||
142 | Vec::new() | ||
143 | }; | ||
144 | Arc::new(TypeAliasData { name, type_ref, visibility, bounds }) | ||
145 | } | 75 | } |
146 | } | 76 | } |
147 | 77 | ||
@@ -155,30 +85,24 @@ pub struct TraitData { | |||
155 | impl TraitData { | 85 | impl TraitData { |
156 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 86 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
157 | let tr_loc = tr.lookup(db); | 87 | let tr_loc = tr.lookup(db); |
158 | let src = tr_loc.source(db); | 88 | let item_tree = db.item_tree(tr_loc.id.file_id); |
159 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 89 | let tr_def = &item_tree[tr_loc.id.value]; |
160 | let auto = src.value.auto_token().is_some(); | 90 | let name = tr_def.name.clone(); |
91 | let auto = tr_def.auto; | ||
161 | let module_id = tr_loc.container.module(db); | 92 | let module_id = tr_loc.container.module(db); |
162 | |||
163 | let container = AssocContainerId::TraitId(tr); | 93 | let container = AssocContainerId::TraitId(tr); |
164 | let mut items = Vec::new(); | 94 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); |
165 | 95 | ||
166 | if let Some(item_list) = src.value.item_list() { | 96 | let items = collect_items( |
167 | let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); | 97 | db, |
168 | items.extend(collect_items( | 98 | module_id, |
169 | db, | 99 | &mut expander, |
170 | &mut expander, | 100 | tr_def.items.iter().copied(), |
171 | item_list.assoc_items(), | 101 | tr_loc.id.file_id, |
172 | src.file_id, | 102 | container, |
173 | container, | 103 | 100, |
174 | )); | 104 | ); |
175 | items.extend(collect_items_in_macros( | 105 | |
176 | db, | ||
177 | &mut expander, | ||
178 | &src.with_value(item_list), | ||
179 | container, | ||
180 | )); | ||
181 | } | ||
182 | Arc::new(TraitData { name, items, auto }) | 106 | Arc::new(TraitData { name, items, auto }) |
183 | } | 107 | } |
184 | 108 | ||
@@ -209,33 +133,28 @@ impl ImplData { | |||
209 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | 133 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { |
210 | let _p = profile("impl_data_query"); | 134 | let _p = profile("impl_data_query"); |
211 | let impl_loc = id.lookup(db); | 135 | let impl_loc = id.lookup(db); |
212 | let src = impl_loc.source(db); | ||
213 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
214 | 136 | ||
215 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 137 | let item_tree = db.item_tree(impl_loc.id.file_id); |
216 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); | 138 | let impl_def = &item_tree[impl_loc.id.value]; |
217 | let is_negative = src.value.excl_token().is_some(); | 139 | let target_trait = impl_def.target_trait.clone(); |
140 | let target_type = impl_def.target_type.clone(); | ||
141 | let is_negative = impl_def.is_negative; | ||
218 | let module_id = impl_loc.container.module(db); | 142 | let module_id = impl_loc.container.module(db); |
219 | let container = AssocContainerId::ImplId(id); | 143 | let container = AssocContainerId::ImplId(id); |
144 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
220 | 145 | ||
221 | let mut items: Vec<AssocItemId> = Vec::new(); | 146 | let items = collect_items( |
222 | 147 | db, | |
223 | if let Some(item_list) = src.value.item_list() { | 148 | module_id, |
224 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); | 149 | &mut expander, |
225 | items.extend( | 150 | impl_def.items.iter().copied(), |
226 | collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) | 151 | impl_loc.id.file_id, |
227 | .into_iter() | 152 | container, |
228 | .map(|(_, item)| item), | 153 | 100, |
229 | ); | 154 | ); |
230 | items.extend( | 155 | let items = items.into_iter().map(|(_, item)| item).collect(); |
231 | collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) | ||
232 | .into_iter() | ||
233 | .map(|(_, item)| item), | ||
234 | ); | ||
235 | } | ||
236 | 156 | ||
237 | let res = ImplData { target_trait, target_type, items, is_negative }; | 157 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) |
238 | Arc::new(res) | ||
239 | } | 158 | } |
240 | } | 159 | } |
241 | 160 | ||
@@ -250,22 +169,14 @@ pub struct ConstData { | |||
250 | impl ConstData { | 169 | impl ConstData { |
251 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | 170 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { |
252 | let loc = konst.lookup(db); | 171 | let loc = konst.lookup(db); |
253 | let node = loc.source(db); | 172 | let item_tree = db.item_tree(loc.id.file_id); |
254 | let vis_default = RawVisibility::default_for_container(loc.container); | 173 | let konst = &item_tree[loc.id.value]; |
255 | Arc::new(ConstData::new(db, vis_default, node)) | ||
256 | } | ||
257 | 174 | ||
258 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( | 175 | Arc::new(ConstData { |
259 | db: &dyn DefDatabase, | 176 | name: konst.name.clone(), |
260 | vis_default: RawVisibility, | 177 | type_ref: konst.type_ref.clone(), |
261 | node: InFile<N>, | 178 | visibility: item_tree[konst.visibility].clone(), |
262 | ) -> ConstData { | 179 | }) |
263 | let ctx = LowerCtx::new(db, node.file_id); | ||
264 | let name = node.value.name().map(|n| n.as_name()); | ||
265 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | ||
266 | let visibility = | ||
267 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
268 | ConstData { name, type_ref, visibility } | ||
269 | } | 180 | } |
270 | } | 181 | } |
271 | 182 | ||
@@ -279,44 +190,25 @@ pub struct StaticData { | |||
279 | 190 | ||
280 | impl StaticData { | 191 | impl StaticData { |
281 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | 192 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { |
282 | let node = konst.lookup(db).source(db); | 193 | let node = konst.lookup(db); |
283 | let ctx = LowerCtx::new(db, node.file_id); | 194 | let item_tree = db.item_tree(node.id.file_id); |
284 | 195 | let statik = &item_tree[node.id.value]; | |
285 | let name = node.value.name().map(|n| n.as_name()); | 196 | |
286 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | 197 | Arc::new(StaticData { |
287 | let mutable = node.value.mut_token().is_some(); | 198 | name: Some(statik.name.clone()), |
288 | let visibility = RawVisibility::from_ast_with_default( | 199 | type_ref: statik.type_ref.clone(), |
289 | db, | 200 | visibility: item_tree[statik.visibility].clone(), |
290 | RawVisibility::private(), | 201 | mutable: statik.mutable, |
291 | node.map(|n| n.visibility()), | 202 | }) |
292 | ); | ||
293 | |||
294 | Arc::new(StaticData { name, type_ref, visibility, mutable }) | ||
295 | } | ||
296 | } | ||
297 | |||
298 | fn collect_items_in_macros( | ||
299 | db: &dyn DefDatabase, | ||
300 | expander: &mut Expander, | ||
301 | impl_def: &InFile<ast::ItemList>, | ||
302 | container: AssocContainerId, | ||
303 | ) -> Vec<(Name, AssocItemId)> { | ||
304 | let mut res = Vec::new(); | ||
305 | |||
306 | // We set a limit to protect against infinite recursion | ||
307 | let limit = 100; | ||
308 | |||
309 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
310 | res.extend(collect_items_in_macro(db, expander, m, container, limit)) | ||
311 | } | 203 | } |
312 | |||
313 | res | ||
314 | } | 204 | } |
315 | 205 | ||
316 | fn collect_items_in_macro( | 206 | fn collect_items( |
317 | db: &dyn DefDatabase, | 207 | db: &dyn DefDatabase, |
208 | module: ModuleId, | ||
318 | expander: &mut Expander, | 209 | expander: &mut Expander, |
319 | m: ast::MacroCall, | 210 | assoc_items: impl Iterator<Item = AssocItem>, |
211 | file_id: crate::HirFileId, | ||
320 | container: AssocContainerId, | 212 | container: AssocContainerId, |
321 | limit: usize, | 213 | limit: usize, |
322 | ) -> Vec<(Name, AssocItemId)> { | 214 | ) -> Vec<(Name, AssocItemId)> { |
@@ -324,62 +216,62 @@ fn collect_items_in_macro( | |||
324 | return Vec::new(); | 216 | return Vec::new(); |
325 | } | 217 | } |
326 | 218 | ||
327 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { | 219 | let item_tree = db.item_tree(file_id); |
328 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 220 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); |
329 | let mut res = collect_items( | 221 | |
330 | db, | 222 | let mut items = Vec::new(); |
331 | expander, | 223 | for item in assoc_items { |
332 | items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), | 224 | match item { |
333 | items.file_id, | 225 | AssocItem::Function(id) => { |
334 | container, | 226 | let item = &item_tree[id]; |
335 | ); | 227 | let attrs = item_tree.attrs(ModItem::from(id).into()); |
336 | 228 | if !attrs.is_cfg_enabled(&cfg_options) { | |
337 | // Recursive collect macros | 229 | continue; |
338 | // Note that ast::ModuleItem do not include ast::MacroCall | ||
339 | // We cannot use ModuleItemOwner::items here | ||
340 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
341 | res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) | ||
342 | } | ||
343 | expander.exit(db, mark); | ||
344 | res | ||
345 | } else { | ||
346 | Vec::new() | ||
347 | } | ||
348 | } | ||
349 | |||
350 | fn collect_items( | ||
351 | db: &dyn DefDatabase, | ||
352 | expander: &mut Expander, | ||
353 | assoc_items: impl Iterator<Item = AssocItem>, | ||
354 | file_id: crate::HirFileId, | ||
355 | container: AssocContainerId, | ||
356 | ) -> Vec<(Name, AssocItemId)> { | ||
357 | let items = db.ast_id_map(file_id); | ||
358 | |||
359 | assoc_items | ||
360 | .filter_map(|item_node| match item_node { | ||
361 | ast::AssocItem::FnDef(it) => { | ||
362 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
363 | if !expander.is_cfg_enabled(&it) { | ||
364 | return None; | ||
365 | } | 230 | } |
366 | let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 231 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
367 | .intern(db); | 232 | items.push((item.name.clone(), def.into())); |
368 | Some((name, def.into())) | ||
369 | } | 233 | } |
370 | ast::AssocItem::ConstDef(it) => { | 234 | // FIXME: cfg? |
371 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 235 | AssocItem::Const(id) => { |
372 | let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 236 | let item = &item_tree[id]; |
373 | .intern(db); | 237 | let name = match item.name.clone() { |
374 | Some((name, def.into())) | 238 | Some(name) => name, |
239 | None => continue, | ||
240 | }; | ||
241 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
242 | items.push((name, def.into())); | ||
375 | } | 243 | } |
376 | ast::AssocItem::TypeAliasDef(it) => { | 244 | AssocItem::TypeAlias(id) => { |
377 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 245 | let item = &item_tree[id]; |
378 | let def = | 246 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
379 | TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 247 | items.push((item.name.clone(), def.into())); |
380 | .intern(db); | ||
381 | Some((name, def.into())) | ||
382 | } | 248 | } |
383 | }) | 249 | AssocItem::MacroCall(call) => { |
384 | .collect() | 250 | let call = &item_tree[call]; |
251 | let ast_id_map = db.ast_id_map(file_id); | ||
252 | let root = db.parse_or_expand(file_id).unwrap(); | ||
253 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
254 | |||
255 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
256 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
257 | let item_tree = db.item_tree(src.file_id); | ||
258 | let iter = | ||
259 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
260 | items.extend(collect_items( | ||
261 | db, | ||
262 | module, | ||
263 | expander, | ||
264 | iter, | ||
265 | src.file_id, | ||
266 | container, | ||
267 | limit - 1, | ||
268 | )); | ||
269 | |||
270 | expander.exit(db, mark); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | items | ||
385 | } | 277 | } |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 10cc26480..9c3ede2d7 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -14,8 +14,9 @@ use crate::{ | |||
14 | docs::Documentation, | 14 | docs::Documentation, |
15 | generics::GenericParams, | 15 | generics::GenericParams, |
16 | import_map::ImportMap, | 16 | import_map::ImportMap, |
17 | item_tree::ItemTree, | ||
17 | lang_item::{LangItemTarget, LangItems}, | 18 | lang_item::{LangItemTarget, LangItems}, |
18 | nameres::{raw::RawItems, CrateDefMap}, | 19 | nameres::CrateDefMap, |
19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 20 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
20 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 21 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
21 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 22 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, |
@@ -45,8 +46,8 @@ pub trait InternDatabase: SourceDatabase { | |||
45 | 46 | ||
46 | #[salsa::query_group(DefDatabaseStorage)] | 47 | #[salsa::query_group(DefDatabaseStorage)] |
47 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | 48 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { |
48 | #[salsa::invoke(RawItems::raw_items_query)] | 49 | #[salsa::invoke(ItemTree::item_tree_query)] |
49 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; | 50 | fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; |
50 | 51 | ||
51 | #[salsa::invoke(crate_def_map_wait)] | 52 | #[salsa::invoke(crate_def_map_wait)] |
52 | #[salsa::transparent] | 53 | #[salsa::transparent] |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 09a5241f7..6a0f493a7 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -42,7 +42,7 @@ pub enum TypeParamProvenance { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | /// Data about the generic parameters of a function, struct, impl, etc. | 44 | /// Data about the generic parameters of a function, struct, impl, etc. |
45 | #[derive(Clone, PartialEq, Eq, Debug)] | 45 | #[derive(Clone, PartialEq, Eq, Debug, Default)] |
46 | pub struct GenericParams { | 46 | pub struct GenericParams { |
47 | pub types: Arena<TypeParamData>, | 47 | pub types: Arena<TypeParamData>, |
48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, | 48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, |
@@ -74,8 +74,53 @@ impl GenericParams { | |||
74 | def: GenericDefId, | 74 | def: GenericDefId, |
75 | ) -> Arc<GenericParams> { | 75 | ) -> Arc<GenericParams> { |
76 | let _p = profile("generic_params_query"); | 76 | let _p = profile("generic_params_query"); |
77 | let (params, _source_map) = GenericParams::new(db, def); | 77 | |
78 | Arc::new(params) | 78 | let generics = match def { |
79 | GenericDefId::FunctionId(id) => { | ||
80 | let id = id.lookup(db).id; | ||
81 | let tree = db.item_tree(id.file_id); | ||
82 | let item = &tree[id.value]; | ||
83 | tree[item.generic_params].clone() | ||
84 | } | ||
85 | GenericDefId::AdtId(AdtId::StructId(id)) => { | ||
86 | let id = id.lookup(db).id; | ||
87 | let tree = db.item_tree(id.file_id); | ||
88 | let item = &tree[id.value]; | ||
89 | tree[item.generic_params].clone() | ||
90 | } | ||
91 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | ||
92 | let id = id.lookup(db).id; | ||
93 | let tree = db.item_tree(id.file_id); | ||
94 | let item = &tree[id.value]; | ||
95 | tree[item.generic_params].clone() | ||
96 | } | ||
97 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | ||
98 | let id = id.lookup(db).id; | ||
99 | let tree = db.item_tree(id.file_id); | ||
100 | let item = &tree[id.value]; | ||
101 | tree[item.generic_params].clone() | ||
102 | } | ||
103 | GenericDefId::TraitId(id) => { | ||
104 | let id = id.lookup(db).id; | ||
105 | let tree = db.item_tree(id.file_id); | ||
106 | let item = &tree[id.value]; | ||
107 | tree[item.generic_params].clone() | ||
108 | } | ||
109 | GenericDefId::TypeAliasId(id) => { | ||
110 | let id = id.lookup(db).id; | ||
111 | let tree = db.item_tree(id.file_id); | ||
112 | let item = &tree[id.value]; | ||
113 | tree[item.generic_params].clone() | ||
114 | } | ||
115 | GenericDefId::ImplId(id) => { | ||
116 | let id = id.lookup(db).id; | ||
117 | let tree = db.item_tree(id.file_id); | ||
118 | let item = &tree[id.value]; | ||
119 | tree[item.generic_params].clone() | ||
120 | } | ||
121 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
122 | }; | ||
123 | Arc::new(generics) | ||
79 | } | 124 | } |
80 | 125 | ||
81 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 126 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
@@ -156,7 +201,12 @@ impl GenericParams { | |||
156 | (generics, InFile::new(file_id, sm)) | 201 | (generics, InFile::new(file_id, sm)) |
157 | } | 202 | } |
158 | 203 | ||
159 | fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { | 204 | pub(crate) fn fill( |
205 | &mut self, | ||
206 | lower_ctx: &LowerCtx, | ||
207 | sm: &mut SourceMap, | ||
208 | node: &dyn TypeParamsOwner, | ||
209 | ) { | ||
160 | if let Some(params) = node.type_param_list() { | 210 | if let Some(params) = node.type_param_list() { |
161 | self.fill_params(lower_ctx, sm, params) | 211 | self.fill_params(lower_ctx, sm, params) |
162 | } | 212 | } |
@@ -165,7 +215,7 @@ impl GenericParams { | |||
165 | } | 215 | } |
166 | } | 216 | } |
167 | 217 | ||
168 | fn fill_bounds( | 218 | pub(crate) fn fill_bounds( |
169 | &mut self, | 219 | &mut self, |
170 | lower_ctx: &LowerCtx, | 220 | lower_ctx: &LowerCtx, |
171 | node: &dyn ast::TypeBoundsOwner, | 221 | node: &dyn ast::TypeBoundsOwner, |
@@ -229,7 +279,7 @@ impl GenericParams { | |||
229 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | 279 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); |
230 | } | 280 | } |
231 | 281 | ||
232 | fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { | 282 | pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { |
233 | type_ref.walk(&mut |type_ref| { | 283 | type_ref.walk(&mut |type_ref| { |
234 | if let TypeRef::ImplTrait(bounds) = type_ref { | 284 | if let TypeRef::ImplTrait(bounds) = type_ref { |
235 | let param = TypeParamData { | 285 | let param = TypeParamData { |
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index b03ba939a..c81b966c3 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -5,6 +5,7 @@ use hir_expand::name::Name; | |||
5 | use once_cell::sync::Lazy; | 5 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 6 | use ra_db::CrateId; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use test_utils::mark; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 11 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
@@ -126,19 +127,27 @@ impl ItemScope { | |||
126 | let mut changed = false; | 127 | let mut changed = false; |
127 | let existing = self.visible.entry(name).or_default(); | 128 | let existing = self.visible.entry(name).or_default(); |
128 | 129 | ||
129 | if existing.types.is_none() && def.types.is_some() { | 130 | macro_rules! check_changed { |
130 | existing.types = def.types; | 131 | ($changed:ident, $existing:expr, $def:expr) => { |
131 | changed = true; | 132 | match ($existing, $def) { |
132 | } | 133 | (None, Some(_)) => { |
133 | if existing.values.is_none() && def.values.is_some() { | 134 | $existing = $def; |
134 | existing.values = def.values; | 135 | $changed = true; |
135 | changed = true; | 136 | } |
136 | } | 137 | (Some(e), Some(d)) if e.0 != d.0 => { |
137 | if existing.macros.is_none() && def.macros.is_some() { | 138 | mark::hit!(import_shadowed); |
138 | existing.macros = def.macros; | 139 | $existing = $def; |
139 | changed = true; | 140 | $changed = true; |
141 | } | ||
142 | _ => {} | ||
143 | } | ||
144 | }; | ||
140 | } | 145 | } |
141 | 146 | ||
147 | check_changed!(changed, existing.types, def.types); | ||
148 | check_changed!(changed, existing.values, def.values); | ||
149 | check_changed!(changed, existing.macros, def.macros); | ||
150 | |||
142 | changed | 151 | changed |
143 | } | 152 | } |
144 | 153 | ||
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..3e603bd55 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree.rs | |||
@@ -0,0 +1,753 @@ | |||
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 ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; | ||
17 | use either::Either; | ||
18 | use hir_expand::{ | ||
19 | ast_id_map::FileAstId, | ||
20 | hygiene::Hygiene, | ||
21 | name::{name, AsName, Name}, | ||
22 | HirFileId, InFile, | ||
23 | }; | ||
24 | use ra_arena::{Arena, Idx, RawId}; | ||
25 | use ra_syntax::{ast, match_ast}; | ||
26 | use rustc_hash::FxHashMap; | ||
27 | use smallvec::SmallVec; | ||
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::ModuleItem>, 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 = ra_prof::profile("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::ModuleItem>) -> &[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::ModuleItem>; | ||
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::UseItem, | ||
415 | ExternCrate in extern_crates -> ast::ExternCrateItem, | ||
416 | Function in functions -> ast::FnDef, | ||
417 | Struct in structs -> ast::StructDef, | ||
418 | Union in unions -> ast::UnionDef, | ||
419 | Enum in enums -> ast::EnumDef, | ||
420 | Const in consts -> ast::ConstDef, | ||
421 | Static in statics -> ast::StaticDef, | ||
422 | Trait in traits -> ast::TraitDef, | ||
423 | Impl in impls -> ast::ImplDef, | ||
424 | TypeAlias in type_aliases -> ast::TypeAliasDef, | ||
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::UseItem>, | ||
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::ExternCrateItem>, | ||
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 ret_type: TypeRef, | ||
507 | pub ast_id: FileAstId<ast::FnDef>, | ||
508 | } | ||
509 | |||
510 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
511 | pub struct Struct { | ||
512 | pub name: Name, | ||
513 | pub visibility: RawVisibilityId, | ||
514 | pub generic_params: GenericParamsId, | ||
515 | pub fields: Fields, | ||
516 | pub ast_id: FileAstId<ast::StructDef>, | ||
517 | pub kind: StructDefKind, | ||
518 | } | ||
519 | |||
520 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
521 | pub enum StructDefKind { | ||
522 | /// `struct S { ... }` - type namespace only. | ||
523 | Record, | ||
524 | /// `struct S(...);` | ||
525 | Tuple, | ||
526 | /// `struct S;` | ||
527 | Unit, | ||
528 | } | ||
529 | |||
530 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
531 | pub struct Union { | ||
532 | pub name: Name, | ||
533 | pub visibility: RawVisibilityId, | ||
534 | pub generic_params: GenericParamsId, | ||
535 | pub fields: Fields, | ||
536 | pub ast_id: FileAstId<ast::UnionDef>, | ||
537 | } | ||
538 | |||
539 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
540 | pub struct Enum { | ||
541 | pub name: Name, | ||
542 | pub visibility: RawVisibilityId, | ||
543 | pub generic_params: GenericParamsId, | ||
544 | pub variants: IdRange<Variant>, | ||
545 | pub ast_id: FileAstId<ast::EnumDef>, | ||
546 | } | ||
547 | |||
548 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
549 | pub struct Const { | ||
550 | /// const _: () = (); | ||
551 | pub name: Option<Name>, | ||
552 | pub visibility: RawVisibilityId, | ||
553 | pub type_ref: TypeRef, | ||
554 | pub ast_id: FileAstId<ast::ConstDef>, | ||
555 | } | ||
556 | |||
557 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
558 | pub struct Static { | ||
559 | pub name: Name, | ||
560 | pub visibility: RawVisibilityId, | ||
561 | pub mutable: bool, | ||
562 | pub type_ref: TypeRef, | ||
563 | pub ast_id: FileAstId<ast::StaticDef>, | ||
564 | } | ||
565 | |||
566 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
567 | pub struct Trait { | ||
568 | pub name: Name, | ||
569 | pub visibility: RawVisibilityId, | ||
570 | pub generic_params: GenericParamsId, | ||
571 | pub auto: bool, | ||
572 | pub items: Box<[AssocItem]>, | ||
573 | pub ast_id: FileAstId<ast::TraitDef>, | ||
574 | } | ||
575 | |||
576 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
577 | pub struct Impl { | ||
578 | pub generic_params: GenericParamsId, | ||
579 | pub target_trait: Option<TypeRef>, | ||
580 | pub target_type: TypeRef, | ||
581 | pub is_negative: bool, | ||
582 | pub items: Box<[AssocItem]>, | ||
583 | pub ast_id: FileAstId<ast::ImplDef>, | ||
584 | } | ||
585 | |||
586 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
587 | pub struct TypeAlias { | ||
588 | pub name: Name, | ||
589 | pub visibility: RawVisibilityId, | ||
590 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | ||
591 | pub bounds: Box<[TypeBound]>, | ||
592 | pub generic_params: GenericParamsId, | ||
593 | pub type_ref: Option<TypeRef>, | ||
594 | pub ast_id: FileAstId<ast::TypeAliasDef>, | ||
595 | } | ||
596 | |||
597 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
598 | pub struct Mod { | ||
599 | pub name: Name, | ||
600 | pub visibility: RawVisibilityId, | ||
601 | pub kind: ModKind, | ||
602 | pub ast_id: FileAstId<ast::Module>, | ||
603 | } | ||
604 | |||
605 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
606 | pub enum ModKind { | ||
607 | /// `mod m { ... }` | ||
608 | Inline { items: Box<[ModItem]> }, | ||
609 | |||
610 | /// `mod m;` | ||
611 | Outline {}, | ||
612 | } | ||
613 | |||
614 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
615 | pub struct MacroCall { | ||
616 | /// For `macro_rules!` declarations, this is the name of the declared macro. | ||
617 | pub name: Option<Name>, | ||
618 | /// Path to the called macro. | ||
619 | pub path: ModPath, | ||
620 | /// Has `#[macro_export]`. | ||
621 | pub is_export: bool, | ||
622 | /// Has `#[macro_export(local_inner_macros)]`. | ||
623 | pub is_local_inner: bool, | ||
624 | /// Has `#[rustc_builtin_macro]`. | ||
625 | pub is_builtin: bool, | ||
626 | pub ast_id: FileAstId<ast::MacroCall>, | ||
627 | } | ||
628 | |||
629 | // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array | ||
630 | // lengths, but we don't do much with them yet. | ||
631 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
632 | pub struct Expr; | ||
633 | |||
634 | macro_rules! impl_froms { | ||
635 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | ||
636 | $( | ||
637 | impl From<$t> for $e { | ||
638 | fn from(it: $t) -> $e { | ||
639 | $e::$v(it) | ||
640 | } | ||
641 | } | ||
642 | )* | ||
643 | } | ||
644 | } | ||
645 | |||
646 | impl ModItem { | ||
647 | pub fn as_assoc_item(&self) -> Option<AssocItem> { | ||
648 | match self { | ||
649 | ModItem::Import(_) | ||
650 | | ModItem::ExternCrate(_) | ||
651 | | ModItem::Struct(_) | ||
652 | | ModItem::Union(_) | ||
653 | | ModItem::Enum(_) | ||
654 | | ModItem::Static(_) | ||
655 | | ModItem::Trait(_) | ||
656 | | ModItem::Impl(_) | ||
657 | | ModItem::Mod(_) => None, | ||
658 | ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), | ||
659 | ModItem::Const(konst) => Some(AssocItem::Const(*konst)), | ||
660 | ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), | ||
661 | ModItem::Function(func) => Some(AssocItem::Function(*func)), | ||
662 | } | ||
663 | } | ||
664 | |||
665 | pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { | ||
666 | N::id_from_mod_item(self) | ||
667 | } | ||
668 | } | ||
669 | |||
670 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
671 | pub enum AssocItem { | ||
672 | Function(FileItemTreeId<Function>), | ||
673 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
674 | Const(FileItemTreeId<Const>), | ||
675 | MacroCall(FileItemTreeId<MacroCall>), | ||
676 | } | ||
677 | |||
678 | impl_froms!(AssocItem { | ||
679 | Function(FileItemTreeId<Function>), | ||
680 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
681 | Const(FileItemTreeId<Const>), | ||
682 | MacroCall(FileItemTreeId<MacroCall>), | ||
683 | }); | ||
684 | |||
685 | impl From<AssocItem> for ModItem { | ||
686 | fn from(item: AssocItem) -> Self { | ||
687 | match item { | ||
688 | AssocItem::Function(it) => it.into(), | ||
689 | AssocItem::TypeAlias(it) => it.into(), | ||
690 | AssocItem::Const(it) => it.into(), | ||
691 | AssocItem::MacroCall(it) => it.into(), | ||
692 | } | ||
693 | } | ||
694 | } | ||
695 | |||
696 | #[derive(Debug, Eq, PartialEq)] | ||
697 | pub struct Variant { | ||
698 | pub name: Name, | ||
699 | pub fields: Fields, | ||
700 | } | ||
701 | |||
702 | pub struct IdRange<T> { | ||
703 | range: Range<u32>, | ||
704 | _p: PhantomData<T>, | ||
705 | } | ||
706 | |||
707 | impl<T> IdRange<T> { | ||
708 | fn new(range: Range<Idx<T>>) -> Self { | ||
709 | Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData } | ||
710 | } | ||
711 | } | ||
712 | |||
713 | impl<T> Iterator for IdRange<T> { | ||
714 | type Item = Idx<T>; | ||
715 | fn next(&mut self) -> Option<Self::Item> { | ||
716 | self.range.next().map(|raw| Idx::from_raw(raw.into())) | ||
717 | } | ||
718 | } | ||
719 | |||
720 | impl<T> fmt::Debug for IdRange<T> { | ||
721 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
722 | f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish() | ||
723 | } | ||
724 | } | ||
725 | |||
726 | impl<T> Clone for IdRange<T> { | ||
727 | fn clone(&self) -> Self { | ||
728 | Self { range: self.range.clone(), _p: PhantomData } | ||
729 | } | ||
730 | } | ||
731 | |||
732 | impl<T> PartialEq for IdRange<T> { | ||
733 | fn eq(&self, other: &Self) -> bool { | ||
734 | self.range == other.range | ||
735 | } | ||
736 | } | ||
737 | |||
738 | impl<T> Eq for IdRange<T> {} | ||
739 | |||
740 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
741 | pub enum Fields { | ||
742 | Record(IdRange<Field>), | ||
743 | Tuple(IdRange<Field>), | ||
744 | Unit, | ||
745 | } | ||
746 | |||
747 | /// A single field of an enum variant or struct | ||
748 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
749 | pub struct Field { | ||
750 | pub name: Name, | ||
751 | pub type_ref: TypeRef, | ||
752 | pub visibility: RawVisibilityId, | ||
753 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs new file mode 100644 index 000000000..5149dd141 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/lower.rs | |||
@@ -0,0 +1,698 @@ | |||
1 | //! AST -> `ItemTree` lowering code. | ||
2 | |||
3 | use super::*; | ||
4 | use crate::{ | ||
5 | attr::Attrs, | ||
6 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | ||
7 | }; | ||
8 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; | ||
9 | use ra_arena::map::ArenaMap; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, ModuleItemOwner}, | ||
12 | SyntaxNode, | ||
13 | }; | ||
14 | use smallvec::SmallVec; | ||
15 | use std::{collections::hash_map::Entry, mem, sync::Arc}; | ||
16 | |||
17 | fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { | ||
18 | FileItemTreeId { index, _p: PhantomData } | ||
19 | } | ||
20 | |||
21 | struct ModItems(SmallVec<[ModItem; 1]>); | ||
22 | |||
23 | impl<T> From<T> for ModItems | ||
24 | where | ||
25 | T: Into<ModItem>, | ||
26 | { | ||
27 | fn from(t: T) -> Self { | ||
28 | ModItems(SmallVec::from_buf([t.into(); 1])) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub(super) struct Ctx { | ||
33 | tree: ItemTree, | ||
34 | hygiene: Hygiene, | ||
35 | file: HirFileId, | ||
36 | source_ast_id_map: Arc<AstIdMap>, | ||
37 | body_ctx: crate::body::LowerCtx, | ||
38 | inner_items: Vec<ModItem>, | ||
39 | forced_visibility: Option<RawVisibilityId>, | ||
40 | } | ||
41 | |||
42 | impl Ctx { | ||
43 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | ||
44 | Self { | ||
45 | tree: ItemTree::empty(), | ||
46 | hygiene, | ||
47 | file, | ||
48 | source_ast_id_map: db.ast_id_map(file), | ||
49 | body_ctx: crate::body::LowerCtx::new(db, file), | ||
50 | inner_items: Vec::new(), | ||
51 | forced_visibility: None, | ||
52 | } | ||
53 | } | ||
54 | |||
55 | pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { | ||
56 | self.tree.top_level = item_owner | ||
57 | .items() | ||
58 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
59 | .flat_map(|items| items.0) | ||
60 | .collect(); | ||
61 | self.tree | ||
62 | } | ||
63 | |||
64 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | ||
65 | self.collect_inner_items(within); | ||
66 | self.tree | ||
67 | } | ||
68 | |||
69 | fn data(&mut self) -> &mut ItemTreeData { | ||
70 | self.tree.data_mut() | ||
71 | } | ||
72 | |||
73 | fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { | ||
74 | assert!(inner || self.inner_items.is_empty()); | ||
75 | |||
76 | // Collect inner items for 1-to-1-lowered items. | ||
77 | match item { | ||
78 | ast::ModuleItem::StructDef(_) | ||
79 | | ast::ModuleItem::UnionDef(_) | ||
80 | | ast::ModuleItem::EnumDef(_) | ||
81 | | ast::ModuleItem::FnDef(_) | ||
82 | | ast::ModuleItem::TypeAliasDef(_) | ||
83 | | ast::ModuleItem::ConstDef(_) | ||
84 | | ast::ModuleItem::StaticDef(_) | ||
85 | | ast::ModuleItem::MacroCall(_) => { | ||
86 | // Skip this if we're already collecting inner items. We'll descend into all nodes | ||
87 | // already. | ||
88 | if !inner { | ||
89 | self.collect_inner_items(item.syntax()); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // These are handled in their respective `lower_X` method (since we can't just blindly | ||
94 | // walk them). | ||
95 | ast::ModuleItem::TraitDef(_) | ||
96 | | ast::ModuleItem::ImplDef(_) | ||
97 | | ast::ModuleItem::ExternBlock(_) => {} | ||
98 | |||
99 | // These don't have inner items. | ||
100 | ast::ModuleItem::Module(_) | ||
101 | | ast::ModuleItem::ExternCrateItem(_) | ||
102 | | ast::ModuleItem::UseItem(_) => {} | ||
103 | }; | ||
104 | |||
105 | let attrs = Attrs::new(item, &self.hygiene); | ||
106 | let items = match item { | ||
107 | ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), | ||
108 | ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), | ||
109 | ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), | ||
110 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), | ||
111 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), | ||
112 | ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), | ||
113 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), | ||
114 | ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), | ||
115 | ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), | ||
116 | ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), | ||
117 | ast::ModuleItem::UseItem(ast) => Some(ModItems( | ||
118 | self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), | ||
119 | )), | ||
120 | ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), | ||
121 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
122 | ast::ModuleItem::ExternBlock(ast) => { | ||
123 | Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) | ||
124 | } | ||
125 | }; | ||
126 | |||
127 | if !attrs.is_empty() { | ||
128 | for item in items.iter().flat_map(|items| &items.0) { | ||
129 | self.add_attrs((*item).into(), attrs.clone()); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | items | ||
134 | } | ||
135 | |||
136 | fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) { | ||
137 | match self.tree.attrs.entry(item) { | ||
138 | Entry::Occupied(mut entry) => { | ||
139 | *entry.get_mut() = entry.get().merge(attrs); | ||
140 | } | ||
141 | Entry::Vacant(entry) => { | ||
142 | entry.insert(attrs); | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | fn collect_inner_items(&mut self, container: &SyntaxNode) { | ||
148 | let forced_vis = self.forced_visibility.take(); | ||
149 | let mut inner_items = mem::take(&mut self.tree.inner_items); | ||
150 | inner_items.extend( | ||
151 | container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { | ||
152 | let ast_id = self.source_ast_id_map.ast_id(&item); | ||
153 | Some((ast_id, self.lower_mod_item(&item, true)?.0)) | ||
154 | }), | ||
155 | ); | ||
156 | self.tree.inner_items = inner_items; | ||
157 | self.forced_visibility = forced_vis; | ||
158 | } | ||
159 | |||
160 | fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> { | ||
161 | match item { | ||
162 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), | ||
163 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), | ||
164 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), | ||
165 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
166 | _ => None, | ||
167 | } | ||
168 | } | ||
169 | |||
170 | fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> { | ||
171 | let visibility = self.lower_visibility(strukt); | ||
172 | let name = strukt.name()?.as_name(); | ||
173 | let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); | ||
174 | let fields = self.lower_fields(&strukt.kind()); | ||
175 | let ast_id = self.source_ast_id_map.ast_id(strukt); | ||
176 | let kind = match strukt.kind() { | ||
177 | ast::StructKind::Record(_) => StructDefKind::Record, | ||
178 | ast::StructKind::Tuple(_) => StructDefKind::Tuple, | ||
179 | ast::StructKind::Unit => StructDefKind::Unit, | ||
180 | }; | ||
181 | let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; | ||
182 | Some(id(self.data().structs.alloc(res))) | ||
183 | } | ||
184 | |||
185 | fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { | ||
186 | match strukt_kind { | ||
187 | ast::StructKind::Record(it) => { | ||
188 | let range = self.lower_record_fields(it); | ||
189 | Fields::Record(range) | ||
190 | } | ||
191 | ast::StructKind::Tuple(it) => { | ||
192 | let range = self.lower_tuple_fields(it); | ||
193 | Fields::Tuple(range) | ||
194 | } | ||
195 | ast::StructKind::Unit => Fields::Unit, | ||
196 | } | ||
197 | } | ||
198 | |||
199 | fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> IdRange<Field> { | ||
200 | let start = self.next_field_idx(); | ||
201 | for field in fields.fields() { | ||
202 | if let Some(data) = self.lower_record_field(&field) { | ||
203 | let idx = self.data().fields.alloc(data); | ||
204 | self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); | ||
205 | } | ||
206 | } | ||
207 | let end = self.next_field_idx(); | ||
208 | IdRange::new(start..end) | ||
209 | } | ||
210 | |||
211 | fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> { | ||
212 | let name = field.name()?.as_name(); | ||
213 | let visibility = self.lower_visibility(field); | ||
214 | let type_ref = self.lower_type_ref(&field.ascribed_type()?); | ||
215 | let res = Field { name, type_ref, visibility }; | ||
216 | Some(res) | ||
217 | } | ||
218 | |||
219 | fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> IdRange<Field> { | ||
220 | let start = self.next_field_idx(); | ||
221 | for (i, field) in fields.fields().enumerate() { | ||
222 | if let Some(data) = self.lower_tuple_field(i, &field) { | ||
223 | let idx = self.data().fields.alloc(data); | ||
224 | self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); | ||
225 | } | ||
226 | } | ||
227 | let end = self.next_field_idx(); | ||
228 | IdRange::new(start..end) | ||
229 | } | ||
230 | |||
231 | fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> { | ||
232 | let name = Name::new_tuple_field(idx); | ||
233 | let visibility = self.lower_visibility(field); | ||
234 | let type_ref = self.lower_type_ref(&field.type_ref()?); | ||
235 | let res = Field { name, type_ref, visibility }; | ||
236 | Some(res) | ||
237 | } | ||
238 | |||
239 | fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> { | ||
240 | let visibility = self.lower_visibility(union); | ||
241 | let name = union.name()?.as_name(); | ||
242 | let generic_params = self.lower_generic_params(GenericsOwner::Union, union); | ||
243 | let fields = match union.record_field_def_list() { | ||
244 | Some(record_field_def_list) => { | ||
245 | self.lower_fields(&StructKind::Record(record_field_def_list)) | ||
246 | } | ||
247 | None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())), | ||
248 | }; | ||
249 | let ast_id = self.source_ast_id_map.ast_id(union); | ||
250 | let res = Union { name, visibility, generic_params, fields, ast_id }; | ||
251 | Some(id(self.data().unions.alloc(res))) | ||
252 | } | ||
253 | |||
254 | fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { | ||
255 | let visibility = self.lower_visibility(enum_); | ||
256 | let name = enum_.name()?.as_name(); | ||
257 | let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); | ||
258 | let variants = match &enum_.variant_list() { | ||
259 | Some(variant_list) => self.lower_variants(variant_list), | ||
260 | None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), | ||
261 | }; | ||
262 | let ast_id = self.source_ast_id_map.ast_id(enum_); | ||
263 | let res = Enum { name, visibility, generic_params, variants, ast_id }; | ||
264 | Some(id(self.data().enums.alloc(res))) | ||
265 | } | ||
266 | |||
267 | fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> IdRange<Variant> { | ||
268 | let start = self.next_variant_idx(); | ||
269 | for variant in variants.variants() { | ||
270 | if let Some(data) = self.lower_variant(&variant) { | ||
271 | let idx = self.data().variants.alloc(data); | ||
272 | self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene)); | ||
273 | } | ||
274 | } | ||
275 | let end = self.next_variant_idx(); | ||
276 | IdRange::new(start..end) | ||
277 | } | ||
278 | |||
279 | fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> { | ||
280 | let name = variant.name()?.as_name(); | ||
281 | let fields = self.lower_fields(&variant.kind()); | ||
282 | let res = Variant { name, fields }; | ||
283 | Some(res) | ||
284 | } | ||
285 | |||
286 | fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> { | ||
287 | let visibility = self.lower_visibility(func); | ||
288 | let name = func.name()?.as_name(); | ||
289 | |||
290 | let mut params = Vec::new(); | ||
291 | let mut has_self_param = false; | ||
292 | if let Some(param_list) = func.param_list() { | ||
293 | if let Some(self_param) = param_list.self_param() { | ||
294 | let self_type = match self_param.ascribed_type() { | ||
295 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
296 | None => { | ||
297 | let self_type = TypeRef::Path(name![Self].into()); | ||
298 | match self_param.kind() { | ||
299 | ast::SelfParamKind::Owned => self_type, | ||
300 | ast::SelfParamKind::Ref => { | ||
301 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
302 | } | ||
303 | ast::SelfParamKind::MutRef => { | ||
304 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | }; | ||
309 | params.push(self_type); | ||
310 | has_self_param = true; | ||
311 | } | ||
312 | for param in param_list.params() { | ||
313 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); | ||
314 | params.push(type_ref); | ||
315 | } | ||
316 | } | ||
317 | let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { | ||
318 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
319 | _ => TypeRef::unit(), | ||
320 | }; | ||
321 | |||
322 | let ret_type = if func.async_token().is_some() { | ||
323 | let future_impl = desugar_future_path(ret_type); | ||
324 | let ty_bound = TypeBound::Path(future_impl); | ||
325 | TypeRef::ImplTrait(vec![ty_bound]) | ||
326 | } else { | ||
327 | ret_type | ||
328 | }; | ||
329 | |||
330 | let ast_id = self.source_ast_id_map.ast_id(func); | ||
331 | let mut res = Function { | ||
332 | name, | ||
333 | visibility, | ||
334 | generic_params: GenericParamsId::EMPTY, | ||
335 | has_self_param, | ||
336 | is_unsafe: func.unsafe_token().is_some(), | ||
337 | params: params.into_boxed_slice(), | ||
338 | ret_type, | ||
339 | ast_id, | ||
340 | }; | ||
341 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | ||
342 | |||
343 | Some(id(self.data().functions.alloc(res))) | ||
344 | } | ||
345 | |||
346 | fn lower_type_alias( | ||
347 | &mut self, | ||
348 | type_alias: &ast::TypeAliasDef, | ||
349 | ) -> Option<FileItemTreeId<TypeAlias>> { | ||
350 | let name = type_alias.name()?.as_name(); | ||
351 | let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); | ||
352 | let visibility = self.lower_visibility(type_alias); | ||
353 | let bounds = self.lower_type_bounds(type_alias); | ||
354 | let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); | ||
355 | let ast_id = self.source_ast_id_map.ast_id(type_alias); | ||
356 | let res = TypeAlias { | ||
357 | name, | ||
358 | visibility, | ||
359 | bounds: bounds.into_boxed_slice(), | ||
360 | generic_params, | ||
361 | type_ref, | ||
362 | ast_id, | ||
363 | }; | ||
364 | Some(id(self.data().type_aliases.alloc(res))) | ||
365 | } | ||
366 | |||
367 | fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { | ||
368 | let name = static_.name()?.as_name(); | ||
369 | let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); | ||
370 | let visibility = self.lower_visibility(static_); | ||
371 | let mutable = static_.mut_token().is_some(); | ||
372 | let ast_id = self.source_ast_id_map.ast_id(static_); | ||
373 | let res = Static { name, visibility, mutable, type_ref, ast_id }; | ||
374 | Some(id(self.data().statics.alloc(res))) | ||
375 | } | ||
376 | |||
377 | fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { | ||
378 | let name = konst.name().map(|it| it.as_name()); | ||
379 | let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); | ||
380 | let visibility = self.lower_visibility(konst); | ||
381 | let ast_id = self.source_ast_id_map.ast_id(konst); | ||
382 | let res = Const { name, visibility, type_ref, ast_id }; | ||
383 | id(self.data().consts.alloc(res)) | ||
384 | } | ||
385 | |||
386 | fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { | ||
387 | let name = module.name()?.as_name(); | ||
388 | let visibility = self.lower_visibility(module); | ||
389 | let kind = if module.semicolon_token().is_some() { | ||
390 | ModKind::Outline {} | ||
391 | } else { | ||
392 | ModKind::Inline { | ||
393 | items: module | ||
394 | .item_list() | ||
395 | .map(|list| { | ||
396 | list.items() | ||
397 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
398 | .flat_map(|items| items.0) | ||
399 | .collect() | ||
400 | }) | ||
401 | .unwrap_or_else(|| { | ||
402 | mark::hit!(name_res_works_for_broken_modules); | ||
403 | Box::new([]) as Box<[_]> | ||
404 | }), | ||
405 | } | ||
406 | }; | ||
407 | let ast_id = self.source_ast_id_map.ast_id(module); | ||
408 | let res = Mod { name, visibility, kind, ast_id }; | ||
409 | Some(id(self.data().mods.alloc(res))) | ||
410 | } | ||
411 | |||
412 | fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { | ||
413 | let name = trait_def.name()?.as_name(); | ||
414 | let visibility = self.lower_visibility(trait_def); | ||
415 | let generic_params = | ||
416 | self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); | ||
417 | let auto = trait_def.auto_token().is_some(); | ||
418 | let items = trait_def.item_list().map(|list| { | ||
419 | self.with_inherited_visibility(visibility, |this| { | ||
420 | list.items() | ||
421 | .filter_map(|item| { | ||
422 | let attrs = Attrs::new(&item, &this.hygiene); | ||
423 | this.collect_inner_items(item.syntax()); | ||
424 | this.lower_assoc_item(&item).map(|item| { | ||
425 | this.add_attrs(ModItem::from(item).into(), attrs); | ||
426 | item | ||
427 | }) | ||
428 | }) | ||
429 | .collect() | ||
430 | }) | ||
431 | }); | ||
432 | let ast_id = self.source_ast_id_map.ast_id(trait_def); | ||
433 | let res = Trait { | ||
434 | name, | ||
435 | visibility, | ||
436 | generic_params, | ||
437 | auto, | ||
438 | items: items.unwrap_or_default(), | ||
439 | ast_id, | ||
440 | }; | ||
441 | Some(id(self.data().traits.alloc(res))) | ||
442 | } | ||
443 | |||
444 | fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { | ||
445 | let generic_params = | ||
446 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | ||
447 | let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); | ||
448 | let target_type = self.lower_type_ref(&impl_def.target_type()?); | ||
449 | let is_negative = impl_def.excl_token().is_some(); | ||
450 | |||
451 | // We cannot use `assoc_items()` here as that does not include macro calls. | ||
452 | let items = impl_def | ||
453 | .item_list()? | ||
454 | .items() | ||
455 | .filter_map(|item| { | ||
456 | self.collect_inner_items(item.syntax()); | ||
457 | let assoc = self.lower_assoc_item(&item)?; | ||
458 | let attrs = Attrs::new(&item, &self.hygiene); | ||
459 | self.add_attrs(ModItem::from(assoc).into(), attrs); | ||
460 | Some(assoc) | ||
461 | }) | ||
462 | .collect(); | ||
463 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | ||
464 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; | ||
465 | Some(id(self.data().impls.alloc(res))) | ||
466 | } | ||
467 | |||
468 | fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { | ||
469 | // FIXME: cfg_attr | ||
470 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
471 | let visibility = self.lower_visibility(use_item); | ||
472 | let ast_id = self.source_ast_id_map.ast_id(use_item); | ||
473 | |||
474 | // Every use item can expand to many `Import`s. | ||
475 | let mut imports = Vec::new(); | ||
476 | let tree = self.tree.data_mut(); | ||
477 | ModPath::expand_use_item( | ||
478 | InFile::new(self.file, use_item.clone()), | ||
479 | &self.hygiene, | ||
480 | |path, _tree, is_glob, alias| { | ||
481 | imports.push(id(tree.imports.alloc(Import { | ||
482 | path, | ||
483 | alias, | ||
484 | visibility, | ||
485 | is_glob, | ||
486 | is_prelude, | ||
487 | ast_id, | ||
488 | }))); | ||
489 | }, | ||
490 | ); | ||
491 | |||
492 | imports | ||
493 | } | ||
494 | |||
495 | fn lower_extern_crate( | ||
496 | &mut self, | ||
497 | extern_crate: &ast::ExternCrateItem, | ||
498 | ) -> Option<FileItemTreeId<ExternCrate>> { | ||
499 | let path = ModPath::from_name_ref(&extern_crate.name_ref()?); | ||
500 | let alias = extern_crate.alias().map(|a| { | ||
501 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
502 | }); | ||
503 | let visibility = self.lower_visibility(extern_crate); | ||
504 | let ast_id = self.source_ast_id_map.ast_id(extern_crate); | ||
505 | // FIXME: cfg_attr | ||
506 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
507 | |||
508 | let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; | ||
509 | Some(id(self.data().extern_crates.alloc(res))) | ||
510 | } | ||
511 | |||
512 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | ||
513 | let name = m.name().map(|it| it.as_name()); | ||
514 | let attrs = Attrs::new(m, &self.hygiene); | ||
515 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; | ||
516 | |||
517 | let ast_id = self.source_ast_id_map.ast_id(m); | ||
518 | |||
519 | // FIXME: cfg_attr | ||
520 | let export_attr = attrs.by_key("macro_export"); | ||
521 | |||
522 | let is_export = export_attr.exists(); | ||
523 | let is_local_inner = if is_export { | ||
524 | export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { | ||
525 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { | ||
526 | ident.text.contains("local_inner_macros") | ||
527 | } | ||
528 | _ => false, | ||
529 | }) | ||
530 | } else { | ||
531 | false | ||
532 | }; | ||
533 | |||
534 | let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); | ||
535 | let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; | ||
536 | Some(id(self.data().macro_calls.alloc(res))) | ||
537 | } | ||
538 | |||
539 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { | ||
540 | block.extern_item_list().map_or(Vec::new(), |list| { | ||
541 | list.extern_items() | ||
542 | .filter_map(|item| { | ||
543 | self.collect_inner_items(item.syntax()); | ||
544 | let attrs = Attrs::new(&item, &self.hygiene); | ||
545 | let id: ModItem = match item { | ||
546 | ast::ExternItem::FnDef(ast) => { | ||
547 | let func = self.lower_function(&ast)?; | ||
548 | func.into() | ||
549 | } | ||
550 | ast::ExternItem::StaticDef(ast) => { | ||
551 | let statik = self.lower_static(&ast)?; | ||
552 | statik.into() | ||
553 | } | ||
554 | }; | ||
555 | self.add_attrs(id.into(), attrs); | ||
556 | Some(id) | ||
557 | }) | ||
558 | .collect() | ||
559 | }) | ||
560 | } | ||
561 | |||
562 | /// Lowers generics defined on `node` and collects inner items defined within. | ||
563 | fn lower_generic_params_and_inner_items( | ||
564 | &mut self, | ||
565 | owner: GenericsOwner<'_>, | ||
566 | node: &impl ast::TypeParamsOwner, | ||
567 | ) -> GenericParamsId { | ||
568 | // Generics are part of item headers and may contain inner items we need to collect. | ||
569 | if let Some(params) = node.type_param_list() { | ||
570 | self.collect_inner_items(params.syntax()); | ||
571 | } | ||
572 | if let Some(clause) = node.where_clause() { | ||
573 | self.collect_inner_items(clause.syntax()); | ||
574 | } | ||
575 | |||
576 | self.lower_generic_params(owner, node) | ||
577 | } | ||
578 | |||
579 | fn lower_generic_params( | ||
580 | &mut self, | ||
581 | owner: GenericsOwner<'_>, | ||
582 | node: &impl ast::TypeParamsOwner, | ||
583 | ) -> GenericParamsId { | ||
584 | let mut sm = &mut ArenaMap::default(); | ||
585 | let mut generics = GenericParams::default(); | ||
586 | match owner { | ||
587 | GenericsOwner::Function(func) => { | ||
588 | generics.fill(&self.body_ctx, sm, node); | ||
589 | // lower `impl Trait` in arguments | ||
590 | for param in &*func.params { | ||
591 | generics.fill_implicit_impl_trait_args(param); | ||
592 | } | ||
593 | } | ||
594 | GenericsOwner::Struct | ||
595 | | GenericsOwner::Enum | ||
596 | | GenericsOwner::Union | ||
597 | | GenericsOwner::TypeAlias => { | ||
598 | generics.fill(&self.body_ctx, sm, node); | ||
599 | } | ||
600 | GenericsOwner::Trait(trait_def) => { | ||
601 | // traits get the Self type as an implicit first type parameter | ||
602 | let self_param_id = generics.types.alloc(TypeParamData { | ||
603 | name: Some(name![Self]), | ||
604 | default: None, | ||
605 | provenance: TypeParamProvenance::TraitSelf, | ||
606 | }); | ||
607 | sm.insert(self_param_id, Either::Left(trait_def.clone())); | ||
608 | // add super traits as bounds on Self | ||
609 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | ||
610 | let self_param = TypeRef::Path(name![Self].into()); | ||
611 | generics.fill_bounds(&self.body_ctx, trait_def, self_param); | ||
612 | |||
613 | generics.fill(&self.body_ctx, &mut sm, node); | ||
614 | } | ||
615 | GenericsOwner::Impl => { | ||
616 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | ||
617 | // type-parameter, but rather is a type-alias for impl's target | ||
618 | // type, so this is handled by the resolver. | ||
619 | generics.fill(&self.body_ctx, &mut sm, node); | ||
620 | } | ||
621 | } | ||
622 | |||
623 | self.data().generics.alloc(generics) | ||
624 | } | ||
625 | |||
626 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { | ||
627 | match node.type_bound_list() { | ||
628 | Some(bound_list) => { | ||
629 | bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() | ||
630 | } | ||
631 | None => Vec::new(), | ||
632 | } | ||
633 | } | ||
634 | |||
635 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { | ||
636 | let vis = match self.forced_visibility { | ||
637 | Some(vis) => return vis, | ||
638 | None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), | ||
639 | }; | ||
640 | |||
641 | self.data().vis.alloc(vis) | ||
642 | } | ||
643 | |||
644 | fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { | ||
645 | TypeRef::from_ast(&self.body_ctx, type_ref.clone()) | ||
646 | } | ||
647 | fn lower_type_ref_opt(&self, type_ref: Option<ast::TypeRef>) -> TypeRef { | ||
648 | type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) | ||
649 | } | ||
650 | |||
651 | /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. | ||
652 | fn with_inherited_visibility<R>( | ||
653 | &mut self, | ||
654 | vis: RawVisibilityId, | ||
655 | f: impl FnOnce(&mut Self) -> R, | ||
656 | ) -> R { | ||
657 | let old = mem::replace(&mut self.forced_visibility, Some(vis)); | ||
658 | let res = f(self); | ||
659 | self.forced_visibility = old; | ||
660 | res | ||
661 | } | ||
662 | |||
663 | fn next_field_idx(&self) -> Idx<Field> { | ||
664 | Idx::from_raw(RawId::from( | ||
665 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), | ||
666 | )) | ||
667 | } | ||
668 | fn next_variant_idx(&self) -> Idx<Variant> { | ||
669 | Idx::from_raw(RawId::from( | ||
670 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), | ||
671 | )) | ||
672 | } | ||
673 | } | ||
674 | |||
675 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
676 | let path = path![core::future::Future]; | ||
677 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
678 | let mut last = GenericArgs::empty(); | ||
679 | let binding = | ||
680 | AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; | ||
681 | last.bindings.push(binding); | ||
682 | generic_args.push(Some(Arc::new(last))); | ||
683 | |||
684 | Path::from_known_path(path, generic_args) | ||
685 | } | ||
686 | |||
687 | enum GenericsOwner<'a> { | ||
688 | /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument | ||
689 | /// position. | ||
690 | Function(&'a Function), | ||
691 | Struct, | ||
692 | Enum, | ||
693 | Union, | ||
694 | /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. | ||
695 | Trait(&'a ast::TraitDef), | ||
696 | TypeAlias, | ||
697 | Impl, | ||
698 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs new file mode 100644 index 000000000..08559fb92 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/tests.rs | |||
@@ -0,0 +1,435 @@ | |||
1 | use super::{ItemTree, ModItem, ModKind}; | ||
2 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
3 | use hir_expand::{db::AstDatabase, HirFileId, InFile}; | ||
4 | use insta::assert_snapshot; | ||
5 | use ra_db::fixture::WithFixture; | ||
6 | use ra_syntax::{ast, AstNode}; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use std::sync::Arc; | ||
9 | use stdx::format_to; | ||
10 | |||
11 | fn test_inner_items(ra_fixture: &str) { | ||
12 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
13 | let file_id = HirFileId::from(file_id); | ||
14 | let tree = db.item_tree(file_id); | ||
15 | let root = db.parse_or_expand(file_id).unwrap(); | ||
16 | let ast_id_map = db.ast_id_map(file_id); | ||
17 | |||
18 | // Traverse the item tree and collect all module/impl/trait-level items as AST nodes. | ||
19 | let mut outer_items = FxHashSet::default(); | ||
20 | let mut worklist = tree.top_level_items().to_vec(); | ||
21 | while let Some(item) = worklist.pop() { | ||
22 | let node: ast::ModuleItem = match item { | ||
23 | ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
24 | ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
25 | ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
26 | ModItem::Struct(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
27 | ModItem::Union(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
28 | ModItem::Enum(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
29 | ModItem::Const(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
30 | ModItem::Static(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
31 | ModItem::TypeAlias(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
32 | ModItem::Mod(it) => { | ||
33 | if let ModKind::Inline { items } = &tree[it].kind { | ||
34 | worklist.extend(&**items); | ||
35 | } | ||
36 | tree.source(&db, InFile::new(file_id, it)).into() | ||
37 | } | ||
38 | ModItem::Trait(it) => { | ||
39 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
40 | tree.source(&db, InFile::new(file_id, it)).into() | ||
41 | } | ||
42 | ModItem::Impl(it) => { | ||
43 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
44 | tree.source(&db, InFile::new(file_id, it)).into() | ||
45 | } | ||
46 | ModItem::MacroCall(_) => continue, | ||
47 | }; | ||
48 | |||
49 | outer_items.insert(node); | ||
50 | } | ||
51 | |||
52 | // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or | ||
53 | // registered as inner items. | ||
54 | for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { | ||
55 | if outer_items.contains(&item) { | ||
56 | continue; | ||
57 | } | ||
58 | |||
59 | let ast_id = ast_id_map.ast_id(&item); | ||
60 | assert!(!tree.inner_items(ast_id).is_empty()); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | fn item_tree(ra_fixture: &str) -> Arc<ItemTree> { | ||
65 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
66 | db.item_tree(file_id.into()) | ||
67 | } | ||
68 | |||
69 | fn print_item_tree(ra_fixture: &str) -> String { | ||
70 | let tree = item_tree(ra_fixture); | ||
71 | let mut out = String::new(); | ||
72 | |||
73 | format_to!(out, "inner attrs: {:?}\n\n", tree.top_level_attrs()); | ||
74 | format_to!(out, "top-level items:\n"); | ||
75 | for item in tree.top_level_items() { | ||
76 | fmt_mod_item(&mut out, &tree, *item); | ||
77 | format_to!(out, "\n"); | ||
78 | } | ||
79 | |||
80 | if !tree.inner_items.is_empty() { | ||
81 | format_to!(out, "\ninner items:\n\n"); | ||
82 | for (ast_id, items) in &tree.inner_items { | ||
83 | format_to!(out, "for AST {:?}:\n", ast_id); | ||
84 | for inner in items { | ||
85 | fmt_mod_item(&mut out, &tree, *inner); | ||
86 | format_to!(out, "\n\n"); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | out | ||
92 | } | ||
93 | |||
94 | fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { | ||
95 | let attrs = tree.attrs(item.into()); | ||
96 | if !attrs.is_empty() { | ||
97 | format_to!(out, "#[{:?}]\n", attrs); | ||
98 | } | ||
99 | |||
100 | let mut children = String::new(); | ||
101 | match item { | ||
102 | ModItem::ExternCrate(it) => { | ||
103 | format_to!(out, "{:?}", tree[it]); | ||
104 | } | ||
105 | ModItem::Import(it) => { | ||
106 | format_to!(out, "{:?}", tree[it]); | ||
107 | } | ||
108 | ModItem::Function(it) => { | ||
109 | format_to!(out, "{:?}", tree[it]); | ||
110 | } | ||
111 | ModItem::Struct(it) => { | ||
112 | format_to!(out, "{:?}", tree[it]); | ||
113 | } | ||
114 | ModItem::Union(it) => { | ||
115 | format_to!(out, "{:?}", tree[it]); | ||
116 | } | ||
117 | ModItem::Enum(it) => { | ||
118 | format_to!(out, "{:?}", tree[it]); | ||
119 | } | ||
120 | ModItem::Const(it) => { | ||
121 | format_to!(out, "{:?}", tree[it]); | ||
122 | } | ||
123 | ModItem::Static(it) => { | ||
124 | format_to!(out, "{:?}", tree[it]); | ||
125 | } | ||
126 | ModItem::Trait(it) => { | ||
127 | format_to!(out, "{:?}", tree[it]); | ||
128 | for item in &*tree[it].items { | ||
129 | fmt_mod_item(&mut children, tree, ModItem::from(*item)); | ||
130 | format_to!(children, "\n"); | ||
131 | } | ||
132 | } | ||
133 | ModItem::Impl(it) => { | ||
134 | format_to!(out, "{:?}", tree[it]); | ||
135 | for item in &*tree[it].items { | ||
136 | fmt_mod_item(&mut children, tree, ModItem::from(*item)); | ||
137 | format_to!(children, "\n"); | ||
138 | } | ||
139 | } | ||
140 | ModItem::TypeAlias(it) => { | ||
141 | format_to!(out, "{:?}", tree[it]); | ||
142 | } | ||
143 | ModItem::Mod(it) => { | ||
144 | format_to!(out, "{:?}", tree[it]); | ||
145 | match &tree[it].kind { | ||
146 | ModKind::Inline { items } => { | ||
147 | for item in &**items { | ||
148 | fmt_mod_item(&mut children, tree, *item); | ||
149 | format_to!(children, "\n"); | ||
150 | } | ||
151 | } | ||
152 | ModKind::Outline {} => {} | ||
153 | } | ||
154 | } | ||
155 | ModItem::MacroCall(it) => { | ||
156 | format_to!(out, "{:?}", tree[it]); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | for line in children.lines() { | ||
161 | format_to!(out, "\n> {}", line); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn smoke() { | ||
167 | assert_snapshot!(print_item_tree(r" | ||
168 | #![attr] | ||
169 | |||
170 | #[attr_on_use] | ||
171 | use {a, b::*}; | ||
172 | |||
173 | #[ext_crate] | ||
174 | extern crate krate; | ||
175 | |||
176 | #[on_trait] | ||
177 | trait Tr<U> { | ||
178 | #[assoc_ty] | ||
179 | type AssocTy: Tr<()>; | ||
180 | |||
181 | #[assoc_const] | ||
182 | const CONST: u8; | ||
183 | |||
184 | #[assoc_method] | ||
185 | fn method(&self); | ||
186 | |||
187 | #[assoc_dfl_method] | ||
188 | fn dfl_method(&mut self) {} | ||
189 | } | ||
190 | |||
191 | #[struct0] | ||
192 | struct Struct0<T = ()>; | ||
193 | |||
194 | #[struct1] | ||
195 | struct Struct1<T>(#[struct1fld] u8); | ||
196 | |||
197 | #[struct2] | ||
198 | struct Struct2<T> { | ||
199 | #[struct2fld] | ||
200 | fld: (T, ), | ||
201 | } | ||
202 | |||
203 | #[en] | ||
204 | enum En { | ||
205 | #[enum_variant] | ||
206 | Variant { | ||
207 | #[enum_field] | ||
208 | field: u8, | ||
209 | }, | ||
210 | } | ||
211 | |||
212 | #[un] | ||
213 | union Un { | ||
214 | #[union_fld] | ||
215 | fld: u16, | ||
216 | } | ||
217 | "), @r###" | ||
218 | inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } | ||
219 | |||
220 | top-level items: | ||
221 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] | ||
222 | Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
223 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] | ||
224 | Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
225 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] | ||
226 | ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) } | ||
227 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] | ||
228 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) } | ||
229 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] | ||
230 | > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) } | ||
231 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] | ||
232 | > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) } | ||
233 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] | ||
234 | > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) } | ||
235 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] | ||
236 | > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) } | ||
237 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] | ||
238 | Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit } | ||
239 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] | ||
240 | Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::<ra_hir_def::item_tree::Field>(0..1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple } | ||
241 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] | ||
242 | Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(1..2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record } | ||
243 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] | ||
244 | Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::<ra_hir_def::item_tree::Variant>(0..1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) } | ||
245 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] | ||
246 | Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(3..4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) } | ||
247 | "###); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn simple_inner_items() { | ||
252 | let tree = print_item_tree( | ||
253 | r" | ||
254 | impl<T:A> D for Response<T> { | ||
255 | fn foo() { | ||
256 | end(); | ||
257 | fn end<W: Write>() { | ||
258 | let _x: T = loop {}; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | ", | ||
263 | ); | ||
264 | |||
265 | assert_snapshot!(tree, @r###" | ||
266 | inner attrs: Attrs { entries: None } | ||
267 | |||
268 | top-level items: | ||
269 | Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
270 | > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
271 | |||
272 | inner items: | ||
273 | |||
274 | for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2): | ||
275 | Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
276 | |||
277 | "###); | ||
278 | } | ||
279 | |||
280 | #[test] | ||
281 | fn extern_attrs() { | ||
282 | let tree = print_item_tree( | ||
283 | r#" | ||
284 | #[block_attr] | ||
285 | extern "C" { | ||
286 | #[attr_a] | ||
287 | fn a() {} | ||
288 | #[attr_b] | ||
289 | fn b() {} | ||
290 | } | ||
291 | "#, | ||
292 | ); | ||
293 | |||
294 | assert_snapshot!(tree, @r###" | ||
295 | inner attrs: Attrs { entries: None } | ||
296 | |||
297 | top-level items: | ||
298 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] | ||
299 | Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
300 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] | ||
301 | Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
302 | "###); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn trait_attrs() { | ||
307 | let tree = print_item_tree( | ||
308 | r#" | ||
309 | #[trait_attr] | ||
310 | trait Tr { | ||
311 | #[attr_a] | ||
312 | fn a() {} | ||
313 | #[attr_b] | ||
314 | fn b() {} | ||
315 | } | ||
316 | "#, | ||
317 | ); | ||
318 | |||
319 | assert_snapshot!(tree, @r###" | ||
320 | inner attrs: Attrs { entries: None } | ||
321 | |||
322 | top-level items: | ||
323 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] | ||
324 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) } | ||
325 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] | ||
326 | > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
327 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] | ||
328 | > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
329 | "###); | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn impl_attrs() { | ||
334 | let tree = print_item_tree( | ||
335 | r#" | ||
336 | #[impl_attr] | ||
337 | impl Ty { | ||
338 | #[attr_a] | ||
339 | fn a() {} | ||
340 | #[attr_b] | ||
341 | fn b() {} | ||
342 | } | ||
343 | "#, | ||
344 | ); | ||
345 | |||
346 | assert_snapshot!(tree, @r###" | ||
347 | inner attrs: Attrs { entries: None } | ||
348 | |||
349 | top-level items: | ||
350 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] | ||
351 | Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
352 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] | ||
353 | > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
354 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] | ||
355 | > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
356 | "###); | ||
357 | } | ||
358 | |||
359 | #[test] | ||
360 | fn cursed_inner_items() { | ||
361 | test_inner_items( | ||
362 | r" | ||
363 | struct S<T: Trait = [u8; { fn f() {} 0 }]>(T); | ||
364 | |||
365 | enum En { | ||
366 | Var1 { | ||
367 | t: [(); { trait Inner {} 0 }], | ||
368 | }, | ||
369 | |||
370 | Var2([u16; { enum Inner {} 0 }]), | ||
371 | } | ||
372 | |||
373 | type Ty = [En; { struct Inner; 0 }]; | ||
374 | |||
375 | impl En { | ||
376 | fn assoc() { | ||
377 | trait InnerTrait<T = [u8; { fn f() {} }]> {} | ||
378 | struct InnerStruct<T = [u8; { fn f() {} }]> {} | ||
379 | impl<T = [u8; { fn f() {} }]> InnerTrait for InnerStruct {} | ||
380 | } | ||
381 | } | ||
382 | |||
383 | trait Tr<T = [u8; { fn f() {} }]> { | ||
384 | type AssocTy = [u8; { fn f() {} }]; | ||
385 | |||
386 | const AssocConst: [u8; { fn f() {} }]; | ||
387 | } | ||
388 | ", | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn inner_item_attrs() { | ||
394 | let tree = print_item_tree( | ||
395 | r" | ||
396 | fn foo() { | ||
397 | #[on_inner] | ||
398 | fn inner() {} | ||
399 | } | ||
400 | ", | ||
401 | ); | ||
402 | |||
403 | assert_snapshot!(tree, @r###" | ||
404 | inner attrs: Attrs { entries: None } | ||
405 | |||
406 | top-level items: | ||
407 | Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) } | ||
408 | |||
409 | inner items: | ||
410 | |||
411 | for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1): | ||
412 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] | ||
413 | Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
414 | |||
415 | "###); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn assoc_item_macros() { | ||
420 | let tree = print_item_tree( | ||
421 | r" | ||
422 | impl S { | ||
423 | items!(); | ||
424 | } | ||
425 | ", | ||
426 | ); | ||
427 | |||
428 | assert_snapshot!(tree, @r###" | ||
429 | inner attrs: Attrs { entries: None } | ||
430 | |||
431 | top-level items: | ||
432 | Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
433 | > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) } | ||
434 | "###); | ||
435 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index af2a717c9..564434ccc 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -25,6 +25,8 @@ pub mod item_scope; | |||
25 | pub mod dyn_map; | 25 | pub mod dyn_map; |
26 | pub mod keys; | 26 | pub mod keys; |
27 | 27 | ||
28 | pub mod item_tree; | ||
29 | |||
28 | pub mod adt; | 30 | pub mod adt; |
29 | pub mod data; | 31 | pub mod data; |
30 | pub mod generics; | 32 | pub mod generics; |
@@ -48,7 +50,7 @@ pub mod import_map; | |||
48 | #[cfg(test)] | 50 | #[cfg(test)] |
49 | mod test_db; | 51 | mod test_db; |
50 | 52 | ||
51 | use std::hash::Hash; | 53 | use std::hash::{Hash, Hasher}; |
52 | 54 | ||
53 | use hir_expand::{ | 55 | use hir_expand::{ |
54 | ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, | 56 | ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, |
@@ -56,10 +58,13 @@ use hir_expand::{ | |||
56 | }; | 58 | }; |
57 | use ra_arena::Idx; | 59 | use ra_arena::Idx; |
58 | use ra_db::{impl_intern_key, salsa, CrateId}; | 60 | use ra_db::{impl_intern_key, salsa, CrateId}; |
59 | use ra_syntax::{ast, AstNode}; | 61 | use ra_syntax::ast; |
60 | 62 | ||
61 | use crate::body::Expander; | ||
62 | use crate::builtin_type::BuiltinType; | 63 | use crate::builtin_type::BuiltinType; |
64 | use item_tree::{ | ||
65 | Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, | ||
66 | TypeAlias, Union, | ||
67 | }; | ||
63 | 68 | ||
64 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 69 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
65 | pub struct ModuleId { | 70 | pub struct ModuleId { |
@@ -70,16 +75,62 @@ pub struct ModuleId { | |||
70 | /// An ID of a module, **local** to a specific crate | 75 | /// An ID of a module, **local** to a specific crate |
71 | pub type LocalModuleId = Idx<nameres::ModuleData>; | 76 | pub type LocalModuleId = Idx<nameres::ModuleData>; |
72 | 77 | ||
73 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 78 | #[derive(Debug)] |
74 | pub struct ItemLoc<N: AstNode> { | 79 | pub struct ItemLoc<N: ItemTreeNode> { |
75 | pub container: ContainerId, | 80 | pub container: ContainerId, |
76 | pub ast_id: AstId<N>, | 81 | pub id: ItemTreeId<N>, |
82 | } | ||
83 | |||
84 | impl<N: ItemTreeNode> Clone for ItemLoc<N> { | ||
85 | fn clone(&self) -> Self { | ||
86 | Self { container: self.container, id: self.id } | ||
87 | } | ||
77 | } | 88 | } |
78 | 89 | ||
79 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 90 | impl<N: ItemTreeNode> Copy for ItemLoc<N> {} |
80 | pub struct AssocItemLoc<N: AstNode> { | 91 | |
92 | impl<N: ItemTreeNode> PartialEq for ItemLoc<N> { | ||
93 | fn eq(&self, other: &Self) -> bool { | ||
94 | self.container == other.container && self.id == other.id | ||
95 | } | ||
96 | } | ||
97 | |||
98 | impl<N: ItemTreeNode> Eq for ItemLoc<N> {} | ||
99 | |||
100 | impl<N: ItemTreeNode> Hash for ItemLoc<N> { | ||
101 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
102 | self.container.hash(state); | ||
103 | self.id.hash(state); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | #[derive(Debug)] | ||
108 | pub struct AssocItemLoc<N: ItemTreeNode> { | ||
81 | pub container: AssocContainerId, | 109 | pub container: AssocContainerId, |
82 | pub ast_id: AstId<N>, | 110 | pub id: ItemTreeId<N>, |
111 | } | ||
112 | |||
113 | impl<N: ItemTreeNode> Clone for AssocItemLoc<N> { | ||
114 | fn clone(&self) -> Self { | ||
115 | Self { container: self.container, id: self.id } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {} | ||
120 | |||
121 | impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> { | ||
122 | fn eq(&self, other: &Self) -> bool { | ||
123 | self.container == other.container && self.id == other.id | ||
124 | } | ||
125 | } | ||
126 | |||
127 | impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {} | ||
128 | |||
129 | impl<N: ItemTreeNode> Hash for AssocItemLoc<N> { | ||
130 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
131 | self.container.hash(state); | ||
132 | self.id.hash(state); | ||
133 | } | ||
83 | } | 134 | } |
84 | 135 | ||
85 | macro_rules! impl_intern { | 136 | macro_rules! impl_intern { |
@@ -104,22 +155,22 @@ macro_rules! impl_intern { | |||
104 | 155 | ||
105 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
106 | pub struct FunctionId(salsa::InternId); | 157 | pub struct FunctionId(salsa::InternId); |
107 | type FunctionLoc = AssocItemLoc<ast::FnDef>; | 158 | type FunctionLoc = AssocItemLoc<Function>; |
108 | impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); | 159 | impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); |
109 | 160 | ||
110 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 161 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
111 | pub struct StructId(salsa::InternId); | 162 | pub struct StructId(salsa::InternId); |
112 | type StructLoc = ItemLoc<ast::StructDef>; | 163 | type StructLoc = ItemLoc<Struct>; |
113 | impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); | 164 | impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); |
114 | 165 | ||
115 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 166 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
116 | pub struct UnionId(salsa::InternId); | 167 | pub struct UnionId(salsa::InternId); |
117 | pub type UnionLoc = ItemLoc<ast::UnionDef>; | 168 | pub type UnionLoc = ItemLoc<Union>; |
118 | impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); | 169 | impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); |
119 | 170 | ||
120 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 171 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
121 | pub struct EnumId(salsa::InternId); | 172 | pub struct EnumId(salsa::InternId); |
122 | pub type EnumLoc = ItemLoc<ast::EnumDef>; | 173 | pub type EnumLoc = ItemLoc<Enum>; |
123 | impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); | 174 | impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); |
124 | 175 | ||
125 | // FIXME: rename to `VariantId`, only enums can ave variants | 176 | // FIXME: rename to `VariantId`, only enums can ave variants |
@@ -141,27 +192,27 @@ pub type LocalFieldId = Idx<adt::FieldData>; | |||
141 | 192 | ||
142 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
143 | pub struct ConstId(salsa::InternId); | 194 | pub struct ConstId(salsa::InternId); |
144 | type ConstLoc = AssocItemLoc<ast::ConstDef>; | 195 | type ConstLoc = AssocItemLoc<Const>; |
145 | impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); | 196 | impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); |
146 | 197 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 198 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
148 | pub struct StaticId(salsa::InternId); | 199 | pub struct StaticId(salsa::InternId); |
149 | pub type StaticLoc = ItemLoc<ast::StaticDef>; | 200 | pub type StaticLoc = ItemLoc<Static>; |
150 | impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); | 201 | impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); |
151 | 202 | ||
152 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 203 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
153 | pub struct TraitId(salsa::InternId); | 204 | pub struct TraitId(salsa::InternId); |
154 | pub type TraitLoc = ItemLoc<ast::TraitDef>; | 205 | pub type TraitLoc = ItemLoc<Trait>; |
155 | impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); | 206 | impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); |
156 | 207 | ||
157 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 208 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
158 | pub struct TypeAliasId(salsa::InternId); | 209 | pub struct TypeAliasId(salsa::InternId); |
159 | type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>; | 210 | type TypeAliasLoc = AssocItemLoc<TypeAlias>; |
160 | impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); | 211 | impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); |
161 | 212 | ||
162 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | 213 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] |
163 | pub struct ImplId(salsa::InternId); | 214 | pub struct ImplId(salsa::InternId); |
164 | type ImplLoc = ItemLoc<ast::ImplDef>; | 215 | type ImplLoc = ItemLoc<Impl>; |
165 | impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); | 216 | impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); |
166 | 217 | ||
167 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 218 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -365,7 +416,7 @@ impl HasModule for AssocContainerId { | |||
365 | } | 416 | } |
366 | } | 417 | } |
367 | 418 | ||
368 | impl<N: AstNode> HasModule for AssocItemLoc<N> { | 419 | impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> { |
369 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | 420 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { |
370 | self.container.module(db) | 421 | self.container.module(db) |
371 | } | 422 | } |
@@ -392,6 +443,16 @@ impl HasModule for DefWithBodyId { | |||
392 | } | 443 | } |
393 | } | 444 | } |
394 | 445 | ||
446 | impl DefWithBodyId { | ||
447 | pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { | ||
448 | match self { | ||
449 | DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), | ||
450 | DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), | ||
451 | DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
395 | impl HasModule for GenericDefId { | 456 | impl HasModule for GenericDefId { |
396 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | 457 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { |
397 | match self { | 458 | match self { |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 060273db4..b279bdeef 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -47,7 +47,6 @@ | |||
47 | //! path and, upon success, we run macro expansion and "collect module" phase on | 47 | //! path and, upon success, we run macro expansion and "collect module" phase on |
48 | //! the result | 48 | //! the result |
49 | 49 | ||
50 | pub(crate) mod raw; | ||
51 | mod collector; | 50 | mod collector; |
52 | mod mod_resolution; | 51 | mod mod_resolution; |
53 | mod path_resolution; | 52 | mod path_resolution; |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index cbce04315..2ced4f66b 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -4,6 +4,7 @@ | |||
4 | //! resolves imports and expands macros. | 4 | //! resolves imports and expands macros. |
5 | 5 | ||
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | ast_id_map::FileAstId, | ||
7 | builtin_derive::find_builtin_derive, | 8 | builtin_derive::find_builtin_derive, |
8 | builtin_macro::find_builtin_macro, | 9 | builtin_macro::find_builtin_macro, |
9 | name::{name, AsName, Name}, | 10 | name::{name, AsName, Name}, |
@@ -19,13 +20,16 @@ use test_utils::mark; | |||
19 | use crate::{ | 20 | use crate::{ |
20 | attr::Attrs, | 21 | attr::Attrs, |
21 | db::DefDatabase, | 22 | db::DefDatabase, |
23 | item_tree::{ | ||
24 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, | ||
25 | }, | ||
22 | nameres::{ | 26 | nameres::{ |
23 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 27 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
24 | raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, | 28 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, |
25 | }, | 29 | }, |
26 | path::{ImportAlias, ModPath, PathKind}, | 30 | path::{ImportAlias, ModPath, PathKind}, |
27 | per_ns::PerNs, | 31 | per_ns::PerNs, |
28 | visibility::Visibility, | 32 | visibility::{RawVisibility, Visibility}, |
29 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, | 33 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, |
30 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, | 34 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, |
31 | TraitLoc, TypeAliasLoc, UnionLoc, | 35 | TraitLoc, TypeAliasLoc, UnionLoc, |
@@ -102,10 +106,50 @@ impl PartialResolvedImport { | |||
102 | } | 106 | } |
103 | 107 | ||
104 | #[derive(Clone, Debug, Eq, PartialEq)] | 108 | #[derive(Clone, Debug, Eq, PartialEq)] |
109 | struct Import { | ||
110 | pub path: ModPath, | ||
111 | pub alias: Option<ImportAlias>, | ||
112 | pub visibility: RawVisibility, | ||
113 | pub is_glob: bool, | ||
114 | pub is_prelude: bool, | ||
115 | pub is_extern_crate: bool, | ||
116 | pub is_macro_use: bool, | ||
117 | } | ||
118 | |||
119 | impl Import { | ||
120 | fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self { | ||
121 | let it = &tree[id]; | ||
122 | let visibility = &tree[it.visibility]; | ||
123 | Self { | ||
124 | path: it.path.clone(), | ||
125 | alias: it.alias.clone(), | ||
126 | visibility: visibility.clone(), | ||
127 | is_glob: it.is_glob, | ||
128 | is_prelude: it.is_prelude, | ||
129 | is_extern_crate: false, | ||
130 | is_macro_use: false, | ||
131 | } | ||
132 | } | ||
133 | |||
134 | fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self { | ||
135 | let it = &tree[id]; | ||
136 | let visibility = &tree[it.visibility]; | ||
137 | Self { | ||
138 | path: it.path.clone(), | ||
139 | alias: it.alias.clone(), | ||
140 | visibility: visibility.clone(), | ||
141 | is_glob: false, | ||
142 | is_prelude: false, | ||
143 | is_extern_crate: true, | ||
144 | is_macro_use: it.is_macro_use, | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
105 | struct ImportDirective { | 150 | struct ImportDirective { |
106 | module_id: LocalModuleId, | 151 | module_id: LocalModuleId, |
107 | import_id: raw::Import, | 152 | import: Import, |
108 | import: raw::ImportData, | ||
109 | status: PartialResolvedImport, | 153 | status: PartialResolvedImport, |
110 | } | 154 | } |
111 | 155 | ||
@@ -123,6 +167,13 @@ struct DeriveDirective { | |||
123 | ast_id: AstIdWithPath<ast::ModuleItem>, | 167 | ast_id: AstIdWithPath<ast::ModuleItem>, |
124 | } | 168 | } |
125 | 169 | ||
170 | struct DefData<'a> { | ||
171 | id: ModuleDefId, | ||
172 | name: &'a Name, | ||
173 | visibility: &'a RawVisibility, | ||
174 | has_constructor: bool, | ||
175 | } | ||
176 | |||
126 | /// Walks the tree of module recursively | 177 | /// Walks the tree of module recursively |
127 | struct DefCollector<'a> { | 178 | struct DefCollector<'a> { |
128 | db: &'a dyn DefDatabase, | 179 | db: &'a dyn DefDatabase, |
@@ -140,7 +191,7 @@ struct DefCollector<'a> { | |||
140 | impl DefCollector<'_> { | 191 | impl DefCollector<'_> { |
141 | fn collect(&mut self) { | 192 | fn collect(&mut self) { |
142 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | 193 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; |
143 | let raw_items = self.db.raw_items(file_id.into()); | 194 | let item_tree = self.db.item_tree(file_id.into()); |
144 | let module_id = self.def_map.root; | 195 | let module_id = self.def_map.root; |
145 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | 196 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
146 | ModCollector { | 197 | ModCollector { |
@@ -148,10 +199,10 @@ impl DefCollector<'_> { | |||
148 | macro_depth: 0, | 199 | macro_depth: 0, |
149 | module_id, | 200 | module_id, |
150 | file_id: file_id.into(), | 201 | file_id: file_id.into(), |
151 | raw_items: &raw_items, | 202 | item_tree: &item_tree, |
152 | mod_dir: ModDir::root(), | 203 | mod_dir: ModDir::root(), |
153 | } | 204 | } |
154 | .collect(raw_items.items()); | 205 | .collect(item_tree.top_level_items()); |
155 | 206 | ||
156 | // main name resolution fixed-point loop. | 207 | // main name resolution fixed-point loop. |
157 | let mut i = 0; | 208 | let mut i = 0; |
@@ -286,7 +337,7 @@ impl DefCollector<'_> { | |||
286 | fn import_macros_from_extern_crate( | 337 | fn import_macros_from_extern_crate( |
287 | &mut self, | 338 | &mut self, |
288 | current_module_id: LocalModuleId, | 339 | current_module_id: LocalModuleId, |
289 | import: &raw::ImportData, | 340 | import: &item_tree::ExternCrate, |
290 | ) { | 341 | ) { |
291 | log::debug!( | 342 | log::debug!( |
292 | "importing macros from extern crate: {:?} ({:?})", | 343 | "importing macros from extern crate: {:?} ({:?})", |
@@ -352,11 +403,7 @@ impl DefCollector<'_> { | |||
352 | } | 403 | } |
353 | } | 404 | } |
354 | 405 | ||
355 | fn resolve_import( | 406 | fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { |
356 | &self, | ||
357 | module_id: LocalModuleId, | ||
358 | import: &raw::ImportData, | ||
359 | ) -> PartialResolvedImport { | ||
360 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 407 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
361 | if import.is_extern_crate { | 408 | if import.is_extern_crate { |
362 | let res = self.def_map.resolve_name_in_extern_prelude( | 409 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -649,17 +696,17 @@ impl DefCollector<'_> { | |||
649 | depth: usize, | 696 | depth: usize, |
650 | ) { | 697 | ) { |
651 | let file_id: HirFileId = macro_call_id.as_file(); | 698 | let file_id: HirFileId = macro_call_id.as_file(); |
652 | let raw_items = self.db.raw_items(file_id); | 699 | let item_tree = self.db.item_tree(file_id); |
653 | let mod_dir = self.mod_dirs[&module_id].clone(); | 700 | let mod_dir = self.mod_dirs[&module_id].clone(); |
654 | ModCollector { | 701 | ModCollector { |
655 | def_collector: &mut *self, | 702 | def_collector: &mut *self, |
656 | macro_depth: depth, | 703 | macro_depth: depth, |
657 | file_id, | 704 | file_id, |
658 | module_id, | 705 | module_id, |
659 | raw_items: &raw_items, | 706 | item_tree: &item_tree, |
660 | mod_dir, | 707 | mod_dir, |
661 | } | 708 | } |
662 | .collect(raw_items.items()); | 709 | .collect(item_tree.top_level_items()); |
663 | } | 710 | } |
664 | 711 | ||
665 | fn finish(self) -> CrateDefMap { | 712 | fn finish(self) -> CrateDefMap { |
@@ -673,12 +720,12 @@ struct ModCollector<'a, 'b> { | |||
673 | macro_depth: usize, | 720 | macro_depth: usize, |
674 | module_id: LocalModuleId, | 721 | module_id: LocalModuleId, |
675 | file_id: HirFileId, | 722 | file_id: HirFileId, |
676 | raw_items: &'a raw::RawItems, | 723 | item_tree: &'a ItemTree, |
677 | mod_dir: ModDir, | 724 | mod_dir: ModDir, |
678 | } | 725 | } |
679 | 726 | ||
680 | impl ModCollector<'_, '_> { | 727 | impl ModCollector<'_, '_> { |
681 | fn collect(&mut self, items: &[raw::RawItem]) { | 728 | fn collect(&mut self, items: &[ModItem]) { |
682 | // Note: don't assert that inserted value is fresh: it's simply not true | 729 | // Note: don't assert that inserted value is fresh: it's simply not true |
683 | // for macros. | 730 | // for macros. |
684 | self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); | 731 | self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); |
@@ -695,64 +742,204 @@ impl ModCollector<'_, '_> { | |||
695 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 742 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
696 | // any other items. | 743 | // any other items. |
697 | for item in items { | 744 | for item in items { |
698 | if self.is_cfg_enabled(&item.attrs) { | 745 | if self.is_cfg_enabled(self.item_tree.attrs((*item).into())) { |
699 | if let raw::RawItemKind::Import(import_id) = item.kind { | 746 | if let ModItem::ExternCrate(id) = item { |
700 | let import = self.raw_items[import_id].clone(); | 747 | let import = self.item_tree[*id].clone(); |
701 | if import.is_extern_crate && import.is_macro_use { | 748 | if import.is_macro_use { |
702 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | 749 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); |
703 | } | 750 | } |
704 | } | 751 | } |
705 | } | 752 | } |
706 | } | 753 | } |
707 | 754 | ||
708 | for item in items { | 755 | for &item in items { |
709 | if self.is_cfg_enabled(&item.attrs) { | 756 | let attrs = self.item_tree.attrs(item.into()); |
710 | match item.kind { | 757 | if self.is_cfg_enabled(attrs) { |
711 | raw::RawItemKind::Module(m) => { | 758 | let module = |
712 | self.collect_module(&self.raw_items[m], &item.attrs) | 759 | ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; |
713 | } | 760 | let container = ContainerId::ModuleId(module); |
714 | raw::RawItemKind::Import(import_id) => { | 761 | |
762 | let mut def = None; | ||
763 | match item { | ||
764 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs), | ||
765 | ModItem::Import(import_id) => { | ||
715 | self.def_collector.unresolved_imports.push(ImportDirective { | 766 | self.def_collector.unresolved_imports.push(ImportDirective { |
716 | module_id: self.module_id, | 767 | module_id: self.module_id, |
717 | import_id, | 768 | import: Import::from_use(&self.item_tree, import_id), |
718 | import: self.raw_items[import_id].clone(), | ||
719 | status: PartialResolvedImport::Unresolved, | 769 | status: PartialResolvedImport::Unresolved, |
720 | }) | 770 | }) |
721 | } | 771 | } |
722 | raw::RawItemKind::Def(def) => { | 772 | ModItem::ExternCrate(import_id) => { |
723 | self.define_def(&self.raw_items[def], &item.attrs) | 773 | self.def_collector.unresolved_imports.push(ImportDirective { |
774 | module_id: self.module_id, | ||
775 | import: Import::from_extern_crate(&self.item_tree, import_id), | ||
776 | status: PartialResolvedImport::Unresolved, | ||
777 | }) | ||
724 | } | 778 | } |
725 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 779 | ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]), |
726 | raw::RawItemKind::Impl(imp) => { | 780 | ModItem::Impl(imp) => { |
727 | let module = ModuleId { | 781 | let module = ModuleId { |
728 | krate: self.def_collector.def_map.krate, | 782 | krate: self.def_collector.def_map.krate, |
729 | local_id: self.module_id, | 783 | local_id: self.module_id, |
730 | }; | 784 | }; |
731 | let container = ContainerId::ModuleId(module); | 785 | let container = ContainerId::ModuleId(module); |
732 | let ast_id = self.raw_items[imp].ast_id; | 786 | let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } |
733 | let impl_id = | 787 | .intern(self.def_collector.db); |
734 | ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
735 | .intern(self.def_collector.db); | ||
736 | self.def_collector.def_map.modules[self.module_id] | 788 | self.def_collector.def_map.modules[self.module_id] |
737 | .scope | 789 | .scope |
738 | .define_impl(impl_id) | 790 | .define_impl(impl_id) |
739 | } | 791 | } |
792 | ModItem::Function(id) => { | ||
793 | let func = &self.item_tree[id]; | ||
794 | def = Some(DefData { | ||
795 | id: FunctionLoc { | ||
796 | container: container.into(), | ||
797 | id: ItemTreeId::new(self.file_id, id), | ||
798 | } | ||
799 | .intern(self.def_collector.db) | ||
800 | .into(), | ||
801 | name: &func.name, | ||
802 | visibility: &self.item_tree[func.visibility], | ||
803 | has_constructor: false, | ||
804 | }); | ||
805 | } | ||
806 | ModItem::Struct(id) => { | ||
807 | let it = &self.item_tree[id]; | ||
808 | |||
809 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
810 | // in which case we don't add the invocation, just a single attribute | ||
811 | // macro invocation | ||
812 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
813 | |||
814 | def = Some(DefData { | ||
815 | id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
816 | .intern(self.def_collector.db) | ||
817 | .into(), | ||
818 | name: &it.name, | ||
819 | visibility: &self.item_tree[it.visibility], | ||
820 | has_constructor: it.kind != StructDefKind::Record, | ||
821 | }); | ||
822 | } | ||
823 | ModItem::Union(id) => { | ||
824 | let it = &self.item_tree[id]; | ||
825 | |||
826 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
827 | // in which case we don't add the invocation, just a single attribute | ||
828 | // macro invocation | ||
829 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
830 | |||
831 | def = Some(DefData { | ||
832 | id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
833 | .intern(self.def_collector.db) | ||
834 | .into(), | ||
835 | name: &it.name, | ||
836 | visibility: &self.item_tree[it.visibility], | ||
837 | has_constructor: false, | ||
838 | }); | ||
839 | } | ||
840 | ModItem::Enum(id) => { | ||
841 | let it = &self.item_tree[id]; | ||
842 | |||
843 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
844 | // in which case we don't add the invocation, just a single attribute | ||
845 | // macro invocation | ||
846 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
847 | |||
848 | def = Some(DefData { | ||
849 | id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
850 | .intern(self.def_collector.db) | ||
851 | .into(), | ||
852 | name: &it.name, | ||
853 | visibility: &self.item_tree[it.visibility], | ||
854 | has_constructor: false, | ||
855 | }); | ||
856 | } | ||
857 | ModItem::Const(id) => { | ||
858 | let it = &self.item_tree[id]; | ||
859 | |||
860 | if let Some(name) = &it.name { | ||
861 | def = Some(DefData { | ||
862 | id: ConstLoc { | ||
863 | container: container.into(), | ||
864 | id: ItemTreeId::new(self.file_id, id), | ||
865 | } | ||
866 | .intern(self.def_collector.db) | ||
867 | .into(), | ||
868 | name, | ||
869 | visibility: &self.item_tree[it.visibility], | ||
870 | has_constructor: false, | ||
871 | }); | ||
872 | } | ||
873 | } | ||
874 | ModItem::Static(id) => { | ||
875 | let it = &self.item_tree[id]; | ||
876 | |||
877 | def = Some(DefData { | ||
878 | id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
879 | .intern(self.def_collector.db) | ||
880 | .into(), | ||
881 | name: &it.name, | ||
882 | visibility: &self.item_tree[it.visibility], | ||
883 | has_constructor: false, | ||
884 | }); | ||
885 | } | ||
886 | ModItem::Trait(id) => { | ||
887 | let it = &self.item_tree[id]; | ||
888 | |||
889 | def = Some(DefData { | ||
890 | id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
891 | .intern(self.def_collector.db) | ||
892 | .into(), | ||
893 | name: &it.name, | ||
894 | visibility: &self.item_tree[it.visibility], | ||
895 | has_constructor: false, | ||
896 | }); | ||
897 | } | ||
898 | ModItem::TypeAlias(id) => { | ||
899 | let it = &self.item_tree[id]; | ||
900 | |||
901 | def = Some(DefData { | ||
902 | id: TypeAliasLoc { | ||
903 | container: container.into(), | ||
904 | id: ItemTreeId::new(self.file_id, id), | ||
905 | } | ||
906 | .intern(self.def_collector.db) | ||
907 | .into(), | ||
908 | name: &it.name, | ||
909 | visibility: &self.item_tree[it.visibility], | ||
910 | has_constructor: false, | ||
911 | }); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | if let Some(DefData { id, name, visibility, has_constructor }) = def { | ||
916 | self.def_collector.def_map.modules[self.module_id].scope.define_def(id); | ||
917 | let vis = self | ||
918 | .def_collector | ||
919 | .def_map | ||
920 | .resolve_visibility(self.def_collector.db, self.module_id, visibility) | ||
921 | .unwrap_or(Visibility::Public); | ||
922 | self.def_collector.update( | ||
923 | self.module_id, | ||
924 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], | ||
925 | vis, | ||
926 | ) | ||
740 | } | 927 | } |
741 | } | 928 | } |
742 | } | 929 | } |
743 | } | 930 | } |
744 | 931 | ||
745 | fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { | 932 | fn collect_module(&mut self, module: &Mod, attrs: &Attrs) { |
746 | let path_attr = attrs.by_key("path").string_value(); | 933 | let path_attr = attrs.by_key("path").string_value(); |
747 | let is_macro_use = attrs.by_key("macro_use").exists(); | 934 | let is_macro_use = attrs.by_key("macro_use").exists(); |
748 | match module { | 935 | match &module.kind { |
749 | // inline module, just recurse | 936 | // inline module, just recurse |
750 | raw::ModuleData::Definition { name, visibility, items, ast_id } => { | 937 | ModKind::Inline { items } => { |
751 | let module_id = self.push_child_module( | 938 | let module_id = self.push_child_module( |
752 | name.clone(), | 939 | module.name.clone(), |
753 | AstId::new(self.file_id, *ast_id), | 940 | AstId::new(self.file_id, module.ast_id), |
754 | None, | 941 | None, |
755 | &visibility, | 942 | &self.item_tree[module.visibility], |
756 | ); | 943 | ); |
757 | 944 | ||
758 | ModCollector { | 945 | ModCollector { |
@@ -760,8 +947,8 @@ impl ModCollector<'_, '_> { | |||
760 | macro_depth: self.macro_depth, | 947 | macro_depth: self.macro_depth, |
761 | module_id, | 948 | module_id, |
762 | file_id: self.file_id, | 949 | file_id: self.file_id, |
763 | raw_items: self.raw_items, | 950 | item_tree: self.item_tree, |
764 | mod_dir: self.mod_dir.descend_into_definition(name, path_attr), | 951 | mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr), |
765 | } | 952 | } |
766 | .collect(&*items); | 953 | .collect(&*items); |
767 | if is_macro_use { | 954 | if is_macro_use { |
@@ -769,31 +956,31 @@ impl ModCollector<'_, '_> { | |||
769 | } | 956 | } |
770 | } | 957 | } |
771 | // out of line module, resolve, parse and recurse | 958 | // out of line module, resolve, parse and recurse |
772 | raw::ModuleData::Declaration { name, visibility, ast_id } => { | 959 | ModKind::Outline {} => { |
773 | let ast_id = AstId::new(self.file_id, *ast_id); | 960 | let ast_id = AstId::new(self.file_id, module.ast_id); |
774 | match self.mod_dir.resolve_declaration( | 961 | match self.mod_dir.resolve_declaration( |
775 | self.def_collector.db, | 962 | self.def_collector.db, |
776 | self.file_id, | 963 | self.file_id, |
777 | name, | 964 | &module.name, |
778 | path_attr, | 965 | path_attr, |
779 | ) { | 966 | ) { |
780 | Ok((file_id, is_mod_rs, mod_dir)) => { | 967 | Ok((file_id, is_mod_rs, mod_dir)) => { |
781 | let module_id = self.push_child_module( | 968 | let module_id = self.push_child_module( |
782 | name.clone(), | 969 | module.name.clone(), |
783 | ast_id, | 970 | ast_id, |
784 | Some((file_id, is_mod_rs)), | 971 | Some((file_id, is_mod_rs)), |
785 | &visibility, | 972 | &self.item_tree[module.visibility], |
786 | ); | 973 | ); |
787 | let raw_items = self.def_collector.db.raw_items(file_id.into()); | 974 | let item_tree = self.def_collector.db.item_tree(file_id.into()); |
788 | ModCollector { | 975 | ModCollector { |
789 | def_collector: &mut *self.def_collector, | 976 | def_collector: &mut *self.def_collector, |
790 | macro_depth: self.macro_depth, | 977 | macro_depth: self.macro_depth, |
791 | module_id, | 978 | module_id, |
792 | file_id: file_id.into(), | 979 | file_id: file_id.into(), |
793 | raw_items: &raw_items, | 980 | item_tree: &item_tree, |
794 | mod_dir, | 981 | mod_dir, |
795 | } | 982 | } |
796 | .collect(raw_items.items()); | 983 | .collect(item_tree.top_level_items()); |
797 | if is_macro_use { | 984 | if is_macro_use { |
798 | self.import_all_legacy_macros(module_id); | 985 | self.import_all_legacy_macros(module_id); |
799 | } | 986 | } |
@@ -842,77 +1029,7 @@ impl ModCollector<'_, '_> { | |||
842 | res | 1029 | res |
843 | } | 1030 | } |
844 | 1031 | ||
845 | fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { | 1032 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) { |
846 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | ||
847 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
848 | // in which case we don't add the invocation, just a single attribute | ||
849 | // macro invocation | ||
850 | self.collect_derives(attrs, def); | ||
851 | |||
852 | let name = def.name.clone(); | ||
853 | let container = ContainerId::ModuleId(module); | ||
854 | let vis = &def.visibility; | ||
855 | let mut has_constructor = false; | ||
856 | |||
857 | let def: ModuleDefId = match def.kind { | ||
858 | raw::DefKind::Function(ast_id) => FunctionLoc { | ||
859 | container: container.into(), | ||
860 | ast_id: AstId::new(self.file_id, ast_id), | ||
861 | } | ||
862 | .intern(self.def_collector.db) | ||
863 | .into(), | ||
864 | raw::DefKind::Struct(ast_id, mode) => { | ||
865 | has_constructor = mode != raw::StructDefKind::Record; | ||
866 | StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
867 | .intern(self.def_collector.db) | ||
868 | .into() | ||
869 | } | ||
870 | raw::DefKind::Union(ast_id) => { | ||
871 | UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
872 | .intern(self.def_collector.db) | ||
873 | .into() | ||
874 | } | ||
875 | raw::DefKind::Enum(ast_id) => { | ||
876 | EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
877 | .intern(self.def_collector.db) | ||
878 | .into() | ||
879 | } | ||
880 | raw::DefKind::Const(ast_id) => { | ||
881 | ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) } | ||
882 | .intern(self.def_collector.db) | ||
883 | .into() | ||
884 | } | ||
885 | raw::DefKind::Static(ast_id) => { | ||
886 | StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
887 | .intern(self.def_collector.db) | ||
888 | .into() | ||
889 | } | ||
890 | raw::DefKind::Trait(ast_id) => { | ||
891 | TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
892 | .intern(self.def_collector.db) | ||
893 | .into() | ||
894 | } | ||
895 | raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc { | ||
896 | container: container.into(), | ||
897 | ast_id: AstId::new(self.file_id, ast_id), | ||
898 | } | ||
899 | .intern(self.def_collector.db) | ||
900 | .into(), | ||
901 | }; | ||
902 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | ||
903 | let vis = self | ||
904 | .def_collector | ||
905 | .def_map | ||
906 | .resolve_visibility(self.def_collector.db, self.module_id, vis) | ||
907 | .unwrap_or(Visibility::Public); | ||
908 | self.def_collector.update( | ||
909 | self.module_id, | ||
910 | &[(name, PerNs::from_def(def, vis, has_constructor))], | ||
911 | vis, | ||
912 | ) | ||
913 | } | ||
914 | |||
915 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { | ||
916 | for derive_subtree in attrs.by_key("derive").tt_values() { | 1033 | for derive_subtree in attrs.by_key("derive").tt_values() { |
917 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | 1034 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree |
918 | for tt in &derive_subtree.token_trees { | 1035 | for tt in &derive_subtree.token_trees { |
@@ -923,7 +1040,7 @@ impl ModCollector<'_, '_> { | |||
923 | }; | 1040 | }; |
924 | let path = ModPath::from_tt_ident(ident); | 1041 | let path = ModPath::from_tt_ident(ident); |
925 | 1042 | ||
926 | let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path); | 1043 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); |
927 | self.def_collector | 1044 | self.def_collector |
928 | .unexpanded_attribute_macros | 1045 | .unexpanded_attribute_macros |
929 | .push(DeriveDirective { module_id: self.module_id, ast_id }); | 1046 | .push(DeriveDirective { module_id: self.module_id, ast_id }); |
@@ -931,11 +1048,11 @@ impl ModCollector<'_, '_> { | |||
931 | } | 1048 | } |
932 | } | 1049 | } |
933 | 1050 | ||
934 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 1051 | fn collect_macro(&mut self, mac: &MacroCall) { |
935 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1052 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); |
936 | 1053 | ||
937 | // Case 0: builtin macros | 1054 | // Case 0: builtin macros |
938 | if mac.builtin { | 1055 | if mac.is_builtin { |
939 | if let Some(name) = &mac.name { | 1056 | if let Some(name) = &mac.name { |
940 | let krate = self.def_collector.def_map.krate; | 1057 | let krate = self.def_collector.def_map.krate; |
941 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { | 1058 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { |
@@ -943,7 +1060,7 @@ impl ModCollector<'_, '_> { | |||
943 | self.module_id, | 1060 | self.module_id, |
944 | name.clone(), | 1061 | name.clone(), |
945 | macro_id, | 1062 | macro_id, |
946 | mac.export, | 1063 | mac.is_export, |
947 | ); | 1064 | ); |
948 | return; | 1065 | return; |
949 | } | 1066 | } |
@@ -957,9 +1074,14 @@ impl ModCollector<'_, '_> { | |||
957 | ast_id: Some(ast_id.ast_id), | 1074 | ast_id: Some(ast_id.ast_id), |
958 | krate: Some(self.def_collector.def_map.krate), | 1075 | krate: Some(self.def_collector.def_map.krate), |
959 | kind: MacroDefKind::Declarative, | 1076 | kind: MacroDefKind::Declarative, |
960 | local_inner: mac.local_inner, | 1077 | local_inner: mac.is_local_inner, |
961 | }; | 1078 | }; |
962 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); | 1079 | self.def_collector.define_macro( |
1080 | self.module_id, | ||
1081 | name.clone(), | ||
1082 | macro_id, | ||
1083 | mac.is_export, | ||
1084 | ); | ||
963 | } | 1085 | } |
964 | return; | 1086 | return; |
965 | } | 1087 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs deleted file mode 100644 index f44baa579..000000000 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ /dev/null | |||
@@ -1,482 +0,0 @@ | |||
1 | //! Lowers syntax tree of a rust file into a raw representation of containing | ||
2 | //! items, *without* attaching them to a module structure. | ||
3 | //! | ||
4 | //! That is, raw items don't have semantics, just as syntax, but, unlike syntax, | ||
5 | //! they don't change with trivial source code edits, making them a great tool | ||
6 | //! for building salsa recomputation firewalls. | ||
7 | |||
8 | use std::{ops::Index, sync::Arc}; | ||
9 | |||
10 | use hir_expand::{ | ||
11 | ast_id_map::AstIdMap, | ||
12 | hygiene::Hygiene, | ||
13 | name::{AsName, Name}, | ||
14 | }; | ||
15 | use ra_arena::{Arena, Idx}; | ||
16 | use ra_prof::profile; | ||
17 | use ra_syntax::{ | ||
18 | ast::{self, AttrsOwner, NameOwner, VisibilityOwner}, | ||
19 | AstNode, | ||
20 | }; | ||
21 | use test_utils::mark; | ||
22 | |||
23 | use crate::{ | ||
24 | attr::Attrs, | ||
25 | db::DefDatabase, | ||
26 | path::{ImportAlias, ModPath}, | ||
27 | visibility::RawVisibility, | ||
28 | FileAstId, HirFileId, InFile, | ||
29 | }; | ||
30 | |||
31 | /// `RawItems` is a set of top-level items in a file (except for impls). | ||
32 | /// | ||
33 | /// It is the input to name resolution algorithm. `RawItems` are not invalidated | ||
34 | /// on most edits. | ||
35 | #[derive(Debug, Default, PartialEq, Eq)] | ||
36 | pub struct RawItems { | ||
37 | modules: Arena<ModuleData>, | ||
38 | imports: Arena<ImportData>, | ||
39 | defs: Arena<DefData>, | ||
40 | macros: Arena<MacroData>, | ||
41 | impls: Arena<ImplData>, | ||
42 | /// items for top-level module | ||
43 | items: Vec<RawItem>, | ||
44 | } | ||
45 | |||
46 | impl RawItems { | ||
47 | pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<RawItems> { | ||
48 | let _p = profile("raw_items_query"); | ||
49 | let mut collector = RawItemsCollector { | ||
50 | raw_items: RawItems::default(), | ||
51 | source_ast_id_map: db.ast_id_map(file_id), | ||
52 | file_id, | ||
53 | hygiene: Hygiene::new(db.upcast(), file_id), | ||
54 | }; | ||
55 | if let Some(node) = db.parse_or_expand(file_id) { | ||
56 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { | ||
57 | collector.process_module(None, source_file); | ||
58 | } else if let Some(item_list) = ast::MacroItems::cast(node) { | ||
59 | collector.process_module(None, item_list); | ||
60 | } | ||
61 | } | ||
62 | let raw_items = collector.raw_items; | ||
63 | Arc::new(raw_items) | ||
64 | } | ||
65 | |||
66 | pub(super) fn items(&self) -> &[RawItem] { | ||
67 | &self.items | ||
68 | } | ||
69 | } | ||
70 | |||
71 | impl Index<Idx<ModuleData>> for RawItems { | ||
72 | type Output = ModuleData; | ||
73 | fn index(&self, idx: Idx<ModuleData>) -> &ModuleData { | ||
74 | &self.modules[idx] | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl Index<Import> for RawItems { | ||
79 | type Output = ImportData; | ||
80 | fn index(&self, idx: Import) -> &ImportData { | ||
81 | &self.imports[idx] | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl Index<Idx<DefData>> for RawItems { | ||
86 | type Output = DefData; | ||
87 | fn index(&self, idx: Idx<DefData>) -> &DefData { | ||
88 | &self.defs[idx] | ||
89 | } | ||
90 | } | ||
91 | |||
92 | impl Index<Idx<MacroData>> for RawItems { | ||
93 | type Output = MacroData; | ||
94 | fn index(&self, idx: Idx<MacroData>) -> &MacroData { | ||
95 | &self.macros[idx] | ||
96 | } | ||
97 | } | ||
98 | |||
99 | impl Index<Idx<ImplData>> for RawItems { | ||
100 | type Output = ImplData; | ||
101 | fn index(&self, idx: Idx<ImplData>) -> &ImplData { | ||
102 | &self.impls[idx] | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
107 | pub(super) struct RawItem { | ||
108 | pub(super) attrs: Attrs, | ||
109 | pub(super) kind: RawItemKind, | ||
110 | } | ||
111 | |||
112 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
113 | pub(super) enum RawItemKind { | ||
114 | Module(Idx<ModuleData>), | ||
115 | Import(Import), | ||
116 | Def(Idx<DefData>), | ||
117 | Macro(Idx<MacroData>), | ||
118 | Impl(Idx<ImplData>), | ||
119 | } | ||
120 | |||
121 | #[derive(Debug, PartialEq, Eq)] | ||
122 | pub(super) enum ModuleData { | ||
123 | Declaration { | ||
124 | name: Name, | ||
125 | visibility: RawVisibility, | ||
126 | ast_id: FileAstId<ast::Module>, | ||
127 | }, | ||
128 | Definition { | ||
129 | name: Name, | ||
130 | visibility: RawVisibility, | ||
131 | ast_id: FileAstId<ast::Module>, | ||
132 | items: Vec<RawItem>, | ||
133 | }, | ||
134 | } | ||
135 | |||
136 | pub(crate) type Import = Idx<ImportData>; | ||
137 | |||
138 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
139 | pub struct ImportData { | ||
140 | pub(super) path: ModPath, | ||
141 | pub(super) alias: Option<ImportAlias>, | ||
142 | pub(super) is_glob: bool, | ||
143 | pub(super) is_prelude: bool, | ||
144 | pub(super) is_extern_crate: bool, | ||
145 | pub(super) is_macro_use: bool, | ||
146 | pub(super) visibility: RawVisibility, | ||
147 | } | ||
148 | |||
149 | // type Def = Idx<DefData>; | ||
150 | |||
151 | #[derive(Debug, PartialEq, Eq)] | ||
152 | pub(super) struct DefData { | ||
153 | pub(super) name: Name, | ||
154 | pub(super) kind: DefKind, | ||
155 | pub(super) visibility: RawVisibility, | ||
156 | } | ||
157 | |||
158 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
159 | pub(super) enum StructDefKind { | ||
160 | Record, | ||
161 | Tuple, | ||
162 | Unit, | ||
163 | } | ||
164 | |||
165 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
166 | pub(super) enum DefKind { | ||
167 | Function(FileAstId<ast::FnDef>), | ||
168 | Struct(FileAstId<ast::StructDef>, StructDefKind), | ||
169 | Union(FileAstId<ast::UnionDef>), | ||
170 | Enum(FileAstId<ast::EnumDef>), | ||
171 | Const(FileAstId<ast::ConstDef>), | ||
172 | Static(FileAstId<ast::StaticDef>), | ||
173 | Trait(FileAstId<ast::TraitDef>), | ||
174 | TypeAlias(FileAstId<ast::TypeAliasDef>), | ||
175 | } | ||
176 | |||
177 | impl DefKind { | ||
178 | pub fn ast_id(self) -> FileAstId<ast::ModuleItem> { | ||
179 | match self { | ||
180 | DefKind::Function(it) => it.upcast(), | ||
181 | DefKind::Struct(it, _) => it.upcast(), | ||
182 | DefKind::Union(it) => it.upcast(), | ||
183 | DefKind::Enum(it) => it.upcast(), | ||
184 | DefKind::Const(it) => it.upcast(), | ||
185 | DefKind::Static(it) => it.upcast(), | ||
186 | DefKind::Trait(it) => it.upcast(), | ||
187 | DefKind::TypeAlias(it) => it.upcast(), | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | #[derive(Debug, PartialEq, Eq)] | ||
193 | pub(super) struct MacroData { | ||
194 | pub(super) ast_id: FileAstId<ast::MacroCall>, | ||
195 | pub(super) path: ModPath, | ||
196 | pub(super) name: Option<Name>, | ||
197 | pub(super) export: bool, | ||
198 | pub(super) local_inner: bool, | ||
199 | pub(super) builtin: bool, | ||
200 | } | ||
201 | |||
202 | #[derive(Debug, PartialEq, Eq)] | ||
203 | pub(super) struct ImplData { | ||
204 | pub(super) ast_id: FileAstId<ast::ImplDef>, | ||
205 | } | ||
206 | |||
207 | struct RawItemsCollector { | ||
208 | raw_items: RawItems, | ||
209 | source_ast_id_map: Arc<AstIdMap>, | ||
210 | file_id: HirFileId, | ||
211 | hygiene: Hygiene, | ||
212 | } | ||
213 | |||
214 | impl RawItemsCollector { | ||
215 | fn process_module( | ||
216 | &mut self, | ||
217 | current_module: Option<Idx<ModuleData>>, | ||
218 | body: impl ast::ModuleItemOwner, | ||
219 | ) { | ||
220 | for item in body.items() { | ||
221 | self.add_item(current_module, item) | ||
222 | } | ||
223 | } | ||
224 | |||
225 | fn add_item(&mut self, current_module: Option<Idx<ModuleData>>, item: ast::ModuleItem) { | ||
226 | let attrs = self.parse_attrs(&item); | ||
227 | let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); | ||
228 | let (kind, name) = match item { | ||
229 | ast::ModuleItem::Module(module) => { | ||
230 | self.add_module(current_module, module); | ||
231 | return; | ||
232 | } | ||
233 | ast::ModuleItem::UseItem(use_item) => { | ||
234 | self.add_use_item(current_module, use_item); | ||
235 | return; | ||
236 | } | ||
237 | ast::ModuleItem::ExternCrateItem(extern_crate) => { | ||
238 | self.add_extern_crate_item(current_module, extern_crate); | ||
239 | return; | ||
240 | } | ||
241 | ast::ModuleItem::ImplDef(it) => { | ||
242 | self.add_impl(current_module, it); | ||
243 | return; | ||
244 | } | ||
245 | ast::ModuleItem::StructDef(it) => { | ||
246 | let kind = match it.kind() { | ||
247 | ast::StructKind::Record(_) => StructDefKind::Record, | ||
248 | ast::StructKind::Tuple(_) => StructDefKind::Tuple, | ||
249 | ast::StructKind::Unit => StructDefKind::Unit, | ||
250 | }; | ||
251 | let id = self.source_ast_id_map.ast_id(&it); | ||
252 | let name = it.name(); | ||
253 | (DefKind::Struct(id, kind), name) | ||
254 | } | ||
255 | ast::ModuleItem::UnionDef(it) => { | ||
256 | let id = self.source_ast_id_map.ast_id(&it); | ||
257 | let name = it.name(); | ||
258 | (DefKind::Union(id), name) | ||
259 | } | ||
260 | ast::ModuleItem::EnumDef(it) => { | ||
261 | (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
262 | } | ||
263 | ast::ModuleItem::FnDef(it) => { | ||
264 | (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
265 | } | ||
266 | ast::ModuleItem::TraitDef(it) => { | ||
267 | (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
268 | } | ||
269 | ast::ModuleItem::TypeAliasDef(it) => { | ||
270 | (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
271 | } | ||
272 | ast::ModuleItem::ConstDef(it) => { | ||
273 | (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
274 | } | ||
275 | ast::ModuleItem::StaticDef(it) => { | ||
276 | (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
277 | } | ||
278 | ast::ModuleItem::MacroCall(it) => { | ||
279 | self.add_macro(current_module, it); | ||
280 | return; | ||
281 | } | ||
282 | ast::ModuleItem::ExternBlock(it) => { | ||
283 | self.add_extern_block(current_module, it); | ||
284 | return; | ||
285 | } | ||
286 | }; | ||
287 | if let Some(name) = name { | ||
288 | let name = name.as_name(); | ||
289 | let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); | ||
290 | self.push_item(current_module, attrs, RawItemKind::Def(def)); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | fn add_extern_block( | ||
295 | &mut self, | ||
296 | current_module: Option<Idx<ModuleData>>, | ||
297 | block: ast::ExternBlock, | ||
298 | ) { | ||
299 | if let Some(items) = block.extern_item_list() { | ||
300 | for item in items.extern_items() { | ||
301 | let attrs = self.parse_attrs(&item); | ||
302 | let visibility = | ||
303 | RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); | ||
304 | let (kind, name) = match item { | ||
305 | ast::ExternItem::FnDef(it) => { | ||
306 | (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
307 | } | ||
308 | ast::ExternItem::StaticDef(it) => { | ||
309 | (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
310 | } | ||
311 | }; | ||
312 | |||
313 | if let Some(name) = name { | ||
314 | let name = name.as_name(); | ||
315 | let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); | ||
316 | self.push_item(current_module, attrs, RawItemKind::Def(def)); | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) { | ||
323 | let name = match module.name() { | ||
324 | Some(it) => it.as_name(), | ||
325 | None => return, | ||
326 | }; | ||
327 | let attrs = self.parse_attrs(&module); | ||
328 | let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); | ||
329 | |||
330 | let ast_id = self.source_ast_id_map.ast_id(&module); | ||
331 | if module.semicolon_token().is_some() { | ||
332 | let item = | ||
333 | self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); | ||
334 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if let Some(item_list) = module.item_list() { | ||
339 | let item = self.raw_items.modules.alloc(ModuleData::Definition { | ||
340 | name, | ||
341 | visibility, | ||
342 | ast_id, | ||
343 | items: Vec::new(), | ||
344 | }); | ||
345 | self.process_module(Some(item), item_list); | ||
346 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
347 | return; | ||
348 | } | ||
349 | mark::hit!(name_res_works_for_broken_modules); | ||
350 | } | ||
351 | |||
352 | fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) { | ||
353 | // FIXME: cfg_attr | ||
354 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
355 | let attrs = self.parse_attrs(&use_item); | ||
356 | let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene); | ||
357 | |||
358 | let mut buf = Vec::new(); | ||
359 | ModPath::expand_use_item( | ||
360 | InFile { value: use_item, file_id: self.file_id }, | ||
361 | &self.hygiene, | ||
362 | |path, _use_tree, is_glob, alias| { | ||
363 | let import_data = ImportData { | ||
364 | path, | ||
365 | alias, | ||
366 | is_glob, | ||
367 | is_prelude, | ||
368 | is_extern_crate: false, | ||
369 | is_macro_use: false, | ||
370 | visibility: visibility.clone(), | ||
371 | }; | ||
372 | buf.push(import_data); | ||
373 | }, | ||
374 | ); | ||
375 | for import_data in buf { | ||
376 | self.push_import(current_module, attrs.clone(), import_data); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | fn add_extern_crate_item( | ||
381 | &mut self, | ||
382 | current_module: Option<Idx<ModuleData>>, | ||
383 | extern_crate: ast::ExternCrateItem, | ||
384 | ) { | ||
385 | if let Some(name_ref) = extern_crate.name_ref() { | ||
386 | let path = ModPath::from_name_ref(&name_ref); | ||
387 | let visibility = | ||
388 | RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene); | ||
389 | let alias = extern_crate.alias().map(|a| { | ||
390 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
391 | }); | ||
392 | let attrs = self.parse_attrs(&extern_crate); | ||
393 | // FIXME: cfg_attr | ||
394 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
395 | let import_data = ImportData { | ||
396 | path, | ||
397 | alias, | ||
398 | is_glob: false, | ||
399 | is_prelude: false, | ||
400 | is_extern_crate: true, | ||
401 | is_macro_use, | ||
402 | visibility, | ||
403 | }; | ||
404 | self.push_import(current_module, attrs, import_data); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | fn add_macro(&mut self, current_module: Option<Idx<ModuleData>>, m: ast::MacroCall) { | ||
409 | let attrs = self.parse_attrs(&m); | ||
410 | let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) { | ||
411 | Some(it) => it, | ||
412 | _ => return, | ||
413 | }; | ||
414 | |||
415 | let name = m.name().map(|it| it.as_name()); | ||
416 | let ast_id = self.source_ast_id_map.ast_id(&m); | ||
417 | |||
418 | // FIXME: cfg_attr | ||
419 | let export_attr = attrs.by_key("macro_export"); | ||
420 | |||
421 | let export = export_attr.exists(); | ||
422 | let local_inner = if export { | ||
423 | export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { | ||
424 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { | ||
425 | ident.text.contains("local_inner_macros") | ||
426 | } | ||
427 | _ => false, | ||
428 | }) | ||
429 | } else { | ||
430 | false | ||
431 | }; | ||
432 | |||
433 | let builtin = attrs.by_key("rustc_builtin_macro").exists(); | ||
434 | |||
435 | let m = self.raw_items.macros.alloc(MacroData { | ||
436 | ast_id, | ||
437 | path, | ||
438 | name, | ||
439 | export, | ||
440 | local_inner, | ||
441 | builtin, | ||
442 | }); | ||
443 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | ||
444 | } | ||
445 | |||
446 | fn add_impl(&mut self, current_module: Option<Idx<ModuleData>>, imp: ast::ImplDef) { | ||
447 | let attrs = self.parse_attrs(&imp); | ||
448 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
449 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
450 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
451 | } | ||
452 | |||
453 | fn push_import( | ||
454 | &mut self, | ||
455 | current_module: Option<Idx<ModuleData>>, | ||
456 | attrs: Attrs, | ||
457 | data: ImportData, | ||
458 | ) { | ||
459 | let import = self.raw_items.imports.alloc(data); | ||
460 | self.push_item(current_module, attrs, RawItemKind::Import(import)) | ||
461 | } | ||
462 | |||
463 | fn push_item( | ||
464 | &mut self, | ||
465 | current_module: Option<Idx<ModuleData>>, | ||
466 | attrs: Attrs, | ||
467 | kind: RawItemKind, | ||
468 | ) { | ||
469 | match current_module { | ||
470 | Some(module) => match &mut self.raw_items.modules[module] { | ||
471 | ModuleData::Definition { items, .. } => items, | ||
472 | ModuleData::Declaration { .. } => unreachable!(), | ||
473 | }, | ||
474 | None => &mut self.raw_items.items, | ||
475 | } | ||
476 | .push(RawItem { attrs, kind }) | ||
477 | } | ||
478 | |||
479 | fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { | ||
480 | Attrs::new(item, &self.hygiene) | ||
481 | } | ||
482 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index 2b12c0daa..2f440975a 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -229,3 +229,50 @@ fn glob_enum_group() { | |||
229 | "### | 229 | "### |
230 | ); | 230 | ); |
231 | } | 231 | } |
232 | |||
233 | #[test] | ||
234 | fn glob_shadowed_def() { | ||
235 | mark::check!(import_shadowed); | ||
236 | let map = def_map( | ||
237 | r###" | ||
238 | //- /lib.rs | ||
239 | mod foo; | ||
240 | mod bar; | ||
241 | |||
242 | use foo::*; | ||
243 | use bar::baz; | ||
244 | |||
245 | use baz::Bar; | ||
246 | |||
247 | //- /foo.rs | ||
248 | pub mod baz { | ||
249 | pub struct Foo; | ||
250 | } | ||
251 | |||
252 | //- /bar.rs | ||
253 | pub mod baz { | ||
254 | pub struct Bar; | ||
255 | } | ||
256 | "###, | ||
257 | ); | ||
258 | assert_snapshot!(map, @r###" | ||
259 | ⋮crate | ||
260 | ⋮Bar: t v | ||
261 | ⋮bar: t | ||
262 | ⋮baz: t | ||
263 | ⋮foo: t | ||
264 | ⋮ | ||
265 | ⋮crate::bar | ||
266 | ⋮baz: t | ||
267 | ⋮ | ||
268 | ⋮crate::bar::baz | ||
269 | ⋮Bar: t v | ||
270 | ⋮ | ||
271 | ⋮crate::foo | ||
272 | ⋮baz: t | ||
273 | ⋮ | ||
274 | ⋮crate::foo::baz | ||
275 | ⋮Foo: t v | ||
276 | "### | ||
277 | ); | ||
278 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 87165ac33..0c288a108 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -58,44 +58,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | #[test] | 60 | #[test] |
61 | fn adding_inner_items_should_not_invalidate_def_map() { | ||
62 | check_def_map_is_not_recomputed( | ||
63 | r" | ||
64 | //- /lib.rs | ||
65 | struct S { a: i32} | ||
66 | enum E { A } | ||
67 | trait T { | ||
68 | fn a() {} | ||
69 | } | ||
70 | mod foo;<|> | ||
71 | impl S { | ||
72 | fn a() {} | ||
73 | } | ||
74 | use crate::foo::bar::Baz; | ||
75 | //- /foo/mod.rs | ||
76 | pub mod bar; | ||
77 | |||
78 | //- /foo/bar.rs | ||
79 | pub struct Baz; | ||
80 | ", | ||
81 | r" | ||
82 | struct S { a: i32, b: () } | ||
83 | enum E { A, B } | ||
84 | trait T { | ||
85 | fn a() {} | ||
86 | fn b() {} | ||
87 | } | ||
88 | mod foo;<|> | ||
89 | impl S { | ||
90 | fn a() {} | ||
91 | fn b() {} | ||
92 | } | ||
93 | use crate::foo::bar::Baz; | ||
94 | ", | ||
95 | ); | ||
96 | } | ||
97 | |||
98 | #[test] | ||
99 | fn typing_inside_a_macro_should_not_invalidate_def_map() { | 61 | fn typing_inside_a_macro_should_not_invalidate_def_map() { |
100 | let (mut db, pos) = TestDB::with_position( | 62 | let (mut db, pos) = TestDB::with_position( |
101 | r" | 63 | r" |
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index b43b294ca..753684201 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -20,8 +20,11 @@ fn name_res_works_for_broken_modules() { | |||
20 | ", | 20 | ", |
21 | ); | 21 | ); |
22 | assert_snapshot!(map, @r###" | 22 | assert_snapshot!(map, @r###" |
23 | ⋮crate | 23 | crate |
24 | ⋮Baz: _ | 24 | Baz: _ |
25 | foo: t | ||
26 | |||
27 | crate::foo | ||
25 | "###); | 28 | "###); |
26 | } | 29 | } |
27 | 30 | ||
@@ -332,6 +335,22 @@ fn module_resolution_relative_path_2() { | |||
332 | } | 335 | } |
333 | 336 | ||
334 | #[test] | 337 | #[test] |
338 | fn module_resolution_relative_path_outside_root() { | ||
339 | let map = def_map( | ||
340 | r###" | ||
341 | //- /main.rs | ||
342 | |||
343 | #[path="../../../../../outside.rs"] | ||
344 | mod foo; | ||
345 | "###, | ||
346 | ); | ||
347 | |||
348 | assert_snapshot!(map, @r###" | ||
349 | ⋮crate | ||
350 | "###); | ||
351 | } | ||
352 | |||
353 | #[test] | ||
335 | fn module_resolution_explicit_path_mod_rs_2() { | 354 | fn module_resolution_explicit_path_mod_rs_2() { |
336 | let map = def_map( | 355 | let map = def_map( |
337 | r###" | 356 | r###" |
@@ -719,10 +738,7 @@ fn unresolved_module_diagnostics() { | |||
719 | ), | 738 | ), |
720 | ), | 739 | ), |
721 | ), | 740 | ), |
722 | value: FileAstId { | 741 | value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1), |
723 | raw: Idx::<SyntaxNodePtr>(1), | ||
724 | _ty: PhantomData, | ||
725 | }, | ||
726 | }, | 742 | }, |
727 | candidate: "bar.rs", | 743 | candidate: "bar.rs", |
728 | }, | 744 | }, |
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs index 46e90da70..043b93fad 100644 --- a/crates/ra_hir_def/src/src.rs +++ b/crates/ra_hir_def/src/src.rs | |||
@@ -2,30 +2,37 @@ | |||
2 | 2 | ||
3 | use hir_expand::InFile; | 3 | use hir_expand::InFile; |
4 | use ra_arena::map::ArenaMap; | 4 | use ra_arena::map::ArenaMap; |
5 | use ra_syntax::AstNode; | ||
6 | 5 | ||
7 | use crate::{db::DefDatabase, AssocItemLoc, ItemLoc}; | 6 | use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; |
8 | 7 | ||
9 | pub trait HasSource { | 8 | pub trait HasSource { |
10 | type Value; | 9 | type Value; |
11 | fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>; | 10 | fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>; |
12 | } | 11 | } |
13 | 12 | ||
14 | impl<N: AstNode> HasSource for AssocItemLoc<N> { | 13 | impl<N: ItemTreeNode> HasSource for AssocItemLoc<N> { |
15 | type Value = N; | 14 | type Value = N::Source; |
16 | 15 | ||
17 | fn source(&self, db: &dyn DefDatabase) -> InFile<N> { | 16 | fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> { |
18 | let node = self.ast_id.to_node(db.upcast()); | 17 | let tree = db.item_tree(self.id.file_id); |
19 | InFile::new(self.ast_id.file_id, node) | 18 | let ast_id_map = db.ast_id_map(self.id.file_id); |
19 | let root = db.parse_or_expand(self.id.file_id).unwrap(); | ||
20 | let node = &tree[self.id.value]; | ||
21 | |||
22 | InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) | ||
20 | } | 23 | } |
21 | } | 24 | } |
22 | 25 | ||
23 | impl<N: AstNode> HasSource for ItemLoc<N> { | 26 | impl<N: ItemTreeNode> HasSource for ItemLoc<N> { |
24 | type Value = N; | 27 | type Value = N::Source; |
28 | |||
29 | fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> { | ||
30 | let tree = db.item_tree(self.id.file_id); | ||
31 | let ast_id_map = db.ast_id_map(self.id.file_id); | ||
32 | let root = db.parse_or_expand(self.id.file_id).unwrap(); | ||
33 | let node = &tree[self.id.value]; | ||
25 | 34 | ||
26 | fn source(&self, db: &dyn DefDatabase) -> InFile<N> { | 35 | InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) |
27 | let node = self.ast_id.to_node(db.upcast()); | ||
28 | InFile::new(self.ast_id.file_id, node) | ||
29 | } | 36 | } |
30 | } | 37 | } |
31 | 38 | ||
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 1482d3be0..8136cb50c 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::ast; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | path::{ModPath, PathKind}, | 8 | path::{ModPath, PathKind}, |
9 | AssocContainerId, ModuleId, | 9 | ModuleId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// Visibility of an item, not yet resolved. | 12 | /// Visibility of an item, not yet resolved. |
@@ -25,25 +25,6 @@ impl RawVisibility { | |||
25 | RawVisibility::Module(path) | 25 | RawVisibility::Module(path) |
26 | } | 26 | } |
27 | 27 | ||
28 | pub(crate) fn default_for_container(container_id: AssocContainerId) -> Self { | ||
29 | match container_id { | ||
30 | AssocContainerId::TraitId(_) => RawVisibility::Public, | ||
31 | _ => RawVisibility::private(), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn from_ast_with_default( | ||
36 | db: &dyn DefDatabase, | ||
37 | default: RawVisibility, | ||
38 | node: InFile<Option<ast::Visibility>>, | ||
39 | ) -> RawVisibility { | ||
40 | Self::from_ast_with_hygiene_and_default( | ||
41 | node.value, | ||
42 | default, | ||
43 | &Hygiene::new(db.upcast(), node.file_id), | ||
44 | ) | ||
45 | } | ||
46 | |||
47 | pub(crate) fn from_ast( | 28 | pub(crate) fn from_ast( |
48 | db: &dyn DefDatabase, | 29 | db: &dyn DefDatabase, |
49 | node: InFile<Option<ast::Visibility>>, | 30 | node: InFile<Option<ast::Visibility>>, |