]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/child_by_source.rs
Merge #9177
[rust.git] / crates / hir_def / src / child_by_source.rs
1 //! When *constructing* `hir`, we start at some parent syntax node and recursively
2 //! lower the children.
3 //!
4 //! This modules allows one to go in the opposite direction: start with a syntax
5 //! node for a *child*, and get its hir.
6
7 use either::Either;
8
9 use crate::{
10     db::DefDatabase,
11     dyn_map::DynMap,
12     item_scope::ItemScope,
13     keys,
14     src::{HasChildSource, HasSource},
15     AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, ModuleDefId,
16     ModuleId, TraitId, VariantId,
17 };
18
19 pub trait ChildBySource {
20     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
21         let mut res = DynMap::default();
22         self.child_by_source_to(db, &mut res);
23         res
24     }
25     fn child_by_source_to(&self, db: &dyn DefDatabase, map: &mut DynMap);
26 }
27
28 impl ChildBySource for TraitId {
29     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
30         let data = db.trait_data(*self);
31         for (_name, item) in data.items.iter() {
32             match *item {
33                 AssocItemId::FunctionId(func) => {
34                     let src = func.lookup(db).source(db);
35                     res[keys::FUNCTION].insert(src, func)
36                 }
37                 AssocItemId::ConstId(konst) => {
38                     let src = konst.lookup(db).source(db);
39                     res[keys::CONST].insert(src, konst)
40                 }
41                 AssocItemId::TypeAliasId(ty) => {
42                     let src = ty.lookup(db).source(db);
43                     res[keys::TYPE_ALIAS].insert(src, ty)
44                 }
45             }
46         }
47     }
48 }
49
50 impl ChildBySource for ImplId {
51     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
52         let data = db.impl_data(*self);
53         for &item in data.items.iter() {
54             match item {
55                 AssocItemId::FunctionId(func) => {
56                     let src = func.lookup(db).source(db);
57                     res[keys::FUNCTION].insert(src, func)
58                 }
59                 AssocItemId::ConstId(konst) => {
60                     let src = konst.lookup(db).source(db);
61                     res[keys::CONST].insert(src, konst)
62                 }
63                 AssocItemId::TypeAliasId(ty) => {
64                     let src = ty.lookup(db).source(db);
65                     res[keys::TYPE_ALIAS].insert(src, ty)
66                 }
67             }
68         }
69     }
70 }
71
72 impl ChildBySource for ModuleId {
73     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
74         let def_map = self.def_map(db);
75         let module_data = &def_map[self.local_id];
76         module_data.scope.child_by_source_to(db, res);
77     }
78 }
79
80 impl ChildBySource for ItemScope {
81     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
82         self.declarations().for_each(|item| add_module_def(db, res, item));
83         self.unnamed_consts().for_each(|konst| {
84             let src = konst.lookup(db).source(db);
85             res[keys::CONST].insert(src, konst);
86         });
87         self.impls().for_each(|imp| add_impl(db, res, imp));
88         self.attr_macro_invocs().for_each(|(ast_id, call_id)| {
89             let item = ast_id.with_value(ast_id.to_node(db.upcast()));
90             res[keys::ATTR_MACRO].insert(item, call_id);
91         });
92
93         fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
94             match item {
95                 ModuleDefId::FunctionId(func) => {
96                     let src = func.lookup(db).source(db);
97                     map[keys::FUNCTION].insert(src, func)
98                 }
99                 ModuleDefId::ConstId(konst) => {
100                     let src = konst.lookup(db).source(db);
101                     map[keys::CONST].insert(src, konst)
102                 }
103                 ModuleDefId::StaticId(statik) => {
104                     let src = statik.lookup(db).source(db);
105                     map[keys::STATIC].insert(src, statik)
106                 }
107                 ModuleDefId::TypeAliasId(ty) => {
108                     let src = ty.lookup(db).source(db);
109                     map[keys::TYPE_ALIAS].insert(src, ty)
110                 }
111                 ModuleDefId::TraitId(trait_) => {
112                     let src = trait_.lookup(db).source(db);
113                     map[keys::TRAIT].insert(src, trait_)
114                 }
115                 ModuleDefId::AdtId(adt) => match adt {
116                     AdtId::StructId(strukt) => {
117                         let src = strukt.lookup(db).source(db);
118                         map[keys::STRUCT].insert(src, strukt)
119                     }
120                     AdtId::UnionId(union_) => {
121                         let src = union_.lookup(db).source(db);
122                         map[keys::UNION].insert(src, union_)
123                     }
124                     AdtId::EnumId(enum_) => {
125                         let src = enum_.lookup(db).source(db);
126                         map[keys::ENUM].insert(src, enum_)
127                     }
128                 },
129                 _ => (),
130             }
131         }
132         fn add_impl(db: &dyn DefDatabase, map: &mut DynMap, imp: ImplId) {
133             let src = imp.lookup(db).source(db);
134             map[keys::IMPL].insert(src, imp)
135         }
136     }
137 }
138
139 impl ChildBySource for VariantId {
140     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
141         let arena_map = self.child_source(db);
142         let arena_map = arena_map.as_ref();
143         for (local_id, source) in arena_map.value.iter() {
144             let id = FieldId { parent: *self, local_id };
145             match source {
146                 Either::Left(source) => {
147                     res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
148                 }
149                 Either::Right(source) => {
150                     res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
151                 }
152             }
153         }
154     }
155 }
156
157 impl ChildBySource for EnumId {
158     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
159         let arena_map = self.child_source(db);
160         let arena_map = arena_map.as_ref();
161         for (local_id, source) in arena_map.value.iter() {
162             let id = EnumVariantId { parent: *self, local_id };
163             res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
164         }
165     }
166 }
167
168 impl ChildBySource for DefWithBodyId {
169     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
170         let body = db.body(*self);
171         for (_, def_map) in body.blocks(db) {
172             // All block expressions are merged into the same map, because they logically all add
173             // inner items to the containing `DefWithBodyId`.
174             def_map[def_map.root()].scope.child_by_source_to(db, res);
175         }
176     }
177 }