diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index 3b2a7805..11cf71f9 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -94,9 +94,12 @@ func parseHeader(topLevel []interface{}, addNamePrefix string) (*CppParsedHeader if err != nil { panic(fmt.Errorf("processEnum: %w", err)) // A real problem } - if len(en.Entries) > 0 { // e.g. qmetatype's version of QCborSimpleType (the real one is in qcborcommon) - ret.Enums = append(ret.Enums, en) - } + + // n.b. In some cases we may produce multiple "copies" of an enum + // (e.g. qcborcommon and qmetatype both define QCborSimpleType) + // Allow, but use a transform pass to avoid multiple definitions of + // it + ret.Enums = append(ret.Enums, en) case "VarDecl": // TODO e.g. qmath.h diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index fc9159aa..af41403c 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -400,19 +400,26 @@ import "C" } for _, e := range src.Enums { + if e.EnumName == "" { + continue // Removed by transformRedundant AST pass + } + goEnumName := cabiClassName(e.EnumName) ret.WriteString(` type ` + goEnumName + ` ` + parseSingleTypeString(e.UnderlyingType).RenderTypeGo() + ` - - const ( `) - for _, ee := range e.Entries { - ret.WriteString(cabiClassName(goEnumName+"::"+ee.EntryName) + " " + goEnumName + " = " + ee.EntryValue + "\n") - } + if len(e.Entries) > 0 { - ret.WriteString("\n)\n\n") + ret.WriteString("const (\n") + + for _, ee := range e.Entries { + ret.WriteString(cabiClassName(goEnumName+"::"+ee.EntryName) + " " + goEnumName + " = " + ee.EntryValue + "\n") + } + + ret.WriteString("\n)\n\n") + } } for _, c := range src.Classes { diff --git a/cmd/genbindings/exceptions.go b/cmd/genbindings/exceptions.go index 08d640e6..403f9428 100644 --- a/cmd/genbindings/exceptions.go +++ b/cmd/genbindings/exceptions.go @@ -195,10 +195,6 @@ func CheckComplexity(p CppParameter, isReturnType bool) error { "QXmlStreamAttributes", // e.g. qxmlstream.h "QVariantMap", // e.g. qcbormap.h "QVariantHash", // e.g. qcbormap.h - "QCborTag", // e.g. qcborstreamreader.h.TODO Needs support for enums - "QCborSimpleType", // e.g. qcborstreamreader.h TODO Needs support for enums - "QCborKnownTags", // e.g. qcborstreamreader.h TODO Needs support for enums - "QCborNegativeInteger", // e.g. qcborstreamreader.h TODO Needs support for enums "QtMsgType", // e.g. qdebug.h TODO Needs support for enums "QTextStreamFunction", // e.g. qdebug.h "QFactoryInterface", // qfactoryinterface.h diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index e6b87bc0..3101d917 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -84,6 +84,9 @@ func main() { } var processHeaders []*CppParsedHeader + atr := astTransformRedundant{ + preserve: make(map[string]*CppEnum), + } for _, inputHeader := range includeFiles { @@ -149,6 +152,7 @@ func main() { astTransformChildClasses(parsed) // must be first astTransformOptional(parsed) astTransformOverloads(parsed) + atr.Process(parsed) // Update global state tracker (AFTER astTransformChildClasses) // Currently, this is only used for inner classes diff --git a/cmd/genbindings/transformredundant.go b/cmd/genbindings/transformredundant.go new file mode 100644 index 00000000..f382c9b2 --- /dev/null +++ b/cmd/genbindings/transformredundant.go @@ -0,0 +1,31 @@ +package main + +// astTransformRedundant merges duplicate enum definitions. +type astTransformRedundant struct { + preserve map[string]*CppEnum +} + +func (a *astTransformRedundant) Process(parsed *CppParsedHeader) { + + for i, e := range parsed.Enums { + prev, ok := a.preserve[e.EnumName] + if !ok { + // It's new + a.preserve[e.EnumName] = &parsed.Enums[i] + continue + } + + // It's pre-existing + if prev.UnderlyingType != e.UnderlyingType { + panic("Enum " + e.EnumName + " is defined multiple times with different underlying types") + } + + // Merge entries + prev.Entries = append(prev.Entries, e.Entries...) + + // Remove from second matched header + // This is difficult to manipulate while preserving pointers, so only + // wipe out the name and use that as a signal later on + parsed.Enums[i].EnumName = "" + } +}