diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index b2fd4bc9..4641f73e 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -342,6 +342,16 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error { } } + // Fixups + // QDataStream.operator<< return a reference to QDataStream, but have a private + // copy constructor + // The bindings don't know it's the same object. This is just a trick for a more + // ergonomic C++ API but has no real effect + // Wipe out + if (mm.MethodName == "operator<<" || mm.MethodName == "operator>>" || mm.MethodName == "writeBytes") && mm.ReturnType.ParameterType == "QDataStream" && mm.ReturnType.ByRef { + mm.ReturnType = CppParameter{ParameterType: "void"} + } + return nil } @@ -371,6 +381,16 @@ func parseTypeString(typeString string) (CppParameter, []CppParameter, error) { returnType := parseSingleTypeString(strings.TrimSpace(typeString[0:opos])) + // Skip functions that return ints-by-reference since the ergonomics don't + // go through the binding + if returnType.IntType() && returnType.ByRef { + return CppParameter{}, nil, ErrTooComplex // e.g. QSize::rheight() + } + + if returnType.QMapOf() { + return CppParameter{}, nil, ErrTooComplex // e.g. QVariant constructor + } + inner := typeString[opos+1 : epos] // Should be no more brackets @@ -386,6 +406,25 @@ func parseTypeString(typeString string) (CppParameter, []CppParameter, error) { insert := parseSingleTypeString(p) + if insert.QMapOf() { + return CppParameter{}, nil, ErrTooComplex // Example??? + } + if insert.ParameterType == "QList" { + return CppParameter{}, nil, ErrTooComplex // e.g. QVariant constructor - this has a deleted copy-constructor so we can't get it over the CABI boundary by value + } + if insert.ParameterType == "void **" { + return CppParameter{}, nil, ErrTooComplex // e.g. qobjectdefs.h QMetaObject->Activate() + } + if insert.ParameterType == "void" && insert.Pointer { + return CppParameter{}, nil, ErrTooComplex // e.g. qobjectdefs.h QMetaObject->InvokeOnGadget() + } + if insert.ParameterType == "char *&" { + return CppParameter{}, nil, ErrTooComplex // e.g. QDataStream.operator<<() + } + if insert.ParameterType == "qfloat16" { + return CppParameter{}, nil, ErrTooComplex // e.g. QDataStream - there is no such half-float type in C or Go + } + if insert.ParameterType != "" { ret = append(ret, insert) } @@ -399,8 +438,13 @@ func parseSingleTypeString(p string) CppParameter { tokens := strings.Split(strings.TrimSpace(p), " ") insert := CppParameter{} for _, tok := range tokens { - if tok == "const" { + if tok == "" { + continue // extra space + } else if tok == "const" || tok == "*const" { + // *const happens for QPixmap, clang reports `const char *const *` which + // isn't even valid syntax insert.Const = true + } else if tok == "&" { // U+0026 insert.ByRef = true } else if tok == "*" { diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index e0119df3..ead75dd9 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -334,6 +334,9 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { if ref[0] != 'Q' { continue } + if ref == "QPlatformPixmap" { + continue // This class doesn't have a <> version to include + } ret.WriteString(`#include <` + ref + ">\n") } diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 1a35e65b..0f947a35 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -1,6 +1,7 @@ package main import ( + "C" "go/format" "log" "sort" @@ -236,7 +237,7 @@ import "C" shouldReturn := "return " afterword := "" - returnTypeDecl := m.ReturnType.ParameterType // FIXME handle byRef/const here too + returnTypeDecl := m.ReturnType.RenderTypeGo() // FIXME handle byRef/const here too if m.ReturnType.ParameterType == "void" && !m.ReturnType.Pointer { shouldReturn = "" @@ -245,6 +246,13 @@ import "C" } else if m.ReturnType.ParameterType == "void" && m.ReturnType.Pointer { returnTypeDecl = "interface{}" + } else if m.ReturnType.ParameterType == "char" && m.ReturnType.Pointer { + // Qt functions normally return QString - anything returning char* + // is something like QByteArray.Data() where it returns an unsafe + // internal pointer + imports["unsafe"] = struct{}{} + returnTypeDecl = "unsafe.Pointer" + } else if m.ReturnType.ParameterType == "QString" { shouldReturn = "" returnTypeDecl = "string" diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index 01a49053..b59bfbb1 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -25,6 +25,11 @@ func (p CppParameter) QListOf() (CppParameter, bool) { return CppParameter{}, false } +func (p CppParameter) QMapOf() bool { + return strings.HasPrefix(p.ParameterType, `QMap<`) || + strings.HasPrefix(p.ParameterType, `QHash<`) // TODO support this +} + func (p CppParameter) IntType() bool { switch p.ParameterType { case "int", "unsigned int", "uint",