diff options
Diffstat (limited to 'crates/ra_hir/src/adt.rs')
-rw-r--r-- | crates/ra_hir/src/adt.rs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs new file mode 100644 index 000000000..65c461148 --- /dev/null +++ b/crates/ra_hir/src/adt.rs | |||
@@ -0,0 +1,194 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; | ||
4 | |||
5 | use crate::{ | ||
6 | DefId, Cancelable, | ||
7 | db::{HirDatabase}, | ||
8 | type_ref::TypeRef, | ||
9 | }; | ||
10 | |||
11 | pub struct Struct { | ||
12 | def_id: DefId, | ||
13 | } | ||
14 | |||
15 | impl Struct { | ||
16 | pub(crate) fn new(def_id: DefId) -> Self { | ||
17 | Struct { def_id } | ||
18 | } | ||
19 | |||
20 | pub fn def_id(&self) -> DefId { | ||
21 | self.def_id | ||
22 | } | ||
23 | |||
24 | pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> { | ||
25 | Ok(db.struct_data(self.def_id)?.variant_data.clone()) | ||
26 | } | ||
27 | |||
28 | pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<StructData>> { | ||
29 | Ok(db.struct_data(self.def_id)?) | ||
30 | } | ||
31 | |||
32 | pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> { | ||
33 | Ok(db.struct_data(self.def_id)?.name.clone()) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
38 | pub struct StructData { | ||
39 | name: Option<SmolStr>, | ||
40 | variant_data: Arc<VariantData>, | ||
41 | } | ||
42 | |||
43 | impl StructData { | ||
44 | pub(crate) fn new(struct_def: ast::StructDef) -> StructData { | ||
45 | let name = struct_def.name().map(|n| n.text()); | ||
46 | let variant_data = VariantData::new(struct_def.flavor()); | ||
47 | let variant_data = Arc::new(variant_data); | ||
48 | StructData { name, variant_data } | ||
49 | } | ||
50 | |||
51 | pub fn name(&self) -> Option<&SmolStr> { | ||
52 | self.name.as_ref() | ||
53 | } | ||
54 | |||
55 | pub fn variant_data(&self) -> &Arc<VariantData> { | ||
56 | &self.variant_data | ||
57 | } | ||
58 | } | ||
59 | |||
60 | pub struct Enum { | ||
61 | def_id: DefId, | ||
62 | } | ||
63 | |||
64 | impl Enum { | ||
65 | pub(crate) fn new(def_id: DefId) -> Self { | ||
66 | Enum { def_id } | ||
67 | } | ||
68 | |||
69 | pub fn def_id(&self) -> DefId { | ||
70 | self.def_id | ||
71 | } | ||
72 | |||
73 | pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> { | ||
74 | Ok(db.enum_data(self.def_id)?.name.clone()) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
79 | pub struct EnumData { | ||
80 | name: Option<SmolStr>, | ||
81 | variants: Vec<(SmolStr, Arc<VariantData>)>, | ||
82 | } | ||
83 | |||
84 | impl EnumData { | ||
85 | pub(crate) fn new(enum_def: ast::EnumDef) -> Self { | ||
86 | let name = enum_def.name().map(|n| n.text()); | ||
87 | let variants = if let Some(evl) = enum_def.variant_list() { | ||
88 | evl.variants() | ||
89 | .map(|v| { | ||
90 | ( | ||
91 | v.name() | ||
92 | .map(|n| n.text()) | ||
93 | .unwrap_or_else(|| SmolStr::new("[error]")), | ||
94 | Arc::new(VariantData::new(v.flavor())), | ||
95 | ) | ||
96 | }) | ||
97 | .collect() | ||
98 | } else { | ||
99 | Vec::new() | ||
100 | }; | ||
101 | EnumData { name, variants } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /// A single field of an enum variant or struct | ||
106 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
107 | pub struct StructField { | ||
108 | name: SmolStr, | ||
109 | type_ref: TypeRef, | ||
110 | } | ||
111 | |||
112 | impl StructField { | ||
113 | pub fn name(&self) -> SmolStr { | ||
114 | self.name.clone() | ||
115 | } | ||
116 | pub fn type_ref(&self) -> &TypeRef { | ||
117 | &self.type_ref | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// Fields of an enum variant or struct | ||
122 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
123 | pub enum VariantData { | ||
124 | Struct(Vec<StructField>), | ||
125 | Tuple(Vec<StructField>), | ||
126 | Unit, | ||
127 | } | ||
128 | |||
129 | impl VariantData { | ||
130 | pub fn new(flavor: StructFlavor) -> Self { | ||
131 | match flavor { | ||
132 | StructFlavor::Tuple(fl) => { | ||
133 | let fields = fl | ||
134 | .fields() | ||
135 | .enumerate() | ||
136 | .map(|(i, fd)| StructField { | ||
137 | name: SmolStr::new(i.to_string()), | ||
138 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | ||
139 | }) | ||
140 | .collect(); | ||
141 | VariantData::Tuple(fields) | ||
142 | } | ||
143 | StructFlavor::Named(fl) => { | ||
144 | let fields = fl | ||
145 | .fields() | ||
146 | .map(|fd| StructField { | ||
147 | name: fd | ||
148 | .name() | ||
149 | .map(|n| n.text()) | ||
150 | .unwrap_or_else(|| SmolStr::new("[error]")), | ||
151 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | ||
152 | }) | ||
153 | .collect(); | ||
154 | VariantData::Struct(fields) | ||
155 | } | ||
156 | StructFlavor::Unit => VariantData::Unit, | ||
157 | } | ||
158 | } | ||
159 | |||
160 | pub(crate) fn get_field_type_ref(&self, field_name: &str) -> Option<&TypeRef> { | ||
161 | self.fields() | ||
162 | .iter() | ||
163 | .find(|f| f.name == field_name) | ||
164 | .map(|f| &f.type_ref) | ||
165 | } | ||
166 | |||
167 | pub fn fields(&self) -> &[StructField] { | ||
168 | match *self { | ||
169 | VariantData::Struct(ref fields) | VariantData::Tuple(ref fields) => fields, | ||
170 | _ => &[], | ||
171 | } | ||
172 | } | ||
173 | pub fn is_struct(&self) -> bool { | ||
174 | if let VariantData::Struct(..) = *self { | ||
175 | true | ||
176 | } else { | ||
177 | false | ||
178 | } | ||
179 | } | ||
180 | pub fn is_tuple(&self) -> bool { | ||
181 | if let VariantData::Tuple(..) = *self { | ||
182 | true | ||
183 | } else { | ||
184 | false | ||
185 | } | ||
186 | } | ||
187 | pub fn is_unit(&self) -> bool { | ||
188 | if let VariantData::Unit = *self { | ||
189 | true | ||
190 | } else { | ||
191 | false | ||
192 | } | ||
193 | } | ||
194 | } | ||