mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 00:48:38 +00:00
genbindings: subclass support for all virtual methods (1/3)
This commit is contained in:
parent
9b37750d64
commit
aa2fdf98ca
@ -460,6 +460,14 @@ 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
|
||||
// Non-virtual, so we can't override it
|
||||
// There is nothing we can do with this function
|
||||
continue nextMethod
|
||||
}
|
||||
|
||||
// Once all processing is complete, pass to exceptions for final decision
|
||||
|
||||
|
@ -186,6 +186,10 @@ func AllowSignal(mm CppMethod) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func AllowVirtual(mm CppMethod) bool {
|
||||
return true // AllowSignal(mm)
|
||||
}
|
||||
|
||||
func AllowMethod(className string, mm CppMethod) error {
|
||||
|
||||
for _, p := range mm.Parameters {
|
||||
|
@ -674,23 +674,27 @@ extern "C" {
|
||||
|
||||
for _, c := range src.Classes {
|
||||
|
||||
cClassName := cabiClassName(c.ClassName)
|
||||
methodPrefixName := cabiClassName(c.ClassName)
|
||||
|
||||
for i, ctor := range c.Ctors {
|
||||
ret.WriteString(fmt.Sprintf("%s %s_new%s(%s);\n", cClassName+"*", cClassName, maybeSuffix(i), emitParametersCabi(ctor, "")))
|
||||
ret.WriteString(fmt.Sprintf("%s %s_new%s(%s);\n", methodPrefixName+"*", methodPrefixName, maybeSuffix(i), emitParametersCabi(ctor, "")))
|
||||
}
|
||||
|
||||
for _, m := range c.Methods {
|
||||
ret.WriteString(fmt.Sprintf("%s %s_%s(%s);\n", m.ReturnType.RenderTypeCabi(), cClassName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+cClassName+"*")))
|
||||
ret.WriteString(fmt.Sprintf("%s %s_%s(%s);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*")))
|
||||
|
||||
if m.IsSignal {
|
||||
ret.WriteString(fmt.Sprintf("%s %s_connect_%s(%s* self, intptr_t slot);\n", m.ReturnType.RenderTypeCabi(), cClassName, m.SafeMethodName(), cClassName))
|
||||
ret.WriteString(fmt.Sprintf("%s %s_connect_%s(%s* self, intptr_t slot);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), methodPrefixName))
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range c.VirtualMethods() {
|
||||
ret.WriteString(fmt.Sprintf("void %s_override_virtual_%s(%s* self, intptr_t slot);\n", methodPrefixName, m.SafeMethodName(), methodPrefixName))
|
||||
}
|
||||
|
||||
// delete
|
||||
if c.CanDelete {
|
||||
ret.WriteString(fmt.Sprintf("void %s_Delete(%s* self);\n", cClassName, cClassName))
|
||||
ret.WriteString(fmt.Sprintf("void %s_Delete(%s* self);\n", methodPrefixName, methodPrefixName))
|
||||
}
|
||||
|
||||
ret.WriteString("\n")
|
||||
@ -736,7 +740,49 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
|
||||
for _, c := range src.Classes {
|
||||
|
||||
cClassName := cabiClassName(c.ClassName)
|
||||
methodPrefixName := cabiClassName(c.ClassName)
|
||||
cppClassName := c.ClassName
|
||||
virtualMethods := c.VirtualMethods()
|
||||
|
||||
if len(virtualMethods) > 0 {
|
||||
ret.WriteString("class MiqtVirtual" + cppClassName + " : public virtual " + cppClassName + " {\n" +
|
||||
"public:\n" +
|
||||
"\tusing " + cppClassName + "::" + cppClassName + ";\n" + // inherit constructors
|
||||
"\n",
|
||||
)
|
||||
for _, m := range virtualMethods {
|
||||
|
||||
maybeReturn := ifv(m.ReturnType.RenderTypeQtCpp() == "void", "", "return ")
|
||||
|
||||
ret.WriteString(
|
||||
"\tintptr_t handle__" + m.SafeMethodName() + " = 0;\n" +
|
||||
|
||||
"\n" +
|
||||
|
||||
"\t" + m.ReturnType.RenderTypeQtCpp() + " " + m.MethodName + "(...) override {\n" +
|
||||
"\t\tif (handle__" + m.SafeMethodName() + " == 0) {\n" +
|
||||
"\t\t\t" + maybeReturn + methodPrefixName + "::" + m.MethodName + "(...);\n" +
|
||||
"\t\t} else {\n" +
|
||||
"\t\t\t" + maybeReturn + "miqt_exec_callback_" + methodPrefixName + "_" + m.SafeMethodName() + "(...);\n" +
|
||||
"\t\t}\n" +
|
||||
"\t}\n" +
|
||||
|
||||
"\n" +
|
||||
|
||||
"\t" + m.ReturnType.RenderTypeQtCpp() + " virtualbase_" + m.SafeMethodName() + "(...) {\n" +
|
||||
"\t\t" + maybeReturn + methodPrefixName + "::" + m.MethodName + "(...);\n" +
|
||||
"\t}\n" +
|
||||
|
||||
"\n",
|
||||
)
|
||||
}
|
||||
|
||||
ret.WriteString(
|
||||
"};\n" +
|
||||
"\n")
|
||||
|
||||
cppClassName = "MiqtVirtual" + cppClassName
|
||||
}
|
||||
|
||||
for i, ctor := range c.Ctors {
|
||||
|
||||
@ -754,9 +800,9 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
"#endif\n"+
|
||||
"}\n"+
|
||||
"\n",
|
||||
cClassName, cClassName, maybeSuffix(i), emitParametersCabi(ctor, ""),
|
||||
methodPrefixName, methodPrefixName, maybeSuffix(i), emitParametersCabi(ctor, ""),
|
||||
preamble,
|
||||
c.ClassName, forwarding,
|
||||
cppClassName, forwarding,
|
||||
))
|
||||
|
||||
} else {
|
||||
@ -766,9 +812,9 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
"\treturn new %s(%s);\n"+
|
||||
"}\n"+
|
||||
"\n",
|
||||
cClassName, cClassName, maybeSuffix(i), emitParametersCabi(ctor, ""),
|
||||
methodPrefixName, methodPrefixName, maybeSuffix(i), emitParametersCabi(ctor, ""),
|
||||
preamble,
|
||||
c.ClassName, forwarding,
|
||||
cppClassName, forwarding,
|
||||
))
|
||||
|
||||
}
|
||||
@ -800,7 +846,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
"#endif\n"+
|
||||
"}\n"+
|
||||
"\n",
|
||||
m.ReturnType.RenderTypeCabi(), cClassName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+cClassName+"*"),
|
||||
m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*"),
|
||||
preamble,
|
||||
emitAssignCppToCabi("\treturn ", m.ReturnType, callTarget),
|
||||
m.ReturnType.RenderTypeCabi(),
|
||||
@ -808,10 +854,10 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
|
||||
} else if m.BecomesNonConstInVersion != nil {
|
||||
|
||||
nonConstCallTarget := "const_cast<" + cClassName + "*>(self)->" + m.CppCallTarget() + "(" + forwarding + ")"
|
||||
nonConstCallTarget := "const_cast<" + methodPrefixName + "*>(self)->" + m.CppCallTarget() + "(" + forwarding + ")"
|
||||
|
||||
ret.WriteString("" +
|
||||
m.ReturnType.RenderTypeCabi() + " " + cClassName + "_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+cClassName+"*") + ") {\n" +
|
||||
m.ReturnType.RenderTypeCabi() + " " + methodPrefixName + "_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*") + ") {\n" +
|
||||
preamble + "\n" +
|
||||
"// This method was changed from const to non-const in Qt " + *m.BecomesNonConstInVersion + "\n" +
|
||||
"#if QT_VERSION < QT_VERSION_CHECK(" + strings.Replace(*m.BecomesNonConstInVersion, `.`, `,`, -1) + ",0)\n" +
|
||||
@ -831,7 +877,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
"%s"+
|
||||
"}\n"+
|
||||
"\n",
|
||||
m.ReturnType.RenderTypeCabi(), cClassName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+cClassName+"*"),
|
||||
m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*"),
|
||||
preamble,
|
||||
emitAssignCppToCabi("\treturn ", m.ReturnType, callTarget),
|
||||
))
|
||||
@ -860,8 +906,8 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
signalCode += "\t\t" + bindingFunc + "(" + strings.Join(paramArgs, `, `) + ");\n"
|
||||
|
||||
ret.WriteString(
|
||||
`void ` + cClassName + `_connect_` + m.SafeMethodName() + `(` + cClassName + `* self, intptr_t slot) {` + "\n" +
|
||||
"\t" + c.ClassName + `::connect(self, ` + exactSignal + `, self, [=](` + emitParametersCpp(m) + `) {` + "\n" +
|
||||
`void ` + methodPrefixName + `_connect_` + m.SafeMethodName() + `(` + methodPrefixName + `* self, intptr_t slot) {` + "\n" +
|
||||
"\t" + cppClassName + `::connect(self, ` + exactSignal + `, self, [=](` + emitParametersCpp(m) + `) {` + "\n" +
|
||||
signalCode +
|
||||
"\t});\n" +
|
||||
"}\n" +
|
||||
@ -871,6 +917,17 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
|
||||
}
|
||||
|
||||
// Virtual override helpers
|
||||
for _, m := range virtualMethods {
|
||||
ret.WriteString(
|
||||
`void ` + methodPrefixName + `_override_virtual_` + m.SafeMethodName() + `(` + methodPrefixName + `* self, intptr_t slot) {` + "\n" +
|
||||
"\tstatic_cast<" + cppClassName + ">(self)->handle__" + m.SafeMethodName() + " = slot;\n" +
|
||||
"}\n" +
|
||||
"\n",
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Delete
|
||||
if c.CanDelete {
|
||||
ret.WriteString(fmt.Sprintf(
|
||||
@ -878,7 +935,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
||||
"\tdelete self;\n"+
|
||||
"}\n"+
|
||||
"\n",
|
||||
cClassName, cClassName,
|
||||
methodPrefixName, methodPrefixName,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +238,8 @@ type CppMethod struct {
|
||||
IsStatic bool
|
||||
IsSignal bool
|
||||
IsConst bool
|
||||
IsVirtual bool
|
||||
IsProtected bool // If true, we can't call this method but we may still be able to overload it
|
||||
HiddenParams []CppParameter // Populated if there is an overload with more parameters
|
||||
|
||||
// Special quirks
|
||||
@ -382,6 +384,56 @@ type CppClass struct {
|
||||
ChildEnums []CppEnum
|
||||
}
|
||||
|
||||
// Virtual checks if the class has any virtual methods. This requires global
|
||||
// state knowledge as virtual methods might have been inherited.
|
||||
// C++ constructors cannot be virtual.
|
||||
func (c *CppClass) VirtualMethods() []CppMethod {
|
||||
var ret []CppMethod
|
||||
var retNames = make(map[string]struct{}, 0) // if name is present, a child class found it first
|
||||
|
||||
for _, m := range c.Methods {
|
||||
if !m.IsVirtual {
|
||||
continue
|
||||
}
|
||||
if m.IsSignal {
|
||||
continue
|
||||
}
|
||||
if !AllowVirtual(m) {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, m)
|
||||
retNames[m.MethodName] = struct{}{}
|
||||
}
|
||||
|
||||
for _, inh := range c.Inherits {
|
||||
cinfo, ok := KnownClassnames[inh]
|
||||
if !ok {
|
||||
panic("Class " + c.ClassName + " inherits from unknown class " + inh)
|
||||
}
|
||||
|
||||
for _, m := range cinfo.Class.Methods {
|
||||
if !m.IsVirtual {
|
||||
continue
|
||||
}
|
||||
if m.IsSignal {
|
||||
continue
|
||||
}
|
||||
if !AllowVirtual(m) {
|
||||
continue
|
||||
}
|
||||
if _, ok := retNames[m.MethodName]; ok {
|
||||
continue // Already found in a child class
|
||||
}
|
||||
|
||||
ret = append(ret, m)
|
||||
retNames[m.MethodName] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type CppTypedef struct {
|
||||
Alias string
|
||||
UnderlyingType CppParameter
|
||||
|
Loading…
Reference in New Issue
Block a user