mirror of
https://github.com/mappu/miqt.git
synced 2025-04-04 12:40:23 +00:00
genbindings: subclass support for all virtual methods (3/3)
This commit is contained in:
parent
58f212303e
commit
943ccf7b3a
@ -718,9 +718,9 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.VirtualMethods() {
|
for _, m := range c.VirtualMethods() {
|
||||||
ret.WriteString(fmt.Sprintf("void %s_override_virtual_%s(%s* self, intptr_t slot);\n", methodPrefixName, m.SafeMethodName(), methodPrefixName))
|
ret.WriteString(fmt.Sprintf("void %s_override_virtual_%s(%s* self, intptr_t slot);\n", methodPrefixName, m.SafeMethodName(), "void" /*methodPrefixName*/))
|
||||||
|
|
||||||
ret.WriteString(fmt.Sprintf("%s %s_virtualbase_%s(%s);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*")))
|
ret.WriteString(fmt.Sprintf("%s %s_virtualbase_%s(%s);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void" /*methodPrefixName*/ +"*")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
@ -786,18 +786,27 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
|
|
||||||
ret.WriteString("class " + overriddenClassName + " : public virtual " + cppClassName + " {\n" +
|
ret.WriteString("class " + overriddenClassName + " : public virtual " + cppClassName + " {\n" +
|
||||||
"public:\n" +
|
"public:\n" +
|
||||||
"\tusing " + fullyQualifiedConstructor(cppClassName) + ";\n" + // inherit constructors
|
|
||||||
"\n",
|
"\n",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for _, ctor := range c.Ctors {
|
||||||
|
ret.WriteString("\t" + overriddenClassName + "(" + emitParametersCpp(ctor) + "): " + cppClassName + "(" + emitParameterNames(ctor) + ") {};\n")
|
||||||
|
}
|
||||||
|
ret.WriteString("\n")
|
||||||
|
|
||||||
if !c.CanDelete {
|
if !c.CanDelete {
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
"private:\n" +
|
"private:\n" +
|
||||||
"\t~" + overriddenClassName + "();\n" + // = delete;\n" +
|
"\tvirtual ~" + overriddenClassName + "();\n" + // = delete;\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"public:\n" +
|
"public:\n" +
|
||||||
"\n",
|
"\n",
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
ret.WriteString(
|
||||||
|
"\tvirtual ~" + overriddenClassName + "() = default;\n" +
|
||||||
|
"\n",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range virtualMethods {
|
for _, m := range virtualMethods {
|
||||||
@ -834,7 +843,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
|
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
"\t// Subclass to allow providing a Go implementation\n" +
|
"\t// Subclass to allow providing a Go implementation\n" +
|
||||||
"\t" + m.ReturnType.RenderTypeQtCpp() + " " + m.CppCallTarget() + "(" + emitParametersCpp(m) + ") " + ifv(m.IsConst, "const ", "") + "override {\n" +
|
"\tvirtual " + m.ReturnType.RenderTypeQtCpp() + " " + m.CppCallTarget() + "(" + emitParametersCpp(m) + ") " + ifv(m.IsConst, "const ", "") + "override {\n" +
|
||||||
"\t\tif (handle__" + m.SafeMethodName() + " == 0) {\n",
|
"\t\tif (handle__" + m.SafeMethodName() + " == 0) {\n",
|
||||||
)
|
)
|
||||||
if m.IsPureVirtual {
|
if m.IsPureVirtual {
|
||||||
@ -845,6 +854,10 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret.WriteString("\t\t\t" + maybeReturn + methodPrefixName + "::" + m.CppCallTarget() + "(" + emitParameterNames(m) + ");\n")
|
ret.WriteString("\t\t\t" + maybeReturn + methodPrefixName + "::" + m.CppCallTarget() + "(" + emitParameterNames(m) + ");\n")
|
||||||
|
|
||||||
|
if m.ReturnType.Void() {
|
||||||
|
ret.WriteString("\t\t\treturn;\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
"\t\t}\n" +
|
"\t\t}\n" +
|
||||||
@ -874,12 +887,6 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
}
|
}
|
||||||
vbpreamble, vbforwarding := emitParametersCABI2CppForwarding(m.Parameters, "\t\t")
|
vbpreamble, vbforwarding := emitParametersCABI2CppForwarding(m.Parameters, "\t\t")
|
||||||
|
|
||||||
// To call the super/parent's version of this method, normally
|
|
||||||
// we use the scope operator (Base::Foo()), but that only works
|
|
||||||
// inside the actual overridden method itself
|
|
||||||
// Use a reinterpret_cast<> instead
|
|
||||||
|
|
||||||
// vbCallTarget := "reinterpret_cast<" + ifv(m.IsConst, "const ", "") + c.ClassName + "*>(this)->" + m.CppCallTarget() + "(" + vbforwarding + ")"
|
|
||||||
vbCallTarget := methodPrefixName + "::" + m.CppCallTarget() + "(" + vbforwarding + ")"
|
vbCallTarget := methodPrefixName + "::" + m.CppCallTarget() + "(" + vbforwarding + ")"
|
||||||
|
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
@ -904,18 +911,6 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
|
|
||||||
for i, ctor := range c.Ctors {
|
for i, ctor := range c.Ctors {
|
||||||
|
|
||||||
if len(virtualMethods) > 0 &&
|
|
||||||
len(ctor.Parameters) == 1 &&
|
|
||||||
ctor.Parameters[0].ParameterType == c.ClassName &&
|
|
||||||
(ctor.Parameters[0].Pointer || ctor.Parameters[0].ByRef) {
|
|
||||||
// This is a copy-constructor for the base class
|
|
||||||
// We can't just call it on the derived class, that doesn't work:
|
|
||||||
// ""an inherited constructor is not a candidate for initialization from an expression of the same or derived type""
|
|
||||||
// @ref https://stackoverflow.com/q/57926023
|
|
||||||
// FIXME need to block this in the header and in Go as well
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
preamble, forwarding := emitParametersCABI2CppForwarding(ctor.Parameters, "\t")
|
preamble, forwarding := emitParametersCABI2CppForwarding(ctor.Parameters, "\t")
|
||||||
|
|
||||||
if ctor.LinuxOnly {
|
if ctor.LinuxOnly {
|
||||||
@ -1063,8 +1058,8 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
// (Never use a const self*)
|
// (Never use a const self*)
|
||||||
|
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
`void ` + methodPrefixName + `_override_virtual_` + m.SafeMethodName() + `(` + methodPrefixName + `* self, intptr_t slot) {` + "\n" +
|
`void ` + methodPrefixName + `_override_virtual_` + m.SafeMethodName() + `(void* self, intptr_t slot) {` + "\n" +
|
||||||
"\tdynamic_cast<" + cppClassName + "*>(self)->handle__" + m.SafeMethodName() + " = slot;\n" +
|
"\t( (" + cppClassName + "*)(self) )->handle__" + m.SafeMethodName() + " = slot;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"\n",
|
"\n",
|
||||||
)
|
)
|
||||||
@ -1088,10 +1083,10 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
// callTarget is an rvalue representing the full C++ function call.
|
// callTarget is an rvalue representing the full C++ function call.
|
||||||
// These are never static
|
// These are never static
|
||||||
|
|
||||||
callTarget := "dynamic_cast<" + ifv(m.IsConst, "const ", "") + cppClassName + "*>(self)->virtualbase_" + m.SafeMethodName() + "(" + strings.Join(parameterNames, `, `) + ")"
|
callTarget := "( (" + ifv(m.IsConst, "const ", "") + cppClassName + "*)(self) )->virtualbase_" + m.SafeMethodName() + "(" + strings.Join(parameterNames, `, `) + ")"
|
||||||
|
|
||||||
ret.WriteString(
|
ret.WriteString(
|
||||||
m.ReturnType.RenderTypeCabi() + " " + methodPrefixName + "_virtualbase_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*") + ") {\n" +
|
m.ReturnType.RenderTypeCabi() + " " + methodPrefixName + "_virtualbase_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void*") + ") {\n" +
|
||||||
"\t" + ifv(m.ReturnType.Void(), "", "return ") + callTarget + ";\n" +
|
"\t" + ifv(m.ReturnType.Void(), "", "return ") + callTarget + ";\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -806,6 +806,11 @@ import "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.Methods {
|
for _, m := range c.Methods {
|
||||||
|
|
||||||
|
if m.IsProtected {
|
||||||
|
continue // Don't add a direct call for it
|
||||||
|
}
|
||||||
|
|
||||||
preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m)
|
preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m)
|
||||||
|
|
||||||
returnTypeDecl := m.ReturnType.RenderTypeGo(&gfs)
|
returnTypeDecl := m.ReturnType.RenderTypeGo(&gfs)
|
||||||
@ -910,7 +915,7 @@ import "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot ` + goCbType + `) {
|
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot ` + goCbType + `) {
|
||||||
C.` + goClassName + `_override_virtual_` + m.SafeMethodName() + `(this.h, C.intptr_t(cgo.NewHandle(slot)) )
|
C.` + goClassName + `_override_virtual_` + m.SafeMethodName() + `(unsafe.Pointer(this.h), C.intptr_t(cgo.NewHandle(slot)) )
|
||||||
}
|
}
|
||||||
|
|
||||||
//export miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `
|
//export miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `
|
||||||
|
@ -394,6 +394,28 @@ func (c *CppClass) VirtualMethods() []CppMethod {
|
|||||||
var retNames = make(map[string]struct{}, 0) // if name is present, a child class found it first
|
var retNames = make(map[string]struct{}, 0) // if name is present, a child class found it first
|
||||||
var block = slice_to_set(c.PrivateMethods)
|
var block = slice_to_set(c.PrivateMethods)
|
||||||
|
|
||||||
|
if len(c.Ctors) == 0 {
|
||||||
|
// This class can't be constructed
|
||||||
|
// Therefore there's no way to get a derived version of it for subclassing
|
||||||
|
// (Unless we add custom constructors, but that seems like there would be
|
||||||
|
// no in-Qt use for such a thing)
|
||||||
|
// Pretend that this class is non-virtual
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME Allowing the subclassing of QAccessibleWidget compiles fine,
|
||||||
|
// but, always gives a linker error:
|
||||||
|
//
|
||||||
|
// /usr/lib/go-1.19/pkg/tool/linux_amd64/link: running g++ failed: exit status 1
|
||||||
|
// /usr/bin/ld: /tmp/go-link-1745036494/000362.o: in function `MiqtVirtualQAccessibleWidget::MiqtVirtualQAccessibleWidget(QWidget*)':
|
||||||
|
// undefined reference to `vtable for MiqtVirtualQAccessibleWidget'
|
||||||
|
//
|
||||||
|
// An undefined vtable usually indicates that the virtual class is missing
|
||||||
|
// definitions for some virtual methods, but AFAICT we have complete coverage.
|
||||||
|
if c.ClassName == "QAccessibleWidget" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range c.Methods {
|
for _, m := range c.Methods {
|
||||||
if !m.IsVirtual {
|
if !m.IsVirtual {
|
||||||
continue
|
continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user