mirror of
https://github.com/mappu/miqt.git
synced 2025-02-08 22:10:23 +00:00
genbindings: generate bindings for protected methods
This commit is contained in:
parent
73c30809d2
commit
c1bf148a5a
@ -464,12 +464,20 @@ nextMethod:
|
|||||||
mm.IsSignal = isSignal && !mm.IsStatic && AllowSignal(mm)
|
mm.IsSignal = isSignal && !mm.IsStatic && AllowSignal(mm)
|
||||||
mm.IsProtected = (visibility == VsProtected)
|
mm.IsProtected = (visibility == VsProtected)
|
||||||
|
|
||||||
if mm.IsProtected && !mm.IsVirtual {
|
if mm.IsProtected && mm.IsStatic && !mm.IsVirtual {
|
||||||
// Protected method, so we can't call it
|
// Protected static method, so there is no possible subclass to call it from
|
||||||
|
// e.g. QBitmap::fromImageInPlace
|
||||||
// Non-virtual, so we can't override it
|
// Non-virtual, so we can't override it
|
||||||
// There is nothing we can do with this function
|
// There is nothing we can do with this function
|
||||||
continue nextMethod
|
continue nextMethod
|
||||||
}
|
}
|
||||||
|
if mm.IsProtected && strings.HasPrefix(mm.MethodName, `operator`) {
|
||||||
|
// The subclass system causes problems here with e.g. QStandardItem::operator=
|
||||||
|
// This is a protected method, but the assignment `other` ends up
|
||||||
|
// with the child MiqtVirtual class instead of the original one
|
||||||
|
// Just skip them as well
|
||||||
|
continue nextMethod
|
||||||
|
}
|
||||||
|
|
||||||
// Once all processing is complete, pass to exceptions for final decision
|
// Once all processing is complete, pass to exceptions for final decision
|
||||||
|
|
||||||
|
@ -62,6 +62,10 @@ func cabiVirtualBaseName(c CppClass, m CppMethod) string {
|
|||||||
return cabiClassName(c.ClassName) + `_virtualbase_` + m.SafeMethodName()
|
return cabiClassName(c.ClassName) + `_virtualbase_` + m.SafeMethodName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cabiProtectedBaseName(c CppClass, m CppMethod) string {
|
||||||
|
return cabiClassName(c.ClassName) + `_protectedbase_` + m.SafeMethodName()
|
||||||
|
}
|
||||||
|
|
||||||
func cabiOverrideVirtualName(c CppClass, m CppMethod) string {
|
func cabiOverrideVirtualName(c CppClass, m CppMethod) string {
|
||||||
return cabiClassName(c.ClassName) + `_override_virtual_` + m.SafeMethodName()
|
return cabiClassName(c.ClassName) + `_override_virtual_` + m.SafeMethodName()
|
||||||
}
|
}
|
||||||
@ -600,11 +604,51 @@ func getCppZeroValue(p CppParameter) string {
|
|||||||
return "0"
|
return "0"
|
||||||
} else if p.ParameterType == "bool" {
|
} else if p.ParameterType == "bool" {
|
||||||
return "false"
|
return "false"
|
||||||
|
} else if p.ParameterType == "void" {
|
||||||
|
return ""
|
||||||
} else {
|
} else {
|
||||||
return p.RenderTypeQtCpp() + "()"
|
return p.RenderTypeQtCpp() + "()"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCabiZeroValue(p CppParameter) string {
|
||||||
|
// n.b. Identical to getCppZeroValue in most cases
|
||||||
|
|
||||||
|
if p.Pointer {
|
||||||
|
return getCppZeroValue(p)
|
||||||
|
} else if p.IsKnownEnum() {
|
||||||
|
return getCppZeroValue(p)
|
||||||
|
} else if p.IntType() {
|
||||||
|
return getCppZeroValue(p)
|
||||||
|
} else if p.ParameterType == "bool" {
|
||||||
|
return getCppZeroValue(p)
|
||||||
|
} else if p.ParameterType == "void" {
|
||||||
|
return getCppZeroValue(p)
|
||||||
|
|
||||||
|
} else if p.ParameterType == "QString" || p.ParameterType == "QByteArray" {
|
||||||
|
return "(struct miqt_string){}"
|
||||||
|
|
||||||
|
} else if _, ok := p.QListOf(); ok {
|
||||||
|
return "(struct miqt_array){}"
|
||||||
|
|
||||||
|
} else if _, ok := p.QSetOf(); ok {
|
||||||
|
return "(struct miqt_array){}"
|
||||||
|
|
||||||
|
} else if _, _, ok := p.QMapOf(); ok {
|
||||||
|
return "(struct miqt_map){}"
|
||||||
|
|
||||||
|
} else if _, _, ok := p.QPairOf(); ok {
|
||||||
|
return "(struct miqt_map){}"
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Difference for Qt classes: Qt C++ can expect to return them by value,
|
||||||
|
// but CABI always needs to return them by pointer
|
||||||
|
|
||||||
|
return "nullptr"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// getReferencedTypes finds all referenced Qt types in this file.
|
// getReferencedTypes finds all referenced Qt types in this file.
|
||||||
func getReferencedTypes(src *CppParsedHeader) []string {
|
func getReferencedTypes(src *CppParsedHeader) []string {
|
||||||
|
|
||||||
@ -656,6 +700,12 @@ func getReferencedTypes(src *CppParsedHeader) []string {
|
|||||||
}
|
}
|
||||||
maybeAddType(vm.ReturnType)
|
maybeAddType(vm.ReturnType)
|
||||||
}
|
}
|
||||||
|
for _, vm := range c.ProtectedMethods() {
|
||||||
|
for _, p := range vm.Parameters {
|
||||||
|
maybeAddType(p)
|
||||||
|
}
|
||||||
|
maybeAddType(vm.ReturnType)
|
||||||
|
}
|
||||||
for _, cn := range c.AllInheritsClassInfo() {
|
for _, cn := range c.AllInheritsClassInfo() {
|
||||||
maybeAddType(CppParameter{
|
maybeAddType(CppParameter{
|
||||||
ParameterType: cn.Class.ClassName,
|
ParameterType: cn.Class.ClassName,
|
||||||
@ -773,6 +823,8 @@ extern "C" {
|
|||||||
for _, c := range src.Classes {
|
for _, c := range src.Classes {
|
||||||
|
|
||||||
className := cabiClassName(c.ClassName)
|
className := cabiClassName(c.ClassName)
|
||||||
|
virtualMethods := c.VirtualMethods()
|
||||||
|
protectedMethods := c.ProtectedMethods()
|
||||||
|
|
||||||
for i, ctor := range c.Ctors {
|
for i, ctor := range c.Ctors {
|
||||||
ret.WriteString(fmt.Sprintf("%s* %s(%s);\n", className, cabiNewName(c, i), emitParametersCabiConstructor(&c, &ctor)))
|
ret.WriteString(fmt.Sprintf("%s* %s(%s);\n", className, cabiNewName(c, i), emitParametersCabiConstructor(&c, &ctor)))
|
||||||
@ -789,6 +841,10 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.Methods {
|
for _, m := range c.Methods {
|
||||||
|
if m.IsProtected && !m.IsVirtual {
|
||||||
|
continue // Can't call directly, have to go through our wrapper
|
||||||
|
}
|
||||||
|
|
||||||
ret.WriteString(fmt.Sprintf("%s %s(%s);\n", m.ReturnType.RenderTypeCabi(), cabiMethodName(c, m), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+className+"*")))
|
ret.WriteString(fmt.Sprintf("%s %s(%s);\n", m.ReturnType.RenderTypeCabi(), cabiMethodName(c, m), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+className+"*")))
|
||||||
|
|
||||||
if m.IsSignal {
|
if m.IsSignal {
|
||||||
@ -796,12 +852,18 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.VirtualMethods() {
|
for _, m := range virtualMethods {
|
||||||
ret.WriteString(fmt.Sprintf("bool %s(%s* self, intptr_t slot);\n", cabiOverrideVirtualName(c, m), "void" /*methodPrefixName*/))
|
ret.WriteString(fmt.Sprintf("bool %s(%s* self, intptr_t slot);\n", cabiOverrideVirtualName(c, m), "void" /*methodPrefixName*/))
|
||||||
|
|
||||||
ret.WriteString(fmt.Sprintf("%s %s(%s);\n", m.ReturnType.RenderTypeCabi(), cabiVirtualBaseName(c, m), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void" /*className*/ +"*")))
|
ret.WriteString(fmt.Sprintf("%s %s(%s);\n", m.ReturnType.RenderTypeCabi(), cabiVirtualBaseName(c, m), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void" /*className*/ +"*")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(virtualMethods) > 0 {
|
||||||
|
for _, m := range protectedMethods {
|
||||||
|
ret.WriteString(fmt.Sprintf("%s %s(bool* _dynamic_cast_ok, %s);\n", m.ReturnType.RenderTypeCabi(), cabiProtectedBaseName(c, m), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void" /*className*/ +"*")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
if c.CanDelete {
|
if c.CanDelete {
|
||||||
ret.WriteString(fmt.Sprintf("void %s(%s* self);\n", cabiDeleteName(c), className))
|
ret.WriteString(fmt.Sprintf("void %s(%s* self);\n", cabiDeleteName(c), className))
|
||||||
@ -908,6 +970,7 @@ extern "C" {
|
|||||||
methodPrefixName := cabiClassName(c.ClassName)
|
methodPrefixName := cabiClassName(c.ClassName)
|
||||||
cppClassName := c.ClassName
|
cppClassName := c.ClassName
|
||||||
virtualMethods := c.VirtualMethods()
|
virtualMethods := c.VirtualMethods()
|
||||||
|
protectedMethods := c.ProtectedMethods()
|
||||||
|
|
||||||
if len(virtualMethods) > 0 {
|
if len(virtualMethods) > 0 {
|
||||||
|
|
||||||
@ -1037,6 +1100,21 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(protectedMethods) > 0 {
|
||||||
|
ret.WriteString("\t// Wrappers to allow calling protected methods:\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range protectedMethods {
|
||||||
|
|
||||||
|
// The protectedbase wrapper needs to take CABI parameters, not
|
||||||
|
// real Qt parameters, in case there are protected enum types
|
||||||
|
// (e.g. QAbstractItemView::CursorAction)
|
||||||
|
|
||||||
|
ret.WriteString(
|
||||||
|
"\tfriend " + m.ReturnType.RenderTypeCabi() + " " + cabiProtectedBaseName(c, m) + "(bool* _dynamic_cast_ok, " + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void*") + ");\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
"};\n" +
|
"};\n" +
|
||||||
"\n")
|
"\n")
|
||||||
@ -1262,6 +1340,36 @@ extern "C" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(virtualMethods) > 0 {
|
||||||
|
// This is a subclassed class. In that case, we allow calling
|
||||||
|
// protected methods
|
||||||
|
// This is a standalone function, but it can access the protected
|
||||||
|
// method via a friend declaration
|
||||||
|
|
||||||
|
for _, m := range protectedMethods {
|
||||||
|
|
||||||
|
vbpreamble, vbforwarding := emitParametersCABI2CppForwarding(m.Parameters, "\t\t")
|
||||||
|
vbCallTarget := "self_cast->" + m.CppCallTarget() + "(" + vbforwarding + ")"
|
||||||
|
|
||||||
|
ret.WriteString(
|
||||||
|
m.ReturnType.RenderTypeCabi() + " " + cabiProtectedBaseName(c, m) + "(bool* _dynamic_cast_ok, " + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void*") + ") {\n" +
|
||||||
|
|
||||||
|
"\t" + cppClassName + "* self_cast = dynamic_cast<" + cppClassName + "*>( (" + cabiClassName(c.ClassName) + "*)(self) );\n" +
|
||||||
|
"\tif (self_cast == nullptr) {\n" +
|
||||||
|
"\t\t*_dynamic_cast_ok = false;\n" +
|
||||||
|
"\t\treturn " + getCabiZeroValue(m.ReturnType) + ";\n" +
|
||||||
|
"\t}\n" +
|
||||||
|
"\t\n" +
|
||||||
|
"\t*_dynamic_cast_ok = true;\n" +
|
||||||
|
"\t" + vbpreamble + "\n" +
|
||||||
|
emitAssignCppToCabi("\treturn ", m.ReturnType, vbCallTarget) + "\n" +
|
||||||
|
"}\n" +
|
||||||
|
"\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
// If we subclassed, our class destructor is always virtual. Therefore
|
// If we subclassed, our class destructor is always virtual. Therefore
|
||||||
// we can delete from the self ptr without any dynamic_cast<>
|
// we can delete from the self ptr without any dynamic_cast<>
|
||||||
|
@ -988,6 +988,43 @@ import "C"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.VirtualMethods()) > 0 {
|
||||||
|
// We only do protected methods if we are subclassing, and we only subclass if there are virtuals
|
||||||
|
// FIXME should we subclass in either case...?
|
||||||
|
for _, m := range c.ProtectedMethods() {
|
||||||
|
|
||||||
|
preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m)
|
||||||
|
|
||||||
|
forwarding = "unsafe.Pointer(this.h)" + strings.TrimPrefix(forwarding, `this.h`) // TODO integrate properly
|
||||||
|
|
||||||
|
returnTypeDecl := m.ReturnType.renderReturnTypeGo(&gfs)
|
||||||
|
|
||||||
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
|
|
||||||
|
ret.WriteString(`
|
||||||
|
// ` + m.goMethodName() + ` can only be called from a ` + goClassName + ` that was directly constructed.
|
||||||
|
func (this *` + goClassName + `) ` + m.goMethodName() + ` (` + gfs.emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {
|
||||||
|
` + preamble + `
|
||||||
|
var _dynamic_cast_ok C.bool = false
|
||||||
|
` + gfs.emitCabiToGo("_ret := ", m.ReturnType, `C.`+cabiProtectedBaseName(c, m)+`(&_dynamic_cast_ok, `+forwarding+`)`) + `
|
||||||
|
if !_dynamic_cast_ok {
|
||||||
|
panic("miqt: can only call protected methods for directly constructed types")
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
if !m.ReturnType.Void() {
|
||||||
|
ret.WriteString(`
|
||||||
|
return _ret
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString(`
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range c.VirtualMethods() {
|
for _, m := range c.VirtualMethods() {
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
gfs.imports["runtime/cgo"] = struct{}{}
|
gfs.imports["runtime/cgo"] = struct{}{}
|
||||||
@ -1008,7 +1045,7 @@ import "C"
|
|||||||
` + preamble + `
|
` + preamble + `
|
||||||
` + gfs.emitCabiToGo("return ", m.ReturnType, `C.`+cabiVirtualBaseName(c, m)+`(`+forwarding+`)`) + `
|
` + gfs.emitCabiToGo("return ", m.ReturnType, `C.`+cabiVirtualBaseName(c, m)+`(`+forwarding+`)`) + `
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,13 +516,25 @@ func (c *CppClass) ProtectedMethods() []CppMethod {
|
|||||||
var block = slice_to_set(c.PrivateMethods)
|
var block = slice_to_set(c.PrivateMethods)
|
||||||
|
|
||||||
for _, m := range c.Methods {
|
for _, m := range c.Methods {
|
||||||
|
|
||||||
|
// A public method with the same name blocks-out any protected methods
|
||||||
|
// with the same name (even if the signature is different).
|
||||||
|
// e.g.
|
||||||
|
// QTextList::setFormat(const QTextListFormat&) [PUBLIC] inherits
|
||||||
|
// QTextBlockGroup inherits
|
||||||
|
// QTextObject::setFormat(const QTextFormat&) [PROTECTED]
|
||||||
|
// FIXME support selecting the parent overload(?)
|
||||||
|
|
||||||
if !m.IsProtected {
|
if !m.IsProtected {
|
||||||
|
block[m.MethodName] = struct{}{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if m.IsVirtual {
|
if m.IsVirtual {
|
||||||
|
block[m.MethodName] = struct{}{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if m.IsSignal {
|
if m.IsSignal {
|
||||||
|
block[m.MethodName] = struct{}{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,6 +547,7 @@ func (c *CppClass) ProtectedMethods() []CppMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, cinfo := range c.AllInheritsClassInfo() {
|
for _, cinfo := range c.AllInheritsClassInfo() {
|
||||||
|
|
||||||
for _, m := range cinfo.Class.Methods {
|
for _, m := range cinfo.Class.Methods {
|
||||||
if !m.IsProtected {
|
if !m.IsProtected {
|
||||||
continue
|
continue
|
||||||
@ -582,6 +595,7 @@ func (c *CppClass) ProtectedMethods() []CppMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AllInheritsClassInfo recursively finds and lists all the parent classes of this class.
|
// AllInheritsClassInfo recursively finds and lists all the parent classes of this class.
|
||||||
|
// It returns closest-ancestor-first.
|
||||||
func (c *CppClass) AllInheritsClassInfo() []lookupResultClass {
|
func (c *CppClass) AllInheritsClassInfo() []lookupResultClass {
|
||||||
var ret []lookupResultClass
|
var ret []lookupResultClass
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user