@@ -17,11 +17,12 @@ import (
1717type fileInfo struct {
1818 * ast.File
1919 * Package
20- filename string
21- functions map [string ]* functionInfo
22- globals map [string ]* globalInfo
23- typedefs map [string ]* typedefInfo
24- importCPos token.Pos
20+ filename string
21+ functions map [string ]* functionInfo
22+ globals map [string ]* globalInfo
23+ typedefs map [string ]* typedefInfo
24+ elaboratedTypes map [string ]ast.Expr
25+ importCPos token.Pos
2526}
2627
2728// functionInfo stores some information about a Cgo function found by libclang
@@ -81,12 +82,13 @@ typedef unsigned long long _Cgo_ulonglong;
8182// comment with libclang, and modifies the AST to use this information.
8283func (p * Package ) processCgo (filename string , f * ast.File , cflags []string ) []error {
8384 info := & fileInfo {
84- File : f ,
85- Package : p ,
86- filename : filename ,
87- functions : map [string ]* functionInfo {},
88- globals : map [string ]* globalInfo {},
89- typedefs : map [string ]* typedefInfo {},
85+ File : f ,
86+ Package : p ,
87+ filename : filename ,
88+ functions : map [string ]* functionInfo {},
89+ globals : map [string ]* globalInfo {},
90+ typedefs : map [string ]* typedefInfo {},
91+ elaboratedTypes : map [string ]ast.Expr {},
9092 }
9193
9294 // Find `import "C"` statements in the file.
@@ -142,9 +144,12 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) []er
142144 // Forward C types to Go types (like C.uint32_t -> uint32).
143145 info .addTypeAliases ()
144146
145- // Add type declarations for C types, declared using typeef in C.
147+ // Add type declarations for C types, declared using typedef in C.
146148 info .addTypedefs ()
147149
150+ // Add elaborated types for C structs and unions.
151+ info .addElaboratedTypes ()
152+
148153 // Patch the AST to use the declared types and functions.
149154 f = astutil .Apply (f , info .walker , nil ).(* ast.File )
150155
@@ -376,6 +381,42 @@ func (info *fileInfo) addTypedefs() {
376381 info .Decls = append (info .Decls , gen )
377382}
378383
384+ // addElaboratedTypes adds C elaborated types as aliases. These are the "struct
385+ // foo" or "union foo" types, often used in a typedef.
386+ //
387+ // See also:
388+ // https://en.cppreference.com/w/cpp/language/elaborated_type_specifier
389+ func (info * fileInfo ) addElaboratedTypes () {
390+ gen := & ast.GenDecl {
391+ TokPos : info .importCPos ,
392+ Tok : token .TYPE ,
393+ }
394+ names := make ([]string , 0 , len (info .elaboratedTypes ))
395+ for name := range info .elaboratedTypes {
396+ names = append (names , name )
397+ }
398+ sort .Strings (names )
399+ for _ , name := range names {
400+ typ := info .elaboratedTypes [name ]
401+ typeName := "C.struct_" + name
402+ obj := & ast.Object {
403+ Kind : ast .Typ ,
404+ Name : typeName ,
405+ }
406+ typeSpec := & ast.TypeSpec {
407+ Name : & ast.Ident {
408+ NamePos : info .importCPos ,
409+ Name : typeName ,
410+ Obj : obj ,
411+ },
412+ Type : typ ,
413+ }
414+ obj .Decl = typeSpec
415+ gen .Specs = append (gen .Specs , typeSpec )
416+ }
417+ info .Decls = append (info .Decls , gen )
418+ }
419+
379420// walker replaces all "C".<something> expressions to literal "C.<something>"
380421// expressions. Such expressions are impossible to write in Go (a dot cannot be
381422// used in the middle of a name) so in practice all C identifiers live in a
0 commit comments