]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/child_by_source.rs
Merge #6924
[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 }
22
23 impl ChildBySource for TraitId {
24     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
25         let mut res = DynMap::default();
26
27         let data = db.trait_data(*self);
28         for (_name, item) in data.items.iter() {
29             match *item {
30                 AssocItemId::FunctionId(func) => {
31                     let src = func.lookup(db).source(db);
32                     res[keys::FUNCTION].insert(src, func)
33                 }
34                 AssocItemId::ConstId(konst) => {
35                     let src = konst.lookup(db).source(db);
36                     res[keys::CONST].insert(src, konst)
37                 }
38                 AssocItemId::TypeAliasId(ty) => {
39                     let src = ty.lookup(db).source(db);
40                     res[keys::TYPE_ALIAS].insert(src, ty)
41                 }
42             }
43         }
44
45         res
46     }
47 }
48
49 impl ChildBySource for ImplId {
50     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
51         let mut res = DynMap::default();
52
53         let data = db.impl_data(*self);
54         for &item in data.items.iter() {
55             match item {
56                 AssocItemId::FunctionId(func) => {
57                     let src = func.lookup(db).source(db);
58                     res[keys::FUNCTION].insert(src, func)
59                 }
60                 AssocItemId::ConstId(konst) => {
61                     let src = konst.lookup(db).source(db);
62                     res[keys::CONST].insert(src, konst)
63                 }
64                 AssocItemId::TypeAliasId(ty) => {
65                     let src = ty.lookup(db).source(db);
66                     res[keys::TYPE_ALIAS].insert(src, ty)
67                 }
68             }
69         }
70
71         res
72     }
73 }
74
75 impl ChildBySource for ModuleId {
76     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
77         let crate_def_map = db.crate_def_map(self.krate);
78         let module_data = &crate_def_map[self.local_id];
79         module_data.scope.child_by_source(db)
80     }
81 }
82
83 impl ChildBySource for ItemScope {
84     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
85         let mut res = DynMap::default();
86         self.declarations().for_each(|item| add_module_def(db, &mut res, item));
87         self.impls().for_each(|imp| add_impl(db, &mut res, imp));
88         return res;
89
90         fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
91             match item {
92                 ModuleDefId::FunctionId(func) => {
93                     let src = func.lookup(db).source(db);
94                     map[keys::FUNCTION].insert(src, func)
95                 }
96                 ModuleDefId::ConstId(konst) => {
97                     let src = konst.lookup(db).source(db);
98                     map[keys::CONST].insert(src, konst)
99                 }
100                 ModuleDefId::StaticId(statik) => {
101                     let src = statik.lookup(db).source(db);
102                     map[keys::STATIC].insert(src, statik)
103                 }
104                 ModuleDefId::TypeAliasId(ty) => {
105                     let src = ty.lookup(db).source(db);
106                     map[keys::TYPE_ALIAS].insert(src, ty)
107                 }
108                 ModuleDefId::TraitId(trait_) => {
109                     let src = trait_.lookup(db).source(db);
110                     map[keys::TRAIT].insert(src, trait_)
111                 }
112                 ModuleDefId::AdtId(adt) => match adt {
113                     AdtId::StructId(strukt) => {
114                         let src = strukt.lookup(db).source(db);
115                         map[keys::STRUCT].insert(src, strukt)
116                     }
117                     AdtId::UnionId(union_) => {
118                         let src = union_.lookup(db).source(db);
119                         map[keys::UNION].insert(src, union_)
120                     }
121                     AdtId::EnumId(enum_) => {
122                         let src = enum_.lookup(db).source(db);
123                         map[keys::ENUM].insert(src, enum_)
124                     }
125                 },
126                 _ => (),
127             }
128         }
129         fn add_impl(db: &dyn DefDatabase, map: &mut DynMap, imp: ImplId) {
130             let src = imp.lookup(db).source(db);
131             map[keys::IMPL].insert(src, imp)
132         }
133     }
134 }
135
136 impl ChildBySource for VariantId {
137     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
138         let mut res = DynMap::default();
139
140         let arena_map = self.child_source(db);
141         let arena_map = arena_map.as_ref();
142         for (local_id, source) in arena_map.value.iter() {
143             let id = FieldId { parent: *self, local_id };
144             match source {
145                 Either::Left(source) => {
146                     res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
147                 }
148                 Either::Right(source) => {
149                     res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
150                 }
151             }
152         }
153         res
154     }
155 }
156
157 impl ChildBySource for EnumId {
158     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
159         let mut res = DynMap::default();
160
161         let arena_map = self.child_source(db);
162         let arena_map = arena_map.as_ref();
163         for (local_id, source) in arena_map.value.iter() {
164             let id = EnumVariantId { parent: *self, local_id };
165             res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
166         }
167
168         res
169     }
170 }
171
172 impl ChildBySource for DefWithBodyId {
173     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
174         let body = db.body(*self);
175         body.item_scope.child_by_source(db)
176     }
177 }