aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/adt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/adt.rs')
-rw-r--r--crates/ra_hir/src/adt.rs194
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 @@
1use std::sync::Arc;
2
3use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}};
4
5use crate::{
6 DefId, Cancelable,
7 db::{HirDatabase},
8 type_ref::TypeRef,
9};
10
11pub struct Struct {
12 def_id: DefId,
13}
14
15impl 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)]
38pub struct StructData {
39 name: Option<SmolStr>,
40 variant_data: Arc<VariantData>,
41}
42
43impl 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
60pub struct Enum {
61 def_id: DefId,
62}
63
64impl 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)]
79pub struct EnumData {
80 name: Option<SmolStr>,
81 variants: Vec<(SmolStr, Arc<VariantData>)>,
82}
83
84impl 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)]
107pub struct StructField {
108 name: SmolStr,
109 type_ref: TypeRef,
110}
111
112impl 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)]
123pub enum VariantData {
124 Struct(Vec<StructField>),
125 Tuple(Vec<StructField>),
126 Unit,
127}
128
129impl 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}