Skip to content

Commit fa82c7c

Browse files
committed
docs(claude): add support of non function typedefs
1 parent cbf4aa1 commit fa82c7c

5 files changed

Lines changed: 161 additions & 20 deletions

File tree

parser/README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,20 @@ When a parameter is a function pointer typedef, the complete function signature
216216
}
217217
```
218218

219+
### Parameter or Return Type with Typedef Alias
220+
221+
When a parameter or return type is named via a plain (non-function-pointer) typedef, such as `using MenuId = uint32_t;`, the resolved type is used and the original typedef name (plus its Doxygen description, if any) is preserved in an `alias` structure:
222+
223+
```json
224+
{
225+
"type": "uint32",
226+
"description": "A handle to the created menu.",
227+
"alias": {
228+
"name": "MenuId"
229+
}
230+
}
231+
```
232+
219233
### Field Descriptions
220234

221235
- `name`: Function name
@@ -228,11 +242,13 @@ When a parameter is a function pointer typedef, the complete function signature
228242
- `ref`: Boolean indicating if it's a reference parameter
229243
- `description`: Parameter description from Doxygen comments (if available)
230244
- `enum`: (Optional) Full enum structure if parameter is an enum type
245+
- `alias`: (Optional) `{name, description}` of the typedef if the parameter is named via a plain typedef (e.g. `MenuId`)
231246
- `prototype`: (Optional) Full function signature if parameter is a function pointer typedef
232247
- `retType`: Return type object:
233248
- `type`: Mapped return type
234249
- `description`: Return description from Doxygen comments (if available)
235250
- `enum`: (Optional) Full enum structure if return type is an enum
251+
- `alias`: (Optional) `{name, description}` of the typedef if the return type is named via a plain typedef
236252

237253
## Advanced Features
238254

@@ -282,7 +298,7 @@ The script maps C++ types to simplified types:
282298
| `Vector`, `QAngle`, `plg::vec3` | `vec3` |
283299
| Enums | Base type (e.g., `uint8`, `int32`) + enum structure |
284300
| Function pointer typedefs | `function` + prototype structure |
285-
| Other typedefs | `?` |
301+
| Other typedefs (e.g. `using MenuId = uint32_t;`) | Underlying type (e.g. `uint32`), resolved recursively through typedef chains + alias structure |
286302

287303
Pointers (except `void*`) are mapped to `ptr64`, and unknown types default to `?`.
288304

parser/convert.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import "strings"
55
// convertType converts a type string into its mapped type and reference flag.
66
// Returns (mappedType, isReference), mirroring parser.py's convert_type().
77
func convertType(typeStr string, enumsMap map[string]EnumInfo, typedefsMap map[string]TypedefInfo) (string, bool) {
8+
return convertTypeSeen(typeStr, enumsMap, typedefsMap, map[string]bool{})
9+
}
10+
11+
func convertTypeSeen(typeStr string, enumsMap map[string]EnumInfo, typedefsMap map[string]TypedefInfo, seen map[string]bool) (string, bool) {
812
if typeStr == "" {
913
return "?", false
1014
}
@@ -40,6 +44,11 @@ func convertType(typeStr string, enumsMap map[string]EnumInfo, typedefsMap map[s
4044
return mapped, !constFlag
4145
}
4246

47+
// Check if it's a (non-function-pointer) typedef; resolve to its underlying type
48+
if mapped, ok := resolveTypedefBase(baseType, enumsMap, typedefsMap, seen); ok {
49+
return mapped, !constFlag
50+
}
51+
4352
return mapType(baseType), !constFlag
4453
}
4554

@@ -52,9 +61,31 @@ func convertType(typeStr string, enumsMap map[string]EnumInfo, typedefsMap map[s
5261
return mapped, false
5362
}
5463

64+
// Check if it's a (non-function-pointer) typedef; resolve to its underlying type
65+
if mapped, ok := resolveTypedefBase(t, enumsMap, typedefsMap, seen); ok {
66+
return mapped, false
67+
}
68+
5569
return mapType(t), false
5670
}
5771

72+
// resolveTypedefBase resolves t as a plain (non-function-pointer) typedef name to
73+
// its underlying mapped type, following typedef chains recursively. Function-pointer
74+
// typedefs are left alone here - callers handle those separately by emitting a
75+
// "function" type with a prototype. ok is false when t is not such a typedef.
76+
func resolveTypedefBase(t string, enumsMap map[string]EnumInfo, typedefsMap map[string]TypedefInfo, seen map[string]bool) (string, bool) {
77+
td, ok := typedefsMap[t]
78+
if !ok || td.IsFunctionPointer {
79+
return "", false
80+
}
81+
if seen[t] {
82+
return "?", true
83+
}
84+
seen[t] = true
85+
mapped, _ := convertTypeSeen(td.Underlying, enumsMap, typedefsMap, seen)
86+
return mapped, true
87+
}
88+
5889
// stripTypeQualifiers strips const/&/* substrings from a type name, mirroring
5990
// param_type_name.replace('const', ”).replace('&', ”).replace('*', ”).strip().
6091
func stripTypeQualifiers(s string) string {

parser/function.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Param struct {
1212
Ref bool `json:"ref"`
1313
Description string `json:"description,omitempty"`
1414
Enum *EnumStruct `json:"enum,omitempty"`
15+
Alias *AliasStruct `json:"alias,omitempty"`
1516
Prototype *FunctionPrototype `json:"prototype,omitempty"`
1617
}
1718

@@ -20,6 +21,7 @@ type RetType struct {
2021
Type string `json:"type"`
2122
Description string `json:"description,omitempty"`
2223
Enum *EnumStruct `json:"enum,omitempty"`
24+
Alias *AliasStruct `json:"alias,omitempty"`
2325
Prototype *FunctionPrototype `json:"prototype,omitempty"`
2426
}
2527

@@ -104,10 +106,14 @@ func processFunction(function map[string]interface{}, enumsMap map[string]EnumIn
104106
if es := buildEnumStructure(baseTypeName, enumsMap); es != nil {
105107
paramData.Enum = es
106108
}
107-
} else if td, ok := typedefsMap[baseTypeName]; ok && td.IsFunctionPointer {
108-
paramData.Type = "function"
109-
if proto := buildFunctionPrototype(baseTypeName, typedefsMap, enumsMap); proto != nil {
110-
paramData.Prototype = proto
109+
} else if td, ok := typedefsMap[baseTypeName]; ok {
110+
if td.IsFunctionPointer {
111+
paramData.Type = "function"
112+
if proto := buildFunctionPrototype(baseTypeName, typedefsMap, enumsMap); proto != nil {
113+
paramData.Prototype = proto
114+
}
115+
} else if alias := buildAliasStructure(baseTypeName, typedefsMap); alias != nil {
116+
paramData.Alias = alias
111117
}
112118
}
113119

@@ -132,10 +138,14 @@ func processFunction(function map[string]interface{}, enumsMap map[string]EnumIn
132138
if es := buildEnumStructure(baseReturnType, enumsMap); es != nil {
133139
retType.Enum = es
134140
}
135-
} else if td, ok := typedefsMap[baseReturnType]; ok && td.IsFunctionPointer {
136-
retType.Type = "function"
137-
if proto := buildFunctionPrototype(baseReturnType, typedefsMap, enumsMap); proto != nil {
138-
retType.Prototype = proto
141+
} else if td, ok := typedefsMap[baseReturnType]; ok {
142+
if td.IsFunctionPointer {
143+
retType.Type = "function"
144+
if proto := buildFunctionPrototype(baseReturnType, typedefsMap, enumsMap); proto != nil {
145+
retType.Prototype = proto
146+
}
147+
} else if alias := buildAliasStructure(baseReturnType, typedefsMap); alias != nil {
148+
retType.Alias = alias
139149
}
140150
}
141151

parser/parser.py

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,35 @@ def map_type(t: str):
149149
return switch_dict.get(t, '?')
150150

151151

152-
def convert_type(type_str: str, enums_map: dict, typedefs_map: dict):
152+
def resolve_typedef_base(t: str, enums_map: dict, typedefs_map: dict, seen: set):
153+
"""
154+
Resolve t as a plain (non-function-pointer) typedef name to its underlying
155+
mapped type, following typedef chains recursively. Function-pointer typedefs
156+
are left alone here - callers handle those separately by emitting a
157+
"function" type with a prototype. Returns (mapped_type, True) if t is such a
158+
typedef, or (None, False) otherwise.
159+
"""
160+
typedef_info = typedefs_map.get(t)
161+
if not typedef_info or typedef_info.get('IsFunctionPointer'):
162+
return None, False
163+
if t in seen:
164+
return '?', True
165+
seen.add(t)
166+
mapped, _ = convert_type(typedef_info.get('Underlying', ''), enums_map, typedefs_map, seen)
167+
return mapped, True
168+
169+
170+
def convert_type(type_str: str, enums_map: dict, typedefs_map: dict, seen: set = None):
153171
"""
154172
Convert type string into its mapped type and reference flag.
155173
Returns (mapped_type, is_reference)
156174
"""
157175
if not type_str:
158176
return '?', False
159177

178+
if seen is None:
179+
seen = set()
180+
160181
const = False
161182
t = type_str.strip()
162183

@@ -181,19 +202,21 @@ def convert_type(type_str: str, enums_map: dict, typedefs_map: dict):
181202
mapped = enums_map[base_type].get('BaseType', '?')
182203
return mapped, not const
183204

184-
# Check if it's a typedef
185-
#if base_type in typedefs_map:
186-
# return '?', not const # Typedefs usually stay as '?'
205+
# Check if it's a typedef; resolve to its underlying type
206+
mapped, is_typedef = resolve_typedef_base(base_type, enums_map, typedefs_map, seen)
207+
if is_typedef:
208+
return mapped, not const
187209

188210
return map_type(base_type), not const
189211

190212
# Check if it's an enum
191213
if t in enums_map:
192214
return enums_map[t].get('BaseType', '?'), False
193215

194-
# Check if it's a typedef
195-
#if t in typedefs_map:
196-
# return '?', False # Typedefs usually stay as '?'
216+
# Check if it's a typedef; resolve to its underlying type
217+
mapped, is_typedef = resolve_typedef_base(t, enums_map, typedefs_map, seen)
218+
if is_typedef:
219+
return mapped, False
197220

198221
return map_type(t), False
199222

@@ -506,6 +529,19 @@ def build_enum_structure(enum_name: str, enums_map: dict, filter_sentinel_values
506529
return enum_struct
507530

508531

532+
def build_alias_structure(typedef_name: str, typedefs_map: dict):
533+
"""Build alias structure for a resolved, non-function-pointer typedef."""
534+
typedef_info = typedefs_map.get(typedef_name)
535+
if not typedef_info or typedef_info.get('IsFunctionPointer'):
536+
return None
537+
538+
alias_struct = {'name': typedef_name}
539+
if typedef_info.get('Description'):
540+
alias_struct['description'] = typedef_info['Description']
541+
542+
return alias_struct
543+
544+
509545
def build_function_prototype(typedef_name: str, typedefs_map: dict, enums_map: dict):
510546
"""Build function prototype structure for function pointer typedefs."""
511547
if typedef_name not in typedefs_map:
@@ -549,6 +585,10 @@ def build_function_prototype(typedef_name: str, typedefs_map: dict, enums_map: d
549585
enum_struct = build_enum_structure(base_type_name, enums_map)
550586
if enum_struct:
551587
param_data['enum'] = enum_struct
588+
else:
589+
alias_struct = build_alias_structure(base_type_name, typedefs_map)
590+
if alias_struct:
591+
param_data['alias'] = alias_struct
552592

553593
param_types_list.append(param_data)
554594

@@ -576,6 +616,12 @@ def build_function_prototype(typedef_name: str, typedefs_map: dict, enums_map: d
576616
if prototype:
577617
ret_type['prototype'] = prototype
578618

619+
# Check if return type is a plain typedef and add alias structure
620+
elif base_return_type in typedefs_map:
621+
alias_struct = build_alias_structure(base_return_type, typedefs_map)
622+
if alias_struct:
623+
ret_type['alias'] = alias_struct
624+
579625
prototype['retType'] = ret_type
580626

581627
return prototype
@@ -645,6 +691,12 @@ def process_function(function, enums_map, typedefs_map, group_name=None):
645691
if prototype:
646692
param_data['prototype'] = prototype
647693

694+
# Check if parameter is a plain typedef and add alias structure
695+
elif base_type_name in typedefs_map:
696+
alias_struct = build_alias_structure(base_type_name, typedefs_map)
697+
if alias_struct:
698+
param_data['alias'] = alias_struct
699+
648700
param_types.append(param_data)
649701

650702
# Process return type
@@ -673,6 +725,12 @@ def process_function(function, enums_map, typedefs_map, group_name=None):
673725
if prototype:
674726
ret_type['prototype'] = prototype
675727

728+
# Check if return type is a plain typedef and add alias structure
729+
elif base_return_type in typedefs_map:
730+
alias_struct = build_alias_structure(base_return_type, typedefs_map)
731+
if alias_struct:
732+
ret_type['alias'] = alias_struct
733+
676734
# Build final function data
677735
function_data = {
678736
'name': func_name,

parser/typedefs.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ type TypedefInfo struct {
1616
ParamTypes []string
1717
}
1818

19+
// AliasStruct records that a parameter/return type was named via a plain
20+
// (non-function-pointer) typedef, embedded into a Param or RetType.
21+
type AliasStruct struct {
22+
Name string `json:"name"`
23+
Description string `json:"description,omitempty"`
24+
}
25+
26+
// buildAliasStructure builds an alias structure for a resolved, non-function-pointer typedef.
27+
func buildAliasStructure(typedefName string, typedefsMap map[string]TypedefInfo) *AliasStruct {
28+
td, ok := typedefsMap[typedefName]
29+
if !ok || td.IsFunctionPointer {
30+
return nil
31+
}
32+
alias := &AliasStruct{Name: typedefName}
33+
if td.Description != "" {
34+
alias.Description = td.Description
35+
}
36+
return alias
37+
}
38+
1939
var fnPtrReturnTypeRe = regexp.MustCompile(`^\s*(.+?)\s*\(\*\)`)
2040

2141
// parseFunctionPointerSignature parses a function pointer signature string, e.g.
@@ -139,6 +159,8 @@ func buildFunctionPrototype(typedefName string, typedefsMap map[string]TypedefIn
139159
if es := buildEnumStructure(baseTypeName, enumsMap); es != nil {
140160
paramData.Enum = es
141161
}
162+
} else if alias := buildAliasStructure(baseTypeName, typedefsMap); alias != nil {
163+
paramData.Alias = alias
142164
}
143165

144166
paramTypesList = append(paramTypesList, paramData)
@@ -155,10 +177,14 @@ func buildFunctionPrototype(typedefName string, typedefsMap map[string]TypedefIn
155177
if es := buildEnumStructure(baseReturnType, enumsMap); es != nil {
156178
retType.Enum = es
157179
}
158-
} else if td, ok := typedefsMap[baseReturnType]; ok && td.IsFunctionPointer {
159-
retType.Type = "function"
160-
if p := buildFunctionPrototype(baseReturnType, typedefsMap, enumsMap); p != nil {
161-
retType.Prototype = p
180+
} else if td, ok := typedefsMap[baseReturnType]; ok {
181+
if td.IsFunctionPointer {
182+
retType.Type = "function"
183+
if p := buildFunctionPrototype(baseReturnType, typedefsMap, enumsMap); p != nil {
184+
retType.Prototype = p
185+
}
186+
} else if alias := buildAliasStructure(baseReturnType, typedefsMap); alias != nil {
187+
retType.Alias = alias
162188
}
163189
}
164190
proto.RetType = retType

0 commit comments

Comments
 (0)