genbindings: track private methods, exclude from virtual overrides

This commit is contained in:
mappu 2024-11-15 14:27:44 +13:00
parent aa2fdf98ca
commit d25301c910
3 changed files with 41 additions and 8 deletions

View File

@ -351,8 +351,8 @@ nextMethod:
case "EnumDecl": case "EnumDecl":
// Child class enum // Child class enum
if visibility != VsPublic { if visibility == VsPrivate {
continue // Skip private/protected continue // Skip private, ALLOW protected
} }
en, err := processEnum(node, nodename+"::") en, err := processEnum(node, nodename+"::")
@ -427,10 +427,17 @@ nextMethod:
case "CXXMethodDecl": case "CXXMethodDecl":
// Method
methodName, ok := node["name"].(string)
if !ok {
return CppClass{}, errors.New("method has no name")
}
// If this is a virtual method, we want to allow overriding it even // If this is a virtual method, we want to allow overriding it even
// if it is protected // if it is protected
// But we can only call it if it is public // But we can only call it if it is public
if visibility == VsPrivate { if visibility == VsPrivate {
ret.PrivateMethods = append(ret.PrivateMethods, methodName)
continue // Skip private, ALLOW protected continue // Skip private, ALLOW protected
} }
@ -439,12 +446,6 @@ nextMethod:
continue continue
} }
// Method
methodName, ok := node["name"].(string)
if !ok {
return CppClass{}, errors.New("method has no name")
}
var mm CppMethod var mm CppMethod
mm.MethodName = methodName mm.MethodName = methodName

View File

@ -382,6 +382,7 @@ type CppClass struct {
ChildTypedefs []CppTypedef ChildTypedefs []CppTypedef
ChildClassdefs []CppClass ChildClassdefs []CppClass
ChildEnums []CppEnum ChildEnums []CppEnum
PrivateMethods []string
} }
// Virtual checks if the class has any virtual methods. This requires global // Virtual checks if the class has any virtual methods. This requires global
@ -390,6 +391,7 @@ type CppClass struct {
func (c *CppClass) VirtualMethods() []CppMethod { func (c *CppClass) VirtualMethods() []CppMethod {
var ret []CppMethod var ret []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)
for _, m := range c.Methods { for _, m := range c.Methods {
if !m.IsVirtual { if !m.IsVirtual {
@ -426,9 +428,31 @@ func (c *CppClass) VirtualMethods() []CppMethod {
continue // Already found in a child class continue // Already found in a child class
} }
// It's possible that a child class marked a parent method as private
// (e.g. Qt 5 QAbstractTableModel marks parent() as private)
// But then we find the protected version further down
// Use a blocklist to prevent exposing any deeper methods in the call chain
if _, ok := block[m.MethodName]; ok {
continue // Marked as private in a child class
}
// The class info we loaded has not had all typedefs applied to it
// m is copied by value. Mutate it
applyTypedefs_Method(&m)
// Same with astTransformBlocklist
if !blocklist_MethodAllowed(&m) {
continue
}
ret = append(ret, m) ret = append(ret, m)
retNames[m.MethodName] = struct{}{} retNames[m.MethodName] = struct{}{}
} }
// Append this parent's private-virtuals to blocklist so that we
// do not consider them for grandparent classes
for _, privMethod := range c.PrivateMethods {
block[privMethod] = struct{}{}
}
} }
return ret return ret

View File

@ -38,3 +38,11 @@ func ifv[T any](condition bool, trueval T, falseval T) T {
func addr[T any](s T) *T { func addr[T any](s T) *T {
return &s return &s
} }
func slice_to_set[T comparable](list []T) map[T]struct{} {
ret := make(map[T]struct{}, len(list))
for _, v := range list {
ret[v] = struct{}{}
}
return ret
}