clang2il.go: Check for desugared types (support clang-19+)

* Closes #116
This commit is contained in:
Rick Calixte 2025-01-20 14:10:40 -05:00
parent a80a93966d
commit 24cf11dc28
No known key found for this signature in database
5 changed files with 67 additions and 22 deletions

View File

@ -165,6 +165,48 @@ nextTopLevel:
return &ret, nil // done return &ret, nil // done
} }
// shouldPreferQualType returns true if we should use the qualType instead of
// the desugared type based on certain type patterns
func shouldPreferQualType(qualType string) bool {
if strings.Contains(qualType, "intptr") || strings.Contains(qualType, "_t") ||
strings.HasPrefix(qualType, "uint") || strings.Contains(qualType, "ushort") ||
strings.Contains(qualType, "quint") || strings.Contains(qualType, "qint") ||
strings.Contains(qualType, "qptrdiff") || strings.HasPrefix(qualType, "qsize") ||
strings.HasPrefix(qualType, "QList<") || strings.HasPrefix(qualType, "QPair<") ||
strings.HasPrefix(qualType, "QIntegerForSizeof<") {
return true
}
return false
}
// getPreferredType returns either the desugared type or qual type based on our rules
func getPreferredType(node interface{}) string {
if node == nil {
return ""
}
nodeMap, ok := node.(map[string]interface{})
if !ok {
return ""
}
var desugared, qualType string
if d, ok := nodeMap["desugaredQualType"].(string); ok {
desugared = d
}
if q, ok := nodeMap["qualType"].(string); ok {
qualType = q
}
if qualType != "" && shouldPreferQualType(qualType) {
return qualType
}
if desugared != "" {
return desugared
}
return qualType
}
// processTypedef parses a single C++ typedef into our intermediate format. // processTypedef parses a single C++ typedef into our intermediate format.
func processTypedef(node map[string]interface{}, addNamePrefix string) (CppTypedef, error) { func processTypedef(node map[string]interface{}, addNamePrefix string) (CppTypedef, error) {
// Must have a name // Must have a name
@ -174,7 +216,8 @@ func processTypedef(node map[string]interface{}, addNamePrefix string) (CppTyped
} }
if typ, ok := node["type"].(map[string]interface{}); ok { if typ, ok := node["type"].(map[string]interface{}); ok {
if qualType, ok := typ["qualType"].(string); ok { qualType := getPreferredType(typ)
if qualType != "" {
return CppTypedef{ return CppTypedef{
Alias: addNamePrefix + nodename, Alias: addNamePrefix + nodename,
UnderlyingType: parseSingleTypeString(qualType), UnderlyingType: parseSingleTypeString(qualType),
@ -264,7 +307,8 @@ func processClassType(node map[string]interface{}, addNamePrefix string) (CppCla
} }
if typ, ok := base["type"].(map[string]interface{}); ok { if typ, ok := base["type"].(map[string]interface{}); ok {
if qualType, ok := typ["qualType"].(string); ok { qualType := getPreferredType(typ)
if qualType != "" {
ret.DirectInherits = append(ret.DirectInherits, qualType) ret.DirectInherits = append(ret.DirectInherits, qualType)
} }
} }
@ -512,8 +556,9 @@ func processEnum(node map[string]interface{}, addNamePrefix string) (CppEnum, er
// Underlying type // Underlying type
ret.UnderlyingType = parseSingleTypeString("int") ret.UnderlyingType = parseSingleTypeString("int")
if nodefut, ok := node["fixedUnderlyingType"].(map[string]interface{}); ok { if nodefut, ok := node["fixedUnderlyingType"].(map[string]interface{}); ok {
if nodequal, ok := nodefut["qualType"].(string); ok { qualType := getPreferredType(nodefut)
ret.UnderlyingType = parseSingleTypeString(nodequal) if qualType != "" {
ret.UnderlyingType = parseSingleTypeString(qualType)
} }
} }
@ -652,11 +697,11 @@ nextEnumEntry:
func parseMethod(node map[string]interface{}, mm *CppMethod) error { func parseMethod(node map[string]interface{}, mm *CppMethod) error {
if typobj, ok := node["type"].(map[string]interface{}); ok { if typobj, ok := node["type"].(map[string]interface{}); ok {
if qualType, ok := typobj["qualType"].(string); ok { qualType := getPreferredType(typobj)
if qualType != "" {
// The qualType is the whole type of the method, including its parameter types // The qualType is the whole type of the method, including its parameter types
// If anything here is too complicated, skip the whole method // If anything here is too complicated, skip the whole method
var err error
var err error = nil
mm.ReturnType, mm.Parameters, mm.IsConst, err = parseTypeString(qualType) mm.ReturnType, mm.Parameters, mm.IsConst, err = parseTypeString(qualType)
if err != nil { if err != nil {
return err return err

View File

@ -14,27 +14,27 @@ func TestParseMethodTypes(t *testing.T) {
} }
cases := []testCase{ cases := []testCase{
testCase{ {
input: "void (bool)", input: "void (bool)",
expectReturn: CppParameter{ParameterType: "void"}, expectReturn: CppParameter{ParameterType: "void"},
expectParams: []CppParameter{ expectParams: []CppParameter{
CppParameter{ParameterType: "bool"}, {ParameterType: "bool"},
}, },
}, },
testCase{ {
input: "bool (QList<QPair<Foo, Bar>>, QString)", input: "bool (QList<QPair<Foo, Bar>>, QString)",
expectReturn: CppParameter{ParameterType: "bool"}, expectReturn: CppParameter{ParameterType: "bool"},
expectParams: []CppParameter{ expectParams: []CppParameter{
CppParameter{ParameterType: "QList<QPair<Foo, Bar>>"}, {ParameterType: "QList<QPair<Foo, Bar>>"},
CppParameter{ParameterType: "QString"}, {ParameterType: "QString"},
}, },
// expectErr: true, // expectErr: true,
}, },
testCase{ {
input: "bool (QList<QWidget*>)", input: "bool (QList<QWidget*>)",
expectReturn: CppParameter{ParameterType: "bool"}, expectReturn: CppParameter{ParameterType: "bool"},
expectParams: []CppParameter{ expectParams: []CppParameter{
CppParameter{ParameterType: "QList<QWidget*>"}, {ParameterType: "QList<QWidget*>"},
}, },
}, },
} }

View File

@ -9,17 +9,17 @@ func TestChildClassesExtract(t *testing.T) {
src := CppParsedHeader{ src := CppParsedHeader{
Classes: []CppClass{ Classes: []CppClass{
CppClass{ {
ClassName: "Parent", ClassName: "Parent",
ChildClassdefs: []CppClass{ ChildClassdefs: []CppClass{
CppClass{ {
ClassName: "Parent::Child", ClassName: "Parent::Child",
ChildClassdefs: []CppClass{ ChildClassdefs: []CppClass{
CppClass{ {
ClassName: "Parent::Child::Grandchild", ClassName: "Parent::Child::Grandchild",
}, },
}, },

View File

@ -12,11 +12,11 @@ func TestTransformTypedefs(t *testing.T) {
return CppParsedHeader{ return CppParsedHeader{
Classes: []CppClass{ Classes: []CppClass{
CppClass{ {
ClassName: "QTestClass", ClassName: "QTestClass",
Ctors: []CppMethod{ Ctors: []CppMethod{
CppMethod{ {
Parameters: []CppParameter{ Parameters: []CppParameter{
parseSingleTypeString(typeName), parseSingleTypeString(typeName),
}, },

View File

@ -1,9 +1,9 @@
package main package main
import ( import (
"strconv"
"encoding/json" "encoding/json"
"log" "log"
"strconv"
"strings" "strings"
) )
@ -12,7 +12,7 @@ func maybeSuffix(counter int) string {
return "" return ""
} }
return strconv.Itoa(counter+1) return strconv.Itoa(counter + 1)
} }
func titleCase(s string) string { func titleCase(s string) string {
@ -53,4 +53,4 @@ func slice_copy[T comparable](input []T) []T {
ret[i] = elem ret[i] = elem
} }
return ret return ret
} }