diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index 0b918636..eaaabbdb 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -7,7 +7,7 @@ import ( "strings" ) -func parseHeader(topLevel []interface{}) (*CppParsedHeader, error) { +func parseHeader(topLevel []interface{}, addNamePrefix string) (*CppParsedHeader, error) { var ret CppParsedHeader @@ -28,7 +28,7 @@ func parseHeader(topLevel []interface{}) (*CppParsedHeader, error) { case "CXXRecordDecl": // Process the inner class definition - obj, err := processClassType(node, "") + obj, err := processClassType(node, addNamePrefix) if err != nil { if errors.Is(err, ErrNoContent) { log.Printf("-> Skipping (%v)\n", err) @@ -59,7 +59,30 @@ func parseHeader(topLevel []interface{}) (*CppParsedHeader, error) { // ignore case "NamespaceDecl": - // ignore + // Parse everything inside the namespace with prefix, as if it is + // a whole separate file + // Then copy the parsed elements back into our own file + namespace, ok := node["name"].(string) + if !ok { + panic("NamespaceDecl missing name") + } + + namespaceInner, ok := node["inner"].([]interface{}) + if !ok { + // A namespace declaration with no inner content means that, for + // the rest of this whole file, we are in this namespace + // Update our own `addNamePrefix` accordingly + addNamePrefix += namespace + "::" + + } else { + + contents, err := parseHeader(namespaceInner, namespace+"::") + if err != nil { + panic(err) + } + + ret.AddContentFrom(contents) + } case "FunctionDecl": // TODO @@ -84,16 +107,15 @@ func parseHeader(topLevel []interface{}) (*CppParsedHeader, error) { // TODO e.g. qfuturewatcher.h // Probably can't be supported in the Go binding - case "TypeAliasDecl": - // TODO e.g. qglobal.h - // Should be treated like a typedef - - case "UsingDirectiveDecl": - // TODO e.g. qtextstream.h + case "TypeAliasDecl", // qglobal.h + "UsingDirectiveDecl", // qtextstream.h + "UsingDecl", // qglobal.h + "UsingShadowDecl": // global.h + // TODO e.g. // Should be treated like a typedef case "TypedefDecl": - td, err := processTypedef(node, "") + td, err := processTypedef(node, addNamePrefix) if err != nil { return nil, fmt.Errorf("processTypedef: %w", err) } @@ -103,6 +125,9 @@ func parseHeader(topLevel []interface{}) (*CppParsedHeader, error) { // A C++ class method implementation directly in the header // Skip over these + case "FullComment": + // Safe to skip + default: return nil, fmt.Errorf("missing handling for clang ast node type %q", kind) } diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index 171383a6..0d1c557b 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -273,3 +273,9 @@ func (c CppParsedHeader) Empty() bool { return len(c.Typedefs) == 0 && len(c.Classes) == 0 } + +func (c *CppParsedHeader) AddContentFrom(other *CppParsedHeader) { + c.Classes = append(c.Classes, other.Classes...) + c.Enums = append(c.Enums, other.Enums...) + c.Typedefs = append(c.Typedefs, other.Typedefs...) +} diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index a13a1d82..3679229b 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -124,7 +124,7 @@ func main() { } // Convert it to our intermediate format - parsed, err := parseHeader(astInner) + parsed, err := parseHeader(astInner, "") if err != nil { panic(err) }