diff options
Diffstat (limited to 'loader/cgo.go')
-rw-r--r-- | loader/cgo.go | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/loader/cgo.go b/loader/cgo.go index abb5847c6..dc217f962 100644 --- a/loader/cgo.go +++ b/loader/cgo.go @@ -17,11 +17,12 @@ import ( type fileInfo struct { *ast.File *Package - filename string - functions map[string]*functionInfo - globals map[string]*globalInfo - typedefs map[string]*typedefInfo - importCPos token.Pos + filename string + functions map[string]*functionInfo + globals map[string]*globalInfo + typedefs map[string]*typedefInfo + elaboratedTypes map[string]ast.Expr + importCPos token.Pos } // functionInfo stores some information about a Cgo function found by libclang @@ -81,12 +82,13 @@ typedef unsigned long long _Cgo_ulonglong; // comment with libclang, and modifies the AST to use this information. func (p *Package) processCgo(filename string, f *ast.File, cflags []string) []error { info := &fileInfo{ - File: f, - Package: p, - filename: filename, - functions: map[string]*functionInfo{}, - globals: map[string]*globalInfo{}, - typedefs: map[string]*typedefInfo{}, + File: f, + Package: p, + filename: filename, + functions: map[string]*functionInfo{}, + globals: map[string]*globalInfo{}, + typedefs: map[string]*typedefInfo{}, + elaboratedTypes: map[string]ast.Expr{}, } // Find `import "C"` statements in the file. @@ -142,9 +144,12 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) []er // Forward C types to Go types (like C.uint32_t -> uint32). info.addTypeAliases() - // Add type declarations for C types, declared using typeef in C. + // Add type declarations for C types, declared using typedef in C. info.addTypedefs() + // Add elaborated types for C structs and unions. + info.addElaboratedTypes() + // Patch the AST to use the declared types and functions. f = astutil.Apply(f, info.walker, nil).(*ast.File) @@ -376,6 +381,42 @@ func (info *fileInfo) addTypedefs() { info.Decls = append(info.Decls, gen) } +// addElaboratedTypes adds C elaborated types as aliases. These are the "struct +// foo" or "union foo" types, often used in a typedef. +// +// See also: +// https://en.cppreference.com/w/cpp/language/elaborated_type_specifier +func (info *fileInfo) addElaboratedTypes() { + gen := &ast.GenDecl{ + TokPos: info.importCPos, + Tok: token.TYPE, + } + names := make([]string, 0, len(info.elaboratedTypes)) + for name := range info.elaboratedTypes { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + typ := info.elaboratedTypes[name] + typeName := "C.struct_" + name + obj := &ast.Object{ + Kind: ast.Typ, + Name: typeName, + } + typeSpec := &ast.TypeSpec{ + Name: &ast.Ident{ + NamePos: info.importCPos, + Name: typeName, + Obj: obj, + }, + Type: typ, + } + obj.Decl = typeSpec + gen.Specs = append(gen.Specs, typeSpec) + } + info.Decls = append(info.Decls, gen) +} + // walker replaces all "C".<something> expressions to literal "C.<something>" // expressions. Such expressions are impossible to write in Go (a dot cannot be // used in the middle of a name) so in practice all C identifiers live in a |