1
0
Fork 0

Fix typed pointer casting: .assumingMemoryBound for C functions, remove double g_object_ref_sink in constructors

This commit is contained in:
Brendan Szymanski 2026-07-01 17:49:00 -04:00
parent 4a60aff56d
commit 50a42b2d83
5 changed files with 47 additions and 23 deletions

View file

@ -225,16 +225,18 @@ public struct CodeGenerator {
let parentClause = cls.parent.map { ": \($0)" } ?? ""
swift += "public \(classKeyword) \(cls.name)\(parentClause) {\n"
let cPointer = "pointer.assumingMemoryBound(to: \(cls.cType).self)"
swift += """
let pointer: UnsafeMutableRawPointer
public init(pointer: UnsafeMutableRawPointer) {
g_object_ref_sink(pointer)
g_object_ref_sink(\(cPointer))
self.pointer = pointer
}
deinit {
g_object_unref(pointer)
g_object_unref(\(cPointer))
}
@ -267,7 +269,7 @@ public struct CodeGenerator {
let returnTypeStr = fn.returnType == .void ? "" : " -> \(Self.typeToSwift(fn.returnType))"
let returnStmt = fn.returnType == .void ? "" : "return "
let args = params.map { p -> String in
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames)
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType)
}.joined(separator: ", ")
let cCall = "\(fn.cIdentifier)(\(args))"
let wrappedReturn = Self.wrapCReturnValue(callExpression: cCall, returnType: fn.returnType)
@ -312,12 +314,11 @@ public struct CodeGenerator {
"\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))"
}.joined(separator: ", ")
let args = params.map { p -> String in
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames)
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType)
}.joined(separator: ", ")
swift += """
\(methodVisibility) convenience init(\(methodName): String? = nil, \(paramList)) {
let ptr = \(method.cIdentifier)(\(args))
g_object_ref_sink(ptr)
self.init(pointer: ptr!)
}
@ -329,7 +330,7 @@ public struct CodeGenerator {
}.joined(separator: ", ")
let returnTypeStr = method.returnType == .void ? "" : " -> \(Self.typeToSwift(method.returnType))"
let returnStmt = method.returnType == .void ? "" : "return "
let cCall = Self.generateCFunctionCall(method: method, instancePointer: "pointer", classTypeNames: classTypeNames)
let cCall = Self.generateCFunctionCall(method: method, instancePointer: "pointer", classTypeNames: classTypeNames, cType: cls.cType)
swift += """
\(methodVisibility) func \(methodName)(\(paramList))\(returnTypeStr) {
@ -546,7 +547,7 @@ public struct CodeGenerator {
let returnStmt = fn.returnType == .void ? "" : "return "
let args = params.map { p -> String in
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames)
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType)
}.joined(separator: ", ")
let cCall = "\(fn.cIdentifier)(\(args))"
let wrappedReturn = Self.wrapCReturnValue(callExpression: cCall, returnType: fn.returnType)
@ -587,7 +588,7 @@ public struct CodeGenerator {
get {
var value = GValue()
g_value_init(&value, \(cTypeName))
g_object_get_property(pointer, "\(girPropName)", &value)
g_object_get_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value)
let result = \(getterFunc)(&value)
g_value_unset(&value)
return result
@ -596,7 +597,7 @@ public struct CodeGenerator {
var value = GValue()
g_value_init(&value, \(cTypeName))
\(setterFunc)(&value, newValue)
g_object_set_property(pointer, "\(girPropName)", &value)
g_object_set_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value)
g_value_unset(&value)
}
}
@ -608,7 +609,7 @@ public struct CodeGenerator {
public var \(propName): \(swiftType) {
var value = GValue()
g_value_init(&value, \(cTypeName))
g_object_get_property(pointer, "\(girPropName)", &value)
g_object_get_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value)
let result = \(getterFunc)(&value)
g_value_unset(&value)
return result
@ -623,7 +624,7 @@ public struct CodeGenerator {
var value = GValue()
g_value_init(&value, \(cTypeName))
\(setterFunc)(&value, newValue)
g_object_set_property(pointer, "\(girPropName)", &value)
g_object_set_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value)
g_value_unset(&value)
}
}
@ -723,13 +724,12 @@ public struct CodeGenerator {
"\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))"
}.joined(separator: ", ")
let args = params.map { p -> String in
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames)
Self.cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType)
}.joined(separator: ", ")
return """
public convenience init(\(paramList)) {
let ptr = \(constructor.cIdentifier)(\(args))
g_object_ref_sink(ptr)
self.init(pointer: ptr!)
}
@ -739,11 +739,14 @@ public struct CodeGenerator {
// MARK: - C Function Call Generation
public static func generateCFunctionCall(method: Method, instancePointer: String, classTypeNames: Set<String>? = nil) -> String {
public static func generateCFunctionCall(method: Method, instancePointer: String, classTypeNames: Set<String>? = nil, cType: String = "") -> String {
let typedInstancePointer = (instancePointer == "pointer" && !cType.isEmpty)
? "pointer.assumingMemoryBound(to: \(cType).self)"
: instancePointer
let sortedParams = Self.nonVarargParameters(method.parameters)
let args = sortedParams.map { p -> String in
if p.isInstanceParameter { return instancePointer }
return cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames)
if p.isInstanceParameter { return typedInstancePointer }
return cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType)
}.joined(separator: ", ")
let cFuncCall = "\(method.cIdentifier)(\(args))"
@ -763,7 +766,12 @@ public struct CodeGenerator {
/// - classTypeNames: The set of class type names that have a `.pointer`
/// property. Types NOT in this set are passed directly.
/// - Returns: A Swift expression string for the C function argument.
private static func cParameterExpression(name: String, type: GIRType, classTypeNames: Set<String>? = nil) -> String {
private static func typedPointerCast(expression: String, cType: String) -> String {
let stripped = cType.hasSuffix("*") ? String(cType.dropLast()) : cType
return "\(expression).assumingMemoryBound(to: \(stripped).self)"
}
private static func cParameterExpression(name: String, type: GIRType, classTypeNames: Set<String>? = nil, cType: String = "") -> String {
let usesPointer: Bool
switch type {
case .typeRef(let refName, _):
@ -782,10 +790,22 @@ public struct CodeGenerator {
switch type {
case .typeRef:
return usesPointer ? "\(name).pointer" : name
if usesPointer {
if !cType.isEmpty {
return Self.typedPointerCast(expression: "\(name).pointer", cType: cType)
}
return "\(name).pointer"
}
return name
case .optional(let inner):
if case .typeRef = inner {
return usesPointer ? "\(name)?.pointer" : name
if usesPointer {
if !cType.isEmpty {
return "\(name)?.pointer.map { \(Self.typedPointerCast(expression: "$0", cType: cType)) }"
}
return "\(name)?.pointer"
}
return name
}
return name
default:

View file

@ -222,8 +222,12 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate {
case "type":
let typeName = attributeDict["name"] ?? "none"
let resolvedType = parseGIRType(typeName)
let cType = attributeDict["c:type"] ?? ""
if currentParameter != nil {
currentParameter?.type = resolvedType
if !cType.isEmpty {
currentParameter?.cType = cType
}
} else if currentReturnType != nil {
currentReturnType = resolvedType
} else if currentProperty != nil {