Skip to main content

type_crawler/types/
type_kind.rs

1use std::fmt::Display;
2
3use crate::{
4    EnumDecl, Env, StructDecl, Typedef, Types, UnionDecl,
5    error::{AlignofSnafu, ParseError, SizeofSnafu, UnsupportedEntitySnafu, UnsupportedTypeSnafu},
6};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum TypeKind {
10    USize {
11        size: usize,
12    },
13    SSize {
14        size: usize,
15    },
16    U64,
17    U32,
18    U16,
19    U8,
20    S64,
21    S32,
22    S16,
23    S8,
24    F32,
25    F64,
26    LongDouble {
27        size: usize,
28        alignment: usize,
29    },
30    Char16,
31    Char32,
32    WChar {
33        size: usize,
34    },
35    Bool,
36    Void,
37    Reference {
38        size: usize,
39        referenced_type: Box<TypeKind>,
40    },
41    Pointer {
42        size: usize,
43        pointee_type: Box<TypeKind>,
44    },
45    MemberPointer {
46        size: usize,
47        pointee_type: Box<TypeKind>,
48        record_name: String,
49    },
50    Array {
51        element_type: Box<TypeKind>,
52        size: Option<usize>, // None for incomplete arrays
53    },
54    Function {
55        return_type: Box<TypeKind>,
56        parameters: Vec<TypeKind>,
57    },
58    Struct(StructDecl),
59    Class(StructDecl),
60    Union(UnionDecl),
61    Enum(EnumDecl),
62    Typedef(Box<Typedef>),
63    Named(String),
64}
65
66impl TypeKind {
67    pub fn new(env: &Env, types: &Types, ty: clang::Type) -> Result<Self, ParseError> {
68        let kind = ty.get_kind();
69        match kind {
70            clang::TypeKind::ULong => Ok(TypeKind::USize { size: env.word_size().bytes() }),
71            clang::TypeKind::Long => Ok(TypeKind::SSize { size: env.word_size().bytes() }),
72            clang::TypeKind::ULongLong => Ok(TypeKind::U64),
73            clang::TypeKind::UInt => Ok(TypeKind::U32),
74            clang::TypeKind::UShort => Ok(TypeKind::U16),
75            clang::TypeKind::UChar => Ok(TypeKind::U8),
76            clang::TypeKind::LongLong => Ok(TypeKind::S64),
77            clang::TypeKind::Int => Ok(TypeKind::S32),
78            clang::TypeKind::Short => Ok(TypeKind::S16),
79            clang::TypeKind::CharS => Ok(TypeKind::S8),
80            clang::TypeKind::CharU => Ok(TypeKind::U8),
81            clang::TypeKind::Float => Ok(TypeKind::F32),
82            clang::TypeKind::Double => Ok(TypeKind::F64),
83            clang::TypeKind::LongDouble => Ok(TypeKind::LongDouble {
84                size: ty.get_sizeof().map_err(|e| {
85                    SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
86                })?,
87                alignment: ty.get_alignof().map_err(|e| {
88                    AlignofSnafu { type_name: ty.get_display_name(), error: e }.build()
89                })?,
90            }),
91            clang::TypeKind::Char16 => Ok(TypeKind::Char16),
92            clang::TypeKind::Char32 => Ok(TypeKind::Char32),
93            clang::TypeKind::WChar => Ok(TypeKind::WChar {
94                size: ty.get_sizeof().map_err(|e| {
95                    SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
96                })?,
97            }),
98            clang::TypeKind::Bool => Ok(TypeKind::Bool),
99            clang::TypeKind::Void => Ok(TypeKind::Void),
100            clang::TypeKind::LValueReference | clang::TypeKind::Pointer => {
101                let pointee_type = ty.get_pointee_type().ok_or_else(|| {
102                    UnsupportedTypeSnafu {
103                        message: format!("Pointer type without pointee type: {ty:?}"),
104                    }
105                    .build()
106                })?;
107                let inner_type = TypeKind::new(env, types, pointee_type)?;
108                let size = ty.get_sizeof().map_err(|e| {
109                    SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
110                })?;
111                let pointee_type = Box::new(inner_type);
112
113                if kind == clang::TypeKind::LValueReference {
114                    Ok(TypeKind::Reference { size, referenced_type: pointee_type })
115                } else {
116                    Ok(TypeKind::Pointer { size, pointee_type })
117                }
118            }
119            clang::TypeKind::MemberPointer => {
120                let pointee_type = ty.get_pointee_type().ok_or_else(|| {
121                    UnsupportedTypeSnafu {
122                        message: format!("MemberPointer type without pointee type: {ty:?}"),
123                    }
124                    .build()
125                })?;
126                let inner_type = TypeKind::new(env, types, pointee_type)?;
127                let size = ty.get_sizeof().map_err(|e| {
128                    SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
129                })?;
130                let pointee_type = Box::new(inner_type);
131
132                let record_name = ty
133                    .get_class_type()
134                    .ok_or_else(|| {
135                        UnsupportedTypeSnafu {
136                            message: format!("MemberPointer type without class type: {ty:?}"),
137                        }
138                        .build()
139                    })?
140                    .get_display_name();
141
142                Ok(TypeKind::MemberPointer { size, pointee_type, record_name })
143            }
144            clang::TypeKind::IncompleteArray => {
145                let element_type = ty.get_element_type().ok_or_else(|| {
146                    UnsupportedTypeSnafu {
147                        message: format!("IncompleteArray type without element type: {ty:?}"),
148                    }
149                    .build()
150                })?;
151                let inner_type = TypeKind::new(env, types, element_type)?;
152                Ok(TypeKind::Array { element_type: Box::new(inner_type), size: None })
153            }
154            clang::TypeKind::ConstantArray => {
155                let element_type = ty.get_element_type().ok_or_else(|| {
156                    UnsupportedTypeSnafu {
157                        message: format!("ConstantArray type without element type: {ty:?}"),
158                    }
159                    .build()
160                })?;
161                let size = ty.get_size().ok_or_else(|| {
162                    UnsupportedTypeSnafu { message: format!("ConstantArray without size: {ty:?}") }
163                        .build()
164                })?;
165                let inner_type = TypeKind::new(env, types, element_type)?;
166                Ok(TypeKind::Array { element_type: Box::new(inner_type), size: Some(size) })
167            }
168            clang::TypeKind::FunctionPrototype => {
169                let return_type = ty.get_result_type().ok_or_else(|| {
170                    UnsupportedTypeSnafu {
171                        message: format!("FunctionPrototype without return type: {ty:?}"),
172                    }
173                    .build()
174                })?;
175                let parameters = ty.get_argument_types().ok_or_else(|| {
176                    UnsupportedTypeSnafu {
177                        message: format!("FunctionPrototype without parameters: {ty:?}"),
178                    }
179                    .build()
180                })?;
181                let return_type = TypeKind::new(env, types, return_type)?;
182                let parameters = parameters
183                    .into_iter()
184                    .map(|param| TypeKind::new(env, types, param))
185                    .collect::<Result<Vec<_>, _>>()?;
186                Ok(TypeKind::Function { return_type: Box::new(return_type), parameters })
187            }
188            clang::TypeKind::Elaborated => {
189                let elaborated_type = ty.get_elaborated_type().ok_or_else(|| {
190                    UnsupportedTypeSnafu {
191                        message: format!("Elaborated type without type: {ty:?}"),
192                    }
193                    .build()
194                })?;
195                let elaborated_decl = elaborated_type.get_declaration().ok_or_else(|| {
196                    UnsupportedTypeSnafu {
197                        message: format!("Elaborated type without declaration: {ty:?}"),
198                    }
199                    .build()
200                })?;
201                if elaborated_decl.is_anonymous() {
202                    TypeKind::new(env, types, elaborated_type)
203                } else {
204                    let name = elaborated_decl.get_name().ok_or_else(|| {
205                        UnsupportedTypeSnafu {
206                            message: format!("Elaborated type declaration without name: {ty:?}"),
207                        }
208                        .build()
209                    })?;
210                    match name.as_str() {
211                        "bool" => Ok(TypeKind::Bool), // "bool" not defined in C
212                        _ => Ok(TypeKind::Named(name)),
213                    }
214                }
215            }
216            clang::TypeKind::Record => {
217                let node = ty.get_declaration().ok_or_else(|| {
218                    UnsupportedTypeSnafu {
219                        message: format!("Record type without declaration: {ty:?}"),
220                    }
221                    .build()
222                })?;
223                match node.get_kind() {
224                    clang::EntityKind::StructDecl => {
225                        let struct_decl = StructDecl::new(env, types, None, ty)?;
226                        Ok(TypeKind::Struct(struct_decl))
227                    }
228                    clang::EntityKind::ClassDecl => {
229                        let struct_decl = StructDecl::new(env, types, None, ty)?;
230                        Ok(TypeKind::Class(struct_decl))
231                    }
232                    clang::EntityKind::UnionDecl => {
233                        let union_decl = UnionDecl::new(env, types, None, ty)?;
234                        Ok(TypeKind::Union(union_decl))
235                    }
236                    _ => UnsupportedEntitySnafu {
237                        at: "struct/union".to_string(),
238                        message: format!(
239                            "Unsupported entity kind in record: {:?}",
240                            node.get_kind()
241                        ),
242                    }
243                    .fail(),
244                }
245            }
246            clang::TypeKind::Enum => {
247                let decl = ty.get_declaration().ok_or_else(|| {
248                    UnsupportedTypeSnafu {
249                        message: format!("Enum type without declaration: {ty:?}"),
250                    }
251                    .build()
252                })?;
253                let name = decl.get_name();
254                Ok(TypeKind::Enum(EnumDecl::new(name, &decl)?))
255            }
256            _ => {
257                panic!("Unsupported type: {:?} for name: {}", ty.get_kind(), ty.get_display_name())
258            }
259        }
260    }
261
262    pub fn size(&self, types: &Types) -> usize {
263        match self {
264            TypeKind::USize { size } | TypeKind::SSize { size } => *size,
265            TypeKind::U64 | TypeKind::S64 => 8,
266            TypeKind::U32 | TypeKind::S32 => 4,
267            TypeKind::U16 | TypeKind::S16 => 2,
268            TypeKind::U8 | TypeKind::S8 => 1,
269            TypeKind::F32 => 4,
270            TypeKind::F64 => 8,
271            TypeKind::LongDouble { size, .. } => *size,
272            TypeKind::Char16 => 2,
273            TypeKind::Char32 => 4,
274            TypeKind::WChar { size } => *size,
275            TypeKind::Bool => 1,
276            TypeKind::Void => 0,
277            TypeKind::Reference { size, .. } => *size,
278            TypeKind::Pointer { size, .. } => *size,
279            TypeKind::MemberPointer { size, .. } => *size,
280            TypeKind::Array { element_type, size } => {
281                if let Some(size) = size {
282                    let stride =
283                        element_type.size(types).next_multiple_of(element_type.alignment(types));
284                    size * stride
285                } else {
286                    0
287                }
288            }
289            TypeKind::Function { .. } => 0,
290            TypeKind::Struct(struct_decl) => struct_decl.size(),
291            TypeKind::Class(class_decl) => class_decl.size(),
292            TypeKind::Union(union_decl) => union_decl.size(),
293            TypeKind::Enum(enum_decl) => enum_decl.size(),
294            TypeKind::Typedef(typedef) => typedef.underlying_type().size(types),
295            TypeKind::Named(name) => types.get(name).map(|ty| ty.size(types)).unwrap_or(0),
296        }
297    }
298
299    pub fn alignment(&self, types: &Types) -> usize {
300        match self {
301            TypeKind::USize { size } | TypeKind::SSize { size } => *size,
302            TypeKind::U64 | TypeKind::S64 => 8,
303            TypeKind::U32 | TypeKind::S32 => 4,
304            TypeKind::U16 | TypeKind::S16 => 2,
305            TypeKind::U8 | TypeKind::S8 => 1,
306            TypeKind::F32 => 4,
307            TypeKind::F64 => 8,
308            TypeKind::LongDouble { alignment, .. } => *alignment,
309            TypeKind::Char16 => 2,
310            TypeKind::Char32 => 4,
311            TypeKind::WChar { size } => *size,
312            TypeKind::Bool => 1,
313            TypeKind::Void => 0,
314            TypeKind::Reference { size, .. } => *size,
315            TypeKind::Pointer { size, .. } => *size,
316            TypeKind::MemberPointer { size, .. } => *size,
317            TypeKind::Array { element_type, .. } => element_type.alignment(types),
318            TypeKind::Function { .. } => 0,
319            TypeKind::Struct(struct_decl) => struct_decl.alignment(),
320            TypeKind::Class(class_decl) => class_decl.alignment(),
321            TypeKind::Union(union_decl) => union_decl.alignment(),
322            TypeKind::Enum(enum_decl) => enum_decl.alignment(),
323            TypeKind::Typedef(typedef) => typedef.underlying_type().alignment(types),
324            TypeKind::Named(name) => types.get(name).map(|ty| ty.alignment(types)).unwrap_or(0),
325        }
326    }
327
328    pub fn stride(&self, types: &Types) -> usize {
329        let size = self.size(types);
330        let alignment = self.alignment(types);
331        size.next_multiple_of(alignment)
332    }
333
334    pub fn name(&self) -> Option<&str> {
335        match self {
336            TypeKind::Struct(struct_decl) => struct_decl.name(),
337            TypeKind::Class(class_decl) => class_decl.name(),
338            TypeKind::Union(union_decl) => union_decl.name(),
339            TypeKind::Enum(enum_decl) => enum_decl.name(),
340            TypeKind::Typedef(typedef) => Some(typedef.name()),
341            TypeKind::Named(name) => Some(name),
342            _ => None,
343        }
344    }
345
346    pub fn expand_named<'a>(&'a self, types: &'a Types) -> Option<&'a TypeKind> {
347        match self {
348            TypeKind::Named(name) => types.get(name),
349            _ => Some(self),
350        }
351    }
352
353    pub fn is_forward_decl(&self) -> bool {
354        match self {
355            TypeKind::Struct(struct_decl) => struct_decl.is_forward_decl(),
356            TypeKind::Class(class_decl) => class_decl.is_forward_decl(),
357            _ => false,
358        }
359    }
360
361    pub fn as_struct<'a>(&'a self, types: &'a Types) -> Option<&'a StructDecl> {
362        match self {
363            TypeKind::Struct(struct_decl) => Some(struct_decl),
364            TypeKind::Class(class_decl) => Some(class_decl),
365            TypeKind::Named(name) => types.get(name)?.as_struct(types),
366            _ => None,
367        }
368    }
369}
370
371impl Display for TypeKind {
372    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373        match self {
374            TypeKind::USize { size } => write!(f, "usize({size})"),
375            TypeKind::SSize { size } => write!(f, "ssize({size})"),
376            TypeKind::U64 => write!(f, "u64"),
377            TypeKind::U32 => write!(f, "u32"),
378            TypeKind::U16 => write!(f, "u16"),
379            TypeKind::U8 => write!(f, "u8"),
380            TypeKind::S64 => write!(f, "s64"),
381            TypeKind::S32 => write!(f, "s32"),
382            TypeKind::S16 => write!(f, "s16"),
383            TypeKind::S8 => write!(f, "s8"),
384            TypeKind::F32 => write!(f, "f32"),
385            TypeKind::F64 => write!(f, "f64"),
386            TypeKind::LongDouble { size, .. } => write!(f, "long double({size})"),
387            TypeKind::Char16 => write!(f, "char16"),
388            TypeKind::Char32 => write!(f, "char32"),
389            TypeKind::WChar { size } => write!(f, "wchar({size})"),
390            TypeKind::Bool => write!(f, "bool"),
391            TypeKind::Void => write!(f, "void"),
392            TypeKind::Reference { referenced_type, .. } => {
393                write!(f, "{}&", referenced_type)
394            }
395            TypeKind::Pointer { pointee_type, .. } => {
396                write!(f, "{}*", pointee_type)
397            }
398            TypeKind::MemberPointer { pointee_type, record_name, .. } => {
399                write!(f, "{} {}::*", pointee_type, record_name)
400            }
401            TypeKind::Array { element_type, size } => {
402                if let Some(size) = size {
403                    write!(f, "{}[{}]", element_type, size)
404                } else {
405                    write!(f, "{}[]", element_type)
406                }
407            }
408            TypeKind::Function { return_type, parameters } => {
409                let params =
410                    parameters.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(", ");
411                write!(f, "{return_type} function({params})")
412            }
413            TypeKind::Struct(struct_decl) => write!(f, "struct {struct_decl}"),
414            TypeKind::Class(class_decl) => write!(f, "class {class_decl}"),
415            TypeKind::Union(union_decl) => write!(f, "union {union_decl}"),
416            TypeKind::Enum(enum_decl) => write!(f, "enum {enum_decl}"),
417            TypeKind::Typedef(typedef) => write!(f, "{typedef}"),
418            TypeKind::Named(name) => write!(f, "{name}"),
419        }
420    }
421}