use sigmd::model::{Type, TypeKind};
use super::{BuildContext, clang};
pub fn build_type(ty: clang::Type<'_>, ctx: &BuildContext) -> Type {
let mut current = ty.get_canonical_type();
let mut indirections = 0u8;
while is_pointer_kind(current.get_kind()) {
indirections = indirections.saturating_add(1);
match current.get_pointee_type() {
Some(pointee) => current = pointee.get_canonical_type(),
None => break,
}
}
let raw_name = current.get_display_name();
let name = strip_modifiers(&raw_name).to_string();
let kind = ctx
.parse_custom_type(&name)
.map_or_else(|| leaf_kind(current.get_kind()), TypeKind::Custom);
Type {
indirections,
name,
kind,
}
}
fn is_pointer_kind(kind: clang::TypeKind) -> bool {
matches!(
kind,
clang::TypeKind::Pointer
| clang::TypeKind::LValueReference
| clang::TypeKind::RValueReference,
)
}
fn leaf_kind(kind: clang::TypeKind) -> TypeKind {
match kind {
clang::TypeKind::Void => TypeKind::Void,
clang::TypeKind::Bool => TypeKind::Bool,
clang::TypeKind::CharS | clang::TypeKind::CharU => TypeKind::Char8,
clang::TypeKind::WChar => TypeKind::Char16,
clang::TypeKind::SChar => TypeKind::I8,
clang::TypeKind::Short => TypeKind::I16,
clang::TypeKind::Int | clang::TypeKind::Long => TypeKind::I32,
clang::TypeKind::LongLong => TypeKind::I64,
clang::TypeKind::UChar => TypeKind::U8,
clang::TypeKind::UShort => TypeKind::U16,
clang::TypeKind::UInt | clang::TypeKind::ULong => TypeKind::U32,
clang::TypeKind::ULongLong => TypeKind::U64,
clang::TypeKind::Float => TypeKind::F32,
clang::TypeKind::Double => TypeKind::F64,
clang::TypeKind::Enum => TypeKind::I32,
_ => TypeKind::Unknown,
}
}
pub fn strip_modifiers(name: &str) -> &str {
let name = name.strip_prefix("const ").unwrap_or(name);
let name = name.strip_prefix("enum ").unwrap_or(name);
let name = name.strip_prefix("struct ").unwrap_or(name);
let name = name.strip_prefix("union ").unwrap_or(name);
let name = name.strip_prefix("class ").unwrap_or(name);
name.strip_suffix(" const").unwrap_or(name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strip_modifiers_removes_prefixes_and_suffix() {
assert_eq!(strip_modifiers("DWORD"), "DWORD");
assert_eq!(strip_modifiers("const DWORD"), "DWORD");
assert_eq!(strip_modifiers("struct _UNICODE_STRING"), "_UNICODE_STRING");
assert_eq!(strip_modifiers("enum FOO"), "FOO");
assert_eq!(strip_modifiers("DWORD const"), "DWORD");
assert_eq!(strip_modifiers("const struct X"), "X");
}
}