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.IsProtected = (visibility == VsProtected)
|
||||
|
||||
if mm.IsProtected && !mm.IsVirtual {
|
||||
// Protected method, so we can't call it
|
||||
if mm.IsProtected && mm.IsStatic && !mm.IsVirtual {
|
||||
// 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
|
||||
// There is nothing we can do with this function
|
||||
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
|
||||
|
||||
|
@ -62,6 +62,10 @@ func cabiVirtualBaseName(c CppClass, m CppMethod) string {
|
||||
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 {
|
||||
return cabiClassName(c.ClassName) + `_override_virtual_` + m.SafeMethodName()
|
||||
}
|
||||
@ -600,11 +604,51 @@ func getCppZeroValue(p CppParameter) string {
|
||||
return "0"
|
||||
} else if p.ParameterType == "bool" {
|
||||
return "false"
|
||||
} else if p.ParameterType == "void" {
|
||||
return ""
|
||||
} else {
|
||||
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.
|
||||
func getReferencedTypes(src *CppParsedHeader) []string {
|
||||
|
||||
@ -656,6 +700,12 @@ func getReferencedTypes(src *CppParsedHeader) []string {
|
||||
}
|
||||
maybeAddType(vm.ReturnType)
|
||||
}
|
||||
for _, vm := range c.ProtectedMethods() {
|
||||
for _, p := range vm.Parameters {
|
||||
maybeAddType(p)
|
||||
}
|
||||
maybeAddType(vm.ReturnType)
|
||||
}
|
||||
for _, cn := range c.AllInheritsClassInfo() {
|
||||
maybeAddType(CppParameter{
|
||||
ParameterType: cn.Class.ClassName,
|
||||
@ -773,6 +823,8 @@ extern "C" {
|
||||
for _, c := range src.Classes {
|
||||
|
||||
className := cabiClassName(c.ClassName)
|
||||
virtualMethods := c.VirtualMethods()
|
||||
protectedMethods := c.ProtectedMethods()
|
||||
|
||||
for i, ctor := range c.Ctors {
|
||||
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 {
|
||||
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+"*")))
|
||||
|
||||
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("%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
|
||||
if c.CanDelete {
|
||||
ret.WriteString(fmt.Sprintf("void %s(%s* self);\n", cabiDeleteName(c), className))
|
||||
@ -908,6 +970,7 @@ extern "C" {
|
||||
methodPrefixName := cabiClassName(c.ClassName)
|
||||
cppClassName := c.ClassName
|
||||
virtualMethods := c.VirtualMethods()
|
||||
protectedMethods := c.ProtectedMethods()
|
||||
|
||||
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(
|
||||
"};\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
|
||||
// If we subclassed, our class destructor is always virtual. Therefore
|
||||
// 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() {
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
gfs.imports["runtime/cgo"] = struct{}{}
|
||||
@ -1008,7 +1045,7 @@ import "C"
|
||||
` + preamble + `
|
||||
` + 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)
|
||||
|
||||
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 {
|
||||
block[m.MethodName] = struct{}{}
|
||||
continue
|
||||
}
|
||||
if m.IsVirtual {
|
||||
block[m.MethodName] = struct{}{}
|
||||
continue
|
||||
}
|
||||
if m.IsSignal {
|
||||
block[m.MethodName] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
@ -535,6 +547,7 @@ func (c *CppClass) ProtectedMethods() []CppMethod {
|
||||
}
|
||||
|
||||
for _, cinfo := range c.AllInheritsClassInfo() {
|
||||
|
||||
for _, m := range cinfo.Class.Methods {
|
||||
if !m.IsProtected {
|
||||
continue
|
||||
@ -582,6 +595,7 @@ func (c *CppClass) ProtectedMethods() []CppMethod {
|
||||
}
|
||||
|
||||
// AllInheritsClassInfo recursively finds and lists all the parent classes of this class.
|
||||
// It returns closest-ancestor-first.
|
||||
func (c *CppClass) AllInheritsClassInfo() []lookupResultClass {
|
||||
var ret []lookupResultClass
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user