]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/child_by_source.rs
Merge #8398
[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
89         fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
90             match item {
91                 ModuleDefId::FunctionId(func) => {
92                     let src = func.lookup(db).source(db);
93                     map[keys::FUNCTION].insert(src, func)
94                 }
95                 ModuleDefId::ConstId(konst) => {
96                     let src = konst.lookup(db).source(db);
97                     map[keys::CONST].insert(src, konst)
98                 }
99                 ModuleDefId::StaticId(statik) => {
100                     let src = statik.lookup(db).source(db);
101                     map[keys::STATIC].insert(src, statik)
102                 }
103                 ModuleDefId::TypeAliasId(ty) => {
104                     let src = ty.lookup(db).source(db);
105                     map[keys::TYPE_ALIAS].insert(src, ty)
106                 }
107                 ModuleDefId::TraitId(trait_) => {
108                     let src = trait_.lookup(db).source(db);
109                     map[keys::TRAIT].insert(src, trait_)
110                 }
111                 ModuleDefId::AdtId(adt) => match adt {
112                     AdtId::StructId(strukt) => {
113                         let src = strukt.lookup(db).source(db);
114                         map[keys::STRUCT].insert(src, strukt)
115                     }
116                     AdtId::UnionId(union_) => {
117                         let src = union_.lookup(db).source(db);
118                         map[keys::UNION].insert(src, union_)
119                     }
120                     AdtId::EnumId(enum_) => {
121                         let src = enum_.lookup(db).source(db);
122                         map[keys::ENUM].insert(src, enum_)
123                     }
124                 },
125                 _ => (),
126             }
127         }
128         fn add_impl(db: &dyn DefDatabase, map: &mut DynMap, imp: ImplId) {
129             let src = imp.lookup(db).source(db);
130             map[keys::IMPL].insert(src, imp)
131         }
132     }
133 }
134
135 impl ChildBySource for VariantId {
136     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
137         let arena_map = self.child_source(db);
138         let arena_map = arena_map.as_ref();
139         for (local_id, source) in arena_map.value.iter() {
140             let id = FieldId { parent: *self, local_id };
141             match source {
142                 Either::Left(source) => {
143                     res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
144                 }
145                 Either::Right(source) => {
146                     res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
147                 }
148             }
149         }
150     }
151 }
152
153 impl ChildBySource for EnumId {
154     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
155         let arena_map = self.child_source(db);
156         let arena_map = arena_map.as_ref();
157         for (local_id, source) in arena_map.value.iter() {
158             let id = EnumVariantId { parent: *self, local_id };
159             res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
160         }
161     }
162 }
163
164 impl ChildBySource for DefWithBodyId {
165     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
166         let body = db.body(*self);
167         for (_, def_map) in body.blocks(db) {
168             // All block expressions are merged into the same map, because they logically all add
169             // inner items to the containing `DefWithBodyId`.
170             def_map[def_map.root()].scope.child_by_source_to(db, res);
171         }
172     }
173 }