aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/adt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/adt.rs')
-rw-r--r--crates/ra_hir_def/src/adt.rs295
1 files changed, 0 insertions, 295 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
deleted file mode 100644
index 6cb56a1cd..000000000
--- a/crates/ra_hir_def/src/adt.rs
+++ /dev/null
@@ -1,295 +0,0 @@
1//! Defines hir-level representation of structs, enums and unions
2
3use std::sync::Arc;
4
5use either::Either;
6use hir_expand::{
7 name::{AsName, Name},
8 InFile,
9};
10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12
13use crate::{
14 body::{CfgExpander, LowerCtx},
15 db::DefDatabase,
16 item_tree::{Field, Fields, ItemTree},
17 src::HasChildSource,
18 src::HasSource,
19 trace::Trace,
20 type_ref::TypeRef,
21 visibility::RawVisibility,
22 EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId,
23 VariantId,
24};
25use ra_cfg::CfgOptions;
26
27/// Note that we use `StructData` for unions as well!
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct StructData {
30 pub name: Name,
31 pub variant_data: Arc<VariantData>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct EnumData {
36 pub name: Name,
37 pub variants: Arena<EnumVariantData>,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct EnumVariantData {
42 pub name: Name,
43 pub variant_data: Arc<VariantData>,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum VariantData {
48 Record(Arena<FieldData>),
49 Tuple(Arena<FieldData>),
50 Unit,
51}
52
53/// A single field of an enum variant or struct
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct FieldData {
56 pub name: Name,
57 pub type_ref: TypeRef,
58 pub visibility: RawVisibility,
59}
60
61impl StructData {
62 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
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();
66
67 let strukt = &item_tree[loc.id.value];
68 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);
69
70 Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) })
71 }
72 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
73 let loc = id.lookup(db);
74 let item_tree = db.item_tree(loc.id.file_id);
75 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
76
77 let union = &item_tree[loc.id.value];
78 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);
79
80 Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) })
81 }
82}
83
84impl EnumData {
85 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
86 let loc = e.lookup(db);
87 let item_tree = db.item_tree(loc.id.file_id);
88 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
89
90 let enum_ = &item_tree[loc.id.value];
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 })
105 }
106
107 pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
108 let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
109 Some(id)
110 }
111}
112
113impl HasChildSource for EnumId {
114 type ChildId = LocalEnumVariantId;
115 type Value = ast::Variant;
116 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
117 let src = self.lookup(db).source(db);
118 let mut trace = Trace::new_for_map();
119 lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db));
120 src.with_value(trace.into_map())
121 }
122}
123
124fn lower_enum(
125 db: &dyn DefDatabase,
126 trace: &mut Trace<EnumVariantData, ast::Variant>,
127 ast: &InFile<ast::Enum>,
128 module_id: ModuleId,
129) {
130 let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
131 let variants = ast
132 .value
133 .variant_list()
134 .into_iter()
135 .flat_map(|it| it.variants())
136 .filter(|var| expander.is_cfg_enabled(var));
137 for var in variants {
138 trace.alloc(
139 || var.clone(),
140 || EnumVariantData {
141 name: var.name().map_or_else(Name::missing, |it| it.as_name()),
142 variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)),
143 },
144 );
145 }
146}
147
148impl VariantData {
149 fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
150 let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
151 let mut trace = Trace::new_for_arena();
152 match lower_struct(db, &mut expander, &mut trace, &flavor) {
153 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
154 StructKind::Record => VariantData::Record(trace.into_arena()),
155 StructKind::Unit => VariantData::Unit,
156 }
157 }
158
159 pub fn fields(&self) -> &Arena<FieldData> {
160 const EMPTY: &Arena<FieldData> = &Arena::new();
161 match &self {
162 VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
163 _ => EMPTY,
164 }
165 }
166
167 pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
168 self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
169 }
170
171 pub fn kind(&self) -> StructKind {
172 match self {
173 VariantData::Record(_) => StructKind::Record,
174 VariantData::Tuple(_) => StructKind::Tuple,
175 VariantData::Unit => StructKind::Unit,
176 }
177 }
178}
179
180impl HasChildSource for VariantId {
181 type ChildId = LocalFieldId;
182 type Value = Either<ast::TupleField, ast::RecordField>;
183
184 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
185 let (src, module_id) = match self {
186 VariantId::EnumVariantId(it) => {
187 // I don't really like the fact that we call into parent source
188 // here, this might add to more queries then necessary.
189 let src = it.parent.child_source(db);
190 (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db))
191 }
192 VariantId::StructId(it) => {
193 (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db))
194 }
195 VariantId::UnionId(it) => (
196 it.lookup(db).source(db).map(|it| {
197 it.record_field_list()
198 .map(ast::StructKind::Record)
199 .unwrap_or(ast::StructKind::Unit)
200 }),
201 it.lookup(db).container.module(db),
202 ),
203 };
204 let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
205 let mut trace = Trace::new_for_map();
206 lower_struct(db, &mut expander, &mut trace, &src);
207 src.with_value(trace.into_map())
208 }
209}
210
211#[derive(Debug, Copy, Clone, PartialEq, Eq)]
212pub enum StructKind {
213 Tuple,
214 Record,
215 Unit,
216}
217
218fn lower_struct(
219 db: &dyn DefDatabase,
220 expander: &mut CfgExpander,
221 trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>,
222 ast: &InFile<ast::StructKind>,
223) -> StructKind {
224 let ctx = LowerCtx::new(db, ast.file_id);
225
226 match &ast.value {
227 ast::StructKind::Tuple(fl) => {
228 for (i, fd) in fl.fields().enumerate() {
229 if !expander.is_cfg_enabled(&fd) {
230 continue;
231 }
232
233 trace.alloc(
234 || Either::Left(fd.clone()),
235 || FieldData {
236 name: Name::new_tuple_field(i),
237 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
238 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
239 },
240 );
241 }
242 StructKind::Tuple
243 }
244 ast::StructKind::Record(fl) => {
245 for fd in fl.fields() {
246 if !expander.is_cfg_enabled(&fd) {
247 continue;
248 }
249
250 trace.alloc(
251 || Either::Right(fd.clone()),
252 || FieldData {
253 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
254 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
255 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
256 },
257 );
258 }
259 StructKind::Record
260 }
261 ast::StructKind::Unit => StructKind::Unit,
262 }
263}
264
265fn 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
289fn 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}