genbindings: add many more ErrTooComplex and workarounds

This commit is contained in:
mappu 2024-08-15 19:53:01 +12:00
parent 3dafa8dba4
commit a87e7a99a7
4 changed files with 62 additions and 2 deletions

View File

@ -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 return nil
} }
@ -371,6 +381,16 @@ func parseTypeString(typeString string) (CppParameter, []CppParameter, error) {
returnType := parseSingleTypeString(strings.TrimSpace(typeString[0:opos])) 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] inner := typeString[opos+1 : epos]
// Should be no more brackets // Should be no more brackets
@ -386,6 +406,25 @@ func parseTypeString(typeString string) (CppParameter, []CppParameter, error) {
insert := parseSingleTypeString(p) insert := parseSingleTypeString(p)
if insert.QMapOf() {
return CppParameter{}, nil, ErrTooComplex // Example???
}
if insert.ParameterType == "QList<QVariant>" {
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 != "" { if insert.ParameterType != "" {
ret = append(ret, insert) ret = append(ret, insert)
} }
@ -399,8 +438,13 @@ func parseSingleTypeString(p string) CppParameter {
tokens := strings.Split(strings.TrimSpace(p), " ") tokens := strings.Split(strings.TrimSpace(p), " ")
insert := CppParameter{} insert := CppParameter{}
for _, tok := range tokens { 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 insert.Const = true
} else if tok == "&" { // U+0026 } else if tok == "&" { // U+0026
insert.ByRef = true insert.ByRef = true
} else if tok == "*" { } else if tok == "*" {

View File

@ -334,6 +334,9 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
if ref[0] != 'Q' { if ref[0] != 'Q' {
continue continue
} }
if ref == "QPlatformPixmap" {
continue // This class doesn't have a <> version to include
}
ret.WriteString(`#include <` + ref + ">\n") ret.WriteString(`#include <` + ref + ">\n")
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"C"
"go/format" "go/format"
"log" "log"
"sort" "sort"
@ -236,7 +237,7 @@ import "C"
shouldReturn := "return " shouldReturn := "return "
afterword := "" 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 { if m.ReturnType.ParameterType == "void" && !m.ReturnType.Pointer {
shouldReturn = "" shouldReturn = ""
@ -245,6 +246,13 @@ import "C"
} else if m.ReturnType.ParameterType == "void" && m.ReturnType.Pointer { } else if m.ReturnType.ParameterType == "void" && m.ReturnType.Pointer {
returnTypeDecl = "interface{}" 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" { } else if m.ReturnType.ParameterType == "QString" {
shouldReturn = "" shouldReturn = ""
returnTypeDecl = "string" returnTypeDecl = "string"

View File

@ -25,6 +25,11 @@ func (p CppParameter) QListOf() (CppParameter, bool) {
return CppParameter{}, false 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 { func (p CppParameter) IntType() bool {
switch p.ParameterType { switch p.ParameterType {
case "int", "unsigned int", "uint", case "int", "unsigned int", "uint",