diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index 3b3477ce..6e01bd70 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -548,7 +548,7 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error { return nil } -// parseTypeString converts a string like +// parseTypeString converts a function/method type string such as // - `QString (const char *, const char *, int)` // - `void (const QKeySequence \u0026)` // into its (A) return type and (B) separate parameter types. diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index c4f71f1b..e71beacb 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -7,10 +7,12 @@ import ( var ( KnownClassnames map[string]struct{} // Entries of the form QFoo::Bar if it is an inner class + KnownTypedefs map[string]CppTypedef ) func init() { KnownClassnames = make(map[string]struct{}) + KnownTypedefs = make(map[string]CppTypedef) } type CppParameter struct { @@ -23,6 +25,20 @@ type CppParameter struct { Optional bool } +func (p *CppParameter) AssignAlias(newType string) { + if p.TypeAlias == "" { + p.TypeAlias = p.ParameterType // Overwrite once only, at the earliest base type + } + p.ParameterType = newType +} + +func (p *CppParameter) CopyWithAlias(alias CppParameter) CppParameter { + ret := *p // copy + ret.ParameterName = alias.ParameterName + ret.TypeAlias = alias.ParameterType + return ret +} + func (p *CppParameter) UnderlyingType() string { if p.TypeAlias != "" { return p.TypeAlias @@ -221,7 +237,7 @@ type CppClass struct { type CppTypedef struct { Alias string - UnderlyingType string + UnderlyingType CppParameter } type CppParsedHeader struct { diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index bfc7e32b..90ce6e4b 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -141,6 +141,10 @@ func main() { for _, c := range parsed.Classes { KnownClassnames[c.ClassName] = struct{}{} } + for _, td := range parsed.Typedefs { + KnownTypedefs[td.Alias] = td // copy + } + processHeaders = append(processHeaders, parsed) } @@ -151,6 +155,10 @@ func main() { for _, parsed := range processHeaders { log.Printf("Processing %q...", parsed.Filename) + + // More AST transforms on our IL + astTransformTypedefs(parsed) + { // Save the IL file for debug inspection jb, err := json.MarshalIndent(parsed, "", "\t") diff --git a/cmd/genbindings/transformchildclasses.go b/cmd/genbindings/transformchildclasses.go index 514ac1c6..1942b590 100644 --- a/cmd/genbindings/transformchildclasses.go +++ b/cmd/genbindings/transformchildclasses.go @@ -23,9 +23,14 @@ func takeChildren(c *CppClass) []CppClass { func astTransformChildClasses(parsed *CppParsedHeader) { var taken []CppClass - for i, _ := range parsed.Classes { + for i, c := range parsed.Classes { taken = append(taken, takeChildren(&parsed.Classes[i])...) + + // Also lift all child typedefs and enums + parsed.Typedefs = append(parsed.Typedefs, c.ChildTypedefs...) + parsed.Enums = append(parsed.Enums, c.ChildEnums...) } parsed.Classes = append(parsed.Classes, taken...) + } diff --git a/cmd/genbindings/transformtypedefs.go b/cmd/genbindings/transformtypedefs.go new file mode 100644 index 00000000..75e49451 --- /dev/null +++ b/cmd/genbindings/transformtypedefs.go @@ -0,0 +1,55 @@ +package main + +/* +func typedefUnderlyingOrInt(td CppTypedef) string { + if strings.HasPrefix(td.UnderlyingType.ParameterType, "QFlag<") { + return "int" + } + + if strings.HasPrefix(td.UnderlyingType.ParameterType, "signed ") { + return td.UnderlyingType.ParameterType[7:] + } + + if strings.Contains(td.UnderlyingType.ParameterType, "(*)") { + return "uintptr" // Function pointer, nonrepresentible + } + + return td.UnderlyingType.ParameterType +} +*/ + +// astTransformTypedefs replaces the ParameterType with any known typedef value. +func astTransformTypedefs(parsed *CppParsedHeader) { + + for i, c := range parsed.Classes { + + for j, m := range c.Methods { + + for k, p := range m.Parameters { + if td, ok := KnownTypedefs[p.ParameterType]; ok { + p = td.UnderlyingType.CopyWithAlias(p) + } + m.Parameters[k] = p + } + + if td, ok := KnownTypedefs[m.ReturnType.ParameterType]; ok { + m.ReturnType = td.UnderlyingType.CopyWithAlias(m.ReturnType) + //m.ReturnType.AssignAlias(typedefUnderlyingOrInt(td)) + } + c.Methods[j] = m + } + + for j, m := range c.Ctors { + + for k, p := range m.Parameters { + if td, ok := KnownTypedefs[p.ParameterType]; ok { + p = td.UnderlyingType.CopyWithAlias(p) // .AssignAlias(typedefUnderlyingOrInt(td)) + } + m.Parameters[k] = p + } + + c.Ctors[j] = m + } + parsed.Classes[i] = c + } +} diff --git a/cmd/genbindings/transformtypedefs_test.go b/cmd/genbindings/transformtypedefs_test.go new file mode 100644 index 00000000..9dd7084a --- /dev/null +++ b/cmd/genbindings/transformtypedefs_test.go @@ -0,0 +1,45 @@ +package main + +import ( + "testing" +) + +func TestTransformTypedefs(t *testing.T) { + // Test that the static typedefs are applied + + makeTest := func(typeName string) CppParsedHeader { + return CppParsedHeader{ + Classes: []CppClass{ + + CppClass{ + ClassName: "QTestClass", + Ctors: []CppMethod{ + + CppMethod{ + Parameters: []CppParameter{ + CppParameter{ + ParameterName: "foo", + ParameterType: typeName, + }, + }, + IsStatic: true, + }, + }, + }, + }, + } + + } + + // t.Logf("Existing typedefs: %#v\n", KnownTypedefs) + + parsed := makeTest("WId") + + astTransformTypedefs(&parsed) + + got := parsed.Classes[0].Ctors[0].Parameters[0].ParameterType + expect := "uintptr_t" + if got != expect { + t.Errorf("Transform of WId got %q, expected %q", got, expect) + } +}