diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index 628ca375..2eb65395 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -351,8 +351,8 @@ nextMethod: case "EnumDecl": // Child class enum - if visibility != VsPublic { - continue // Skip private/protected + if visibility == VsPrivate { + continue // Skip private, ALLOW protected } en, err := processEnum(node, nodename+"::") @@ -427,10 +427,17 @@ nextMethod: 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 it is protected // But we can only call it if it is public if visibility == VsPrivate { + ret.PrivateMethods = append(ret.PrivateMethods, methodName) continue // Skip private, ALLOW protected } @@ -439,12 +446,6 @@ nextMethod: continue } - // Method - methodName, ok := node["name"].(string) - if !ok { - return CppClass{}, errors.New("method has no name") - } - var mm CppMethod mm.MethodName = methodName diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index 8dd6a600..b1313449 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -382,6 +382,7 @@ type CppClass struct { ChildTypedefs []CppTypedef ChildClassdefs []CppClass ChildEnums []CppEnum + PrivateMethods []string } // Virtual checks if the class has any virtual methods. This requires global @@ -390,6 +391,7 @@ type CppClass struct { 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 + var block = slice_to_set(c.PrivateMethods) for _, m := range c.Methods { if !m.IsVirtual { @@ -426,9 +428,31 @@ func (c *CppClass) VirtualMethods() []CppMethod { 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) 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 diff --git a/cmd/genbindings/util.go b/cmd/genbindings/util.go index db4e075b..5beb03d6 100644 --- a/cmd/genbindings/util.go +++ b/cmd/genbindings/util.go @@ -38,3 +38,11 @@ func ifv[T any](condition bool, trueval T, falseval T) T { func addr[T any](s T) *T { 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 +} \ No newline at end of file