1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use super::*;
#[derive(Debug)]
pub struct Typedef {
pub name: String,
pub ty: metadata::Type,
}
impl Typedef {
/// Prefer `PFOO -> *mut FOO` over an equivalent pointer through another alias.
pub fn is_direct_pointer_alias(&self) -> bool {
let Some(target) = self.name.strip_prefix('P') else {
return false;
};
let pointee = match &self.ty {
metadata::Type::PtrMut(ty, 1) | metadata::Type::PtrConst(ty, 1) => ty.as_ref(),
_ => return false,
};
match pointee {
metadata::Type::ClassName(name) | metadata::Type::ValueName(name) => {
name.name == target
}
_ => false,
}
}
pub fn parse(cursor: Cursor, parser: &mut Parser<'_>) -> Result<Option<Self>, Error> {
let name = cursor.name();
let underlying = cursor.typedef_underlying_type();
// The enum/flags merge emits the public name with this typedef's storage type.
if parser.enum_merge.contains_key(&name) {
return Ok(None);
}
// GUID synonyms collapse to `GUID` at reference sites.
if guid_alias(&name) {
return Ok(None);
}
// Generic void-pointer aliases collapse at reference sites; handles stay named.
if void_pointer_alias(&name).is_some() {
return Ok(None);
}
// Flat Win32 scrapes collapse Direct2D 1.1 compatibility aliases to `D2D_*`.
if parser.header_root.is_some() && d2d_compat_alias(&name).is_some() {
return Ok(None);
}
// Flat Win32 scrapes keep only the canonical string-pointer wrappers. Namespaced
// scrapes must keep local `LP*` aliases because their references are not normalized.
if parser.header_root.is_some()
&& let Some(canonical) = string_alias_canonical(&name)
&& canonical != name
{
return Ok(None);
}
// Flat Win32 scrapes collapse curated portability/ABI aliases to primitives; keeping
// pointer-sized aliases named would create false per-arch width splits.
if parser.header_root.is_some()
&& (fundamental_scalar(&name).is_some() || pointer_sized_abi(&name).is_some())
{
return Ok(None);
}
// Semantic scalar aliases such as `BOOLEAN` collapse to primitives.
if parser.header_root.is_some() && semantic_scalar(&name).is_some() {
return Ok(None);
}
// Floating typedefs all collapse by canonical kind to `f32`/`f64`.
if parser.header_root.is_some() && floating_typedef(&underlying).is_some() {
return Ok(None);
}
// Flat Win32 scrapes collapse COM interface pointer aliases to the interface type.
if parser.header_root.is_some() && is_interface_alias(&underlying) {
return Ok(None);
}
// Skip self-aliases, but preserve secondary record aliases in per-header mode.
let elaborated = underlying.kind() == CXType_Elaborated;
let inner_kind = if elaborated {
underlying.underlying_type().kind()
} else {
underlying.kind()
};
if matches!(inner_kind, CXType_Record | CXType_Enum) {
let inner = if elaborated {
underlying.underlying_type()
} else {
underlying
};
let tag = inner.ty().name();
if parser.header_root.is_none() || is_anonymous_name(&tag) {
// Legacy mode or an anonymous tag already emitted under this typedef name.
return Ok(None);
}
let public = parser
.tag_rename
.get(&tag)
.cloned()
.unwrap_or_else(|| tag.clone());
if name == public
|| (name == tag
&& inner_kind == CXType_Enum
&& parser.enum_merge.contains_key(&public))
{
// The record/enum is already emitted under this public name.
return Ok(None);
}
let ty = inner.to_type(parser);
return Ok(Some(Self { name, ty }));
}
// Variadic function-pointer typedefs cannot be metadata callbacks; keep an opaque alias.
if underlying.is_function_pointer() {
if let Some(fn_ty) = underlying.function_pointee()
&& fn_ty.is_variadic()
{
let ty = underlying.to_type(parser);
return Ok(Some(Self { name, ty }));
}
return Ok(None);
}
// `DECLARE_HANDLE` emits an opaque handle rather than a one-off empty tag pointer.
if underlying.is_handle_tag(&name) {
let ty = metadata::Type::PtrMut(Box::new(metadata::Type::Void), 1);
return Ok(Some(Self { name, ty }));
}
let ty = underlying.to_type(parser);
// Base pointer-sized ABI typedefs become `usize`/`isize`; chained aliases inherit.
let ty = match (pointer_sized_abi(&name), &ty) {
(Some(scalar), metadata::Type::U64 | metadata::Type::I64) => scalar,
_ => ty,
};
Ok(Some(Self { name, ty }))
}
pub fn write(&self, namespace: &str) -> Result<TokenStream, Error> {
let name = write_ident(&self.name);
let ty = write_type(namespace, &self.ty);
Ok(quote! {
type #name = #ty;
})
}
}