diff --git a/Sources/SwiftGtkGenCore/BindingPlan.swift b/Sources/SwiftGtkGenCore/BindingPlan.swift new file mode 100644 index 0000000..3ad4b0c --- /dev/null +++ b/Sources/SwiftGtkGenCore/BindingPlan.swift @@ -0,0 +1,544 @@ +// BindingPlan.swift +// Types describing the outcome of binding analysis: which symbols were bound, +// which were skipped, and why. This file is the foundation of the binding-plan +// layer — the explicit marshalling plans (`CallablePlan` et al.) that replace +// direct IR-to-string code generation are added here as the layer is built out. + +import Foundation + +/// Whether a mapped type's Swift declaration has been generated yet. +/// The planner uses this to defer callables that reference types not yet +/// emitted (e.g. functions taking `Source` before the `Source` class is +/// generated). +public enum BindingCategory: String, Equatable, Sendable { + /// Primitive, enum, bitfield, string, or alias — no dependencies. + case ready + /// Object or interface — needs a class/stub before callables can use it. + case needsClass + /// Boxed record — needs a record wrapper. + case needsRecord + /// A type that will never be generated (foreign, unknown). + case unavailable +} + +// MARK: - Value Marshalling + +/// How a Swift value is marshalled **into** a C function call argument. +/// +/// Describes the transformation applied to each parameter before the call. +/// The renderer never sees `GIRType` — it only combines these marshalling +/// shapes with the plan's type names. +public enum MarshalIn: Equatable, Sendable { + /// Passed directly with no conversion (e.g. `Int32` → `gint32`). + case direct + /// Passed through a numeric cast to the target type (e.g. `Int` → `gint8`). + /// - Parameter targetType: The Swift numeric type to cast to. + case numericCast(targetType: String) + /// Convert `Bool` to `gboolean` via `? 1 : 0`. + case boolToGboolean + /// Convert `String` to a C string (`withCString` / `utf8` pointer). + case stringToC + /// Access the underlying pointer of an object or interface wrapper. + case objectPointer + /// Pass the `rawValue` of an enum (Int → C int). + case enumRaw + /// Pass the `rawValue` of a bitfield (UInt32 → C uint). + case bitfieldRaw + /// Pass the pointer of a boxed record wrapper. + case boxedPointer + /// Unsupported — causes the whole callable to be skipped. + /// - Parameter reason: Why the parameter cannot be marshalled. + case unsupported(reason: String) +} + +/// How a C return value is marshalled **out** into Swift. +/// +/// Describes the transformation applied to the C function's return value +/// to produce the Swift-typed result that callers see. +public enum MarshalOut: Equatable, Sendable { + /// Direct assignment with no conversion. + case direct + /// Cast from a C numeric type to the target Swift type. + /// - Parameter fromType: The C type being cast from. + case numericCast(fromType: String) + /// Convert `gboolean` (Int32) to `Bool` via `!= 0`. + case gbooleanToBool + /// Copy a C string, optionally freeing the source. + /// - Parameter free: When `true`, the caller owns the string and must `g_free` it. + case stringCopy(free: Bool) + /// Wrap an object pointer, optionally sinking a floating ref. + /// - Parameter sink: When `true`, call `g_object_ref_sink` (for InitiallyUnowned constructors). + case objectWrap(sink: Bool) + /// Wrap an object pointer with `g_object_ref` (for transfer=none returns). + case objectRetain + /// Convert an integer raw value to an enum case. + /// - Parameter swiftType: The fully qualified Swift enum type name. + case enumFromRaw(swiftType: String) + /// Convert a C flags value to a Swift `OptionSet` bitfield. + /// - Parameter swiftType: The fully qualified Swift bitfield type name. + case bitfieldFromRaw(swiftType: String) + /// Wrap a boxed record pointer, optionally copying. + /// - Parameter copy: When `true`, call `g_boxed_copy` (for transfer=none). + case boxedWrap(copy: Bool) + /// Unsupported — causes the whole callable to be skipped. + /// - Parameter reason: Why the return value cannot be marshalled. + case unsupported(reason: String) +} + +/// How a type is accessed through the GValue machinery. +/// +/// Properties without a GIR `getter=` / `setter=` annotation fall back to +/// `g_object_get` / `g_object_set`, which dispatches through the GType system. +/// These ops supply the correct `g_value_get_*` / `g_value_set_*` calls and +/// any follow-on cast for the type. +public struct GValueOps: Equatable, Sendable { + /// The GType macro name used with `g_object_get`/`_set`. + /// Examples: `"G_TYPE_INT"`, `"G_TYPE_STRING"`, `"G_TYPE_OBJECT"`. + public let typeMacro: String + /// The `g_value_get_*` function suffix, e.g. `"int"`, `"enum"`, `"boxed"`. + public let getterSuffix: String + /// The `g_value_set_*` function suffix, e.g. `"int"`, `"enum"`, `"boxed"`. + public let setterSuffix: String + /// Whether the getter result needs a cast to the specific type (e.g. + /// `g_value_get_enum` returns a bare `gint` and must be cast to the enum). + public let needsCast: Bool + + public init(typeMacro: String, getterSuffix: String, setterSuffix: String, needsCast: Bool = false) { + self.typeMacro = typeMacro; self.getterSuffix = getterSuffix + self.setterSuffix = setterSuffix; self.needsCast = needsCast + } +} + +/// The reason a GIR symbol was excluded from binding generation. +/// +/// Every symbol the generator cannot (or should not) bind is skipped as a +/// whole, with one of these reasons recorded in the module's ``SkipReport``. +/// The compile gate diffs reports against a committed baseline: a new skip in +/// a category the generator claims to support is a regression. +public enum SkipReason: String, Codable, CaseIterable, Sendable { + /// The symbol references a namespace with no loaded GIR (e.g. `cairo`). + case foreignNamespace + /// A parameter, return, or field type could not be resolved. + case unknownType + /// The callable is variadic (`...` / `va_list`), which cannot be bridged. + case varargs + /// The callable has an unsupported `direction="out"` parameter. + case outParameter + /// The callable has an unsupported `direction="inout"` parameter. + case inoutParameter + /// A C array parameter or return has no length annotation. + case arrayWithoutLength + /// The type involves a container (GList, GSList, GHashTable, …) that is + /// not yet bridged. + case containerType + /// A callback parameter has no user-data slot, so a Swift closure cannot + /// be attached. + case callbackWithoutUserData + /// A callback parameter has a `scope` the generator does not support. + case unsupportedCallbackScope + /// The record has no GType registration and no configured lifetime + /// functions, so it cannot be safely wrapped. + case plainRecord + /// The record is a class/interface structure (`glib:is-gtype-struct-for`) + /// and is never bound. + case gtypeStruct + /// The symbol is marked `introspectable="0"` in the GIR. + case notIntrospectable + /// The symbol is deprecated and configured for removal. + case deprecatedRemoved + /// The symbol is shadowed by another (`shadowed-by`). + case shadowedSymbol + /// The symbol was explicitly ignored via configuration. + case configIgnored + /// A property type has no supported GValue accessor category. + case unsupportedGValueCategory +} + +/// A single skipped symbol: what was skipped, and why. +/// +/// Entries are written to `skip-reports/.json` by the CLI and diffed +/// by `scripts/compile-gate.sh` against `docs/skip-baseline/`. +public struct SkipEntry: Codable, Equatable, Sendable { + /// Fully qualified GIR symbol name, e.g. `"Gtk.Widget.measure"`. + public let symbol: String + /// The C identifier of the symbol, when known (e.g. `"gtk_widget_measure"`). + public let cIdentifier: String? + /// The category of the skip. + public let reason: SkipReason + /// Human-readable specifics, e.g. `"parameter 'baseline' has direction=out"`. + public let detail: String + + /// Creates a skip entry. + /// + /// - Parameters: + /// - symbol: Fully qualified GIR symbol name. + /// - cIdentifier: The C identifier, if known. + /// - reason: The skip category. + /// - detail: Human-readable specifics for the report. + public init(symbol: String, cIdentifier: String? = nil, reason: SkipReason, detail: String) { + self.symbol = symbol + self.cIdentifier = cIdentifier + self.reason = reason + self.detail = detail + } +} + +/// Binding coverage statistics for one generated module. +/// +/// Coverage is the fraction of introspectable callables that received a +/// complete binding plan. The compile gate requires coverage to be +/// monotonically non-decreasing across changes. +public struct CoverageStats: Codable, Equatable, Sendable { + /// Number of callables successfully planned and emitted. + public var boundCallables: Int + /// Total introspectable callables considered (bound + skipped). + public var totalCallables: Int + /// Number of types successfully planned and emitted. + public var boundTypes: Int + /// Total introspectable types considered (bound + skipped). + public var totalTypes: Int + + /// Creates coverage statistics. + /// + /// - Parameters: + /// - boundCallables: Callables successfully planned and emitted. + /// - totalCallables: Total introspectable callables considered. + /// - boundTypes: Types successfully planned and emitted. + /// - totalTypes: Total introspectable types considered. + public init(boundCallables: Int = 0, totalCallables: Int = 0, boundTypes: Int = 0, totalTypes: Int = 0) { + self.boundCallables = boundCallables + self.totalCallables = totalCallables + self.boundTypes = boundTypes + self.totalTypes = totalTypes + } +} + +/// The complete skip report for one generated module. +/// +/// Serialized as stable, sorted, pretty-printed JSON so reports are +/// line-diffable by the compile gate and reviewable in version control. +public struct SkipReport: Codable, Equatable, Sendable { + /// The Swift module this report describes (e.g. `"GLib"`). + public let module: String + /// All skipped symbols, sorted by symbol name. + public let entries: [SkipEntry] + /// Coverage statistics for the module. + public let stats: CoverageStats + + /// Creates a skip report, sorting entries by symbol name for stable output. + /// + /// - Parameters: + /// - module: The Swift module name. + /// - entries: Skipped symbols in any order; stored sorted. + /// - stats: Coverage statistics for the module. + public init(module: String, entries: [SkipEntry], stats: CoverageStats) { + self.module = module + self.entries = entries.sorted { $0.symbol < $1.symbol } + self.stats = stats + } + + /// Encodes the report as stable pretty-printed JSON with sorted keys. + /// + /// - Returns: UTF-8 JSON data suitable for writing to disk and diffing. + /// - Throws: An `EncodingError` if serialization fails. + public func jsonData() throws -> Data { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + return try encoder.encode(self) + } +} + +// MARK: - Type Plans + +/// The binding plan for a single GIR type (enum, bitfield, constant, alias, +/// class, interface, record, or callback). The renderer consumes these and +/// never sees `GIRType`, `IRModel`, or the registry directly. +public enum TypePlan: Sendable { + /// An enumeration with deduplicated raw values. + case enumeration(EnumPlan) + /// An OptionSet bitfield with verbatim raw values. + case bitfield(BitfieldPlan) + /// A global constant. + case constant(ConstantPlan) + /// A type alias. + case alias(AliasPlan) + /// A GObject class wrapper. + case `class`(ClassPlan) + /// A GObject interface wrapper. + case interface(InterfacePlan) + /// A boxed record wrapper. + case record(RecordPlan) + /// A callable (function, method, or constructor). + case callable(CallablePlan) +} + +/// The plan for a GIR enumeration: cases and alias variables (deduplicated +/// raw values). +public struct EnumPlan: Equatable, Sendable { + /// The Swift enum name (unqualified), e.g. `"ConnectFlags"`. + public let name: String + /// The C type name, e.g. `"GConnectFlags"`. + public let cType: String + /// The primary cases (first occurrence of each raw value). + public let cases: [EnumCase] + /// Duplicate raw values emitted as `public static var` aliases. + public let aliases: [EnumAlias] + /// Whether this enum has a GType registration (for GValue access). + public let hasGType: Bool + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, cType: String, cases: [EnumCase], aliases: [EnumAlias], + hasGType: Bool = false, doc: String? = nil) { + self.name = name; self.cType = cType; self.cases = cases + self.aliases = aliases; self.hasGType = hasGType; self.doc = doc + } +} + +/// A single case of an enumeration: name, raw value, and C identifier. +public struct EnumCase: Equatable, Sendable { + /// The Swift case name (keyword-escaped), e.g. `"after"`. + public let name: String + /// The numeric raw value as a string, e.g. `"1"`. + public let rawValue: String + /// The full C identifier, e.g. `"G_CONNECT_AFTER"`. + public let cIdentifier: String + + public init(name: String, rawValue: String, cIdentifier: String) { + self.name = name; self.rawValue = rawValue; self.cIdentifier = cIdentifier + } +} + +/// A duplicate raw-value member emitted as a `public static var` alias. +public struct EnumAlias: Equatable, Sendable { + /// The alias variable name, e.g. `"baselineFill"`. + public let name: String + /// The primary case this alias points to, e.g. `"baseline"`. + public let targetCaseName: String + + public init(name: String, targetCaseName: String) { + self.name = name; self.targetCaseName = targetCaseName + } +} + +/// The plan for a GIR bitfield (flags type) emitted as an `OptionSet`. +public struct BitfieldPlan: Equatable, Sendable { + /// The Swift struct name (unqualified), e.g. `"ConnectFlags"`. + public let name: String + /// The C type name, e.g. `"GConnectFlags"`. + public let cType: String + /// The flag members with their verbatim raw values. + public let members: [EnumCase] + /// Whether this bitfield has a GType registration. + public let hasGType: Bool + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, cType: String, members: [EnumCase], + hasGType: Bool = false, doc: String? = nil) { + self.name = name; self.cType = cType; self.members = members + self.hasGType = hasGType; self.doc = doc + } +} + +/// The plan for a global constant. +public struct ConstantPlan: Equatable, Sendable { + /// The Swift name of the constant, e.g. `"MAJOR_VERSION"`. + public let name: String + /// The literal value as a string, e.g. `"2"`. + public let value: String + /// The Swift type of the constant, e.g. `"Int"`. + public let swiftType: String + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, value: String, swiftType: String, doc: String? = nil) { + self.name = name; self.value = value; self.swiftType = swiftType; self.doc = doc + } +} + +/// The plan for a type alias. +public struct AliasPlan: Equatable, Sendable { + /// The Swift alias name, e.g. `"MyType"`. + public let name: String + /// The target type name, module-qualified when cross-module. + public let swiftType: String + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, swiftType: String, doc: String? = nil) { + self.name = name; self.swiftType = swiftType; self.doc = doc + } +} + +/// The plan for a GObject class wrapper. +public struct ClassPlan: Equatable, Sendable { + /// The Swift class name (unqualified), e.g. `"Object"`. + public let name: String + /// The C type name, e.g. `"GObject"`. + public let cType: String + /// The module-qualified Swift parent class name, or `nil` for root. + /// E.g. `nil` for `GObject.Object`, `"GObject.InitiallyUnowned"` for `Gtk.Widget`. + public let parent: String? + /// Whether the class is `open` (subclassed by at least one other type). + public let isOpen: Bool + /// Whether the class is abstract — no constructors emitted. + public let isAbstract: Bool + /// The `glib:get-type` function name, e.g. `"g_object_get_type"`. + public let getTypeFunction: String? + /// Whether this class descends from `InitiallyUnowned`, requiring + /// `g_object_ref_sink` on construction. + public let descendsFromInitiallyUnowned: Bool + /// Planned constructors (empty for abstract classes). + public let constructors: [CallablePlan] + /// Planned instance methods. + public let methods: [CallablePlan] + /// Planned static/class functions. + public let functions: [CallablePlan] + /// Module-qualified names of implemented interfaces (e.g. ["GObject.TypePlugin"]). + public let interfaces: [String] + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, cType: String, parent: String? = nil, + isOpen: Bool = false, isAbstract: Bool = false, + getTypeFunction: String? = nil, + descendsFromInitiallyUnowned: Bool = false, + interfaces: [String] = [], + constructors: [CallablePlan] = [], methods: [CallablePlan] = [], + functions: [CallablePlan] = [], doc: String? = nil) { + self.name = name; self.cType = cType; self.parent = parent + self.isOpen = isOpen; self.isAbstract = isAbstract + self.getTypeFunction = getTypeFunction + self.descendsFromInitiallyUnowned = descendsFromInitiallyUnowned + self.interfaces = interfaces + self.constructors = constructors; self.methods = methods + self.functions = functions; self.doc = doc + } +} + +/// The plan for a boxed record wrapper (opaque pointer class). +public struct RecordPlan: Equatable, Sendable { + public let name: String + public let cType: String + public let getTypeFunction: String? + public let copyFunction: String? + public let freeFunction: String? + public let doc: String? + + public init(name: String, cType: String, getTypeFunction: String? = nil, + copyFunction: String? = nil, freeFunction: String? = nil, + doc: String? = nil) { + self.name = name; self.cType = cType + self.getTypeFunction = getTypeFunction + self.copyFunction = copyFunction; self.freeFunction = freeFunction + self.doc = doc + } +} + +/// The plan for a GObject interface wrapper. +public struct InterfacePlan: Equatable, Sendable { + public let name: String + public let cType: String + public let prereqs: [String] + public let getTypeFunction: String? + public let doc: String? + + public init(name: String, cType: String, prereqs: [String] = [], + getTypeFunction: String? = nil, doc: String? = nil) { + self.name = name; self.cType = cType; self.prereqs = prereqs + self.getTypeFunction = getTypeFunction; self.doc = doc + } +} + +/// The complete plan for one Swift module: every type planned, every symbol +/// skipped, and the coverage statistics computed from them. +public struct ModulePlan: Sendable { + /// The Swift module name, e.g. `"GLib"`. + public let module: String + /// All successfully planned types. + public let types: [TypePlan] + /// Every skipped symbol with its reason. + public let skips: [SkipEntry] + /// Coverage statistics derived from planned and skipped counts. + public let coverage: CoverageStats + + public init(module: String, types: [TypePlan], skips: [SkipEntry], + coverage: CoverageStats) { + self.module = module; self.types = types; self.skips = skips + self.coverage = coverage + } + + /// The skip report serialised from this module's skips and coverage. + public var skipReport: SkipReport { + SkipReport(module: module, entries: skips, stats: coverage) + } +} + +// MARK: - Callable Plans + +/// The complete binding plan for one callable (function, method, or constructor). +/// +/// Every parameter has been fully mapped by the TypeMapper; the renderer only +/// combines the `Mapping` values into a Swift function signature and a C call. +public struct CallablePlan: Equatable, Sendable { + /// The Swift name of the function/method/constructor (keyword-escaped). + public let name: String + /// The C function identifier, e.g. `"gtk_widget_set_visible"`. + public let cIdentifier: String + /// The parameters in Swift declaration order. + public let parameters: [ParameterPlan] + /// The return mapping, or `nil` for a void function. + public let returnMapping: Mapping? + /// `true` when this callable is a class/static function (not an instance + /// method). Constructor callables are implicitly static. + public let isStatic: Bool + /// `true` when this callable is a constructor. + public let isConstructor: Bool + /// The ownership init variant for constructor callables: `nil` for + /// non-constructors; `.takingOwnership`, `.retaining`, or + /// `.sinkingRef` for constructors. + public let ownershipInit: OwnershipInit? + /// Documentation from the GIR `` element. + public let doc: String? + + public init(name: String, cIdentifier: String, parameters: [ParameterPlan], + returnMapping: Mapping? = nil, isStatic: Bool = false, + isConstructor: Bool = false, ownershipInit: OwnershipInit? = nil, + doc: String? = nil) { + self.name = name; self.cIdentifier = cIdentifier; self.parameters = parameters + self.returnMapping = returnMapping; self.isStatic = isStatic + self.isConstructor = isConstructor; self.ownershipInit = ownershipInit + self.doc = doc + } +} + +/// How a constructor takes ownership of the new GObject instance. +public enum OwnershipInit: String, Equatable, Sendable { + /// `transfer-ownership="full"`: store the pointer, no additional ref. + case takingOwnership + /// `transfer-ownership="none"`, non-floating: call `g_object_ref`. + case retaining + /// The class descends from `InitiallyUnowned`: call `g_object_ref_sink`. + case sinkingRef +} + +/// One parameter of a `CallablePlan`: its Swift name, C argument position, +/// and the complete type mapping. +public struct ParameterPlan: Equatable, Sendable { + /// The Swift parameter name (keyword-escaped). + public let swiftName: String + /// The zero-based index in the C function's argument list (all parameters, + /// including instance parameter). + public let cArgIndex: Int + /// The complete type mapping for this parameter. + public let mapping: Mapping + /// `true` when this parameter is the implicit instance (`self`). + public let isInstanceParameter: Bool + + public init(swiftName: String, cArgIndex: Int, mapping: Mapping, + isInstanceParameter: Bool = false) { + self.swiftName = swiftName; self.cArgIndex = cArgIndex + self.mapping = mapping; self.isInstanceParameter = isInstanceParameter + } +} diff --git a/Sources/SwiftGtkGenCore/CodeGen+Scaffolding.swift b/Sources/SwiftGtkGenCore/CodeGen+Scaffolding.swift index a9458a0..17e4f94 100644 --- a/Sources/SwiftGtkGenCore/CodeGen+Scaffolding.swift +++ b/Sources/SwiftGtkGenCore/CodeGen+Scaffolding.swift @@ -187,7 +187,11 @@ extension CodeGenerator { var cTargets = "" for name in moduleNames { let cName = "C\(name)" - cTargets += " .systemLibrary(name: \"\(cName)\", path: \"Sources/\(cName)\"),\n" + let pkgConfigName = analysis.repositories[name]?.packageName ?? "" + let pkgConfigArg = pkgConfigName.isEmpty + ? "" + : ", pkgConfig: \"\(pkgConfigName)\", providers: [.apt([\"\(pkgConfigName)\"]), .brew([\"\(pkgConfigName)\"])]" + cTargets += " .systemLibrary(name: \"\(cName)\", path: \"Sources/\(cName)\"\(pkgConfigArg)),\n" } // Swift wrapper targets @@ -216,7 +220,6 @@ extension CodeGenerator { let swiftSettings: [SwiftSetting] = [ .enableExperimentalFeature("StrictConcurrency=complete"), .defaultIsolation(MainActor.self), - .enableUpcomingFeature("NonisolatedNonsendingByDefault"), ] let package = Package( diff --git a/Sources/SwiftGtkGenCore/CodeGen+Signal.swift b/Sources/SwiftGtkGenCore/CodeGen+Signal.swift deleted file mode 100644 index b5f6541..0000000 --- a/Sources/SwiftGtkGenCore/CodeGen+Signal.swift +++ /dev/null @@ -1,118 +0,0 @@ -import Foundation - -extension CodeGenerator { - // MARK: - Signal Connection Generation - - /// Generates a signal connection method using `g_signal_connect_data`. - /// - /// The method takes a Swift closure and bridges it to a C function pointer - /// via `Unmanaged.passRetained`. The retain/release is managed by - /// `GClosureNotify` (the destroy handler passed to `g_signal_connect_data`). - /// - /// For signals with parameters, the C callback receives them as - /// `UnsafeMutableRawPointer?` values which are extracted into Swift types. - /// - /// - Parameters: - /// - signal: The GIR signal to generate. - /// - inhibit: If `true`, the handler returns `Bool` to control signal propagation. - /// - Returns: A signal connection method declaration as a string. - public static func generateSignalConnection(signal: Signal, inhibit: Bool = false) -> String { - let signalName = swiftifySignalName(signal.name) - let handlerReturnType = inhibit ? "Bool" : "Void" - let handlerArgs = signal.parameters.map { p -> String in - let swiftType = typeToSwift(p.type) - return "_: \(swiftType)" - }.joined(separator: ", ") - - let detailClause = signal.isDetailed ? ", \"\(signal.name)\"" : "" - - if signal.parameters.isEmpty { - let callbackReturn = inhibit ? " -> gboolean" : " -> Void" - let handlerCall = inhibit ? "let result = stored(); return result ? 1 : 0" : "stored()" - return """ - public func connect\(signalName)(_ handler: @escaping () -> \(handlerReturnType)) -> Int { - let boxed = Unmanaged.passRetained(handler as AnyObject).toOpaque() - let callback: @convention(c) (UnsafeMutableRawPointer?, UnsafeMutableRawPointer?)\(callbackReturn) = { (_, data) in - let stored = Unmanaged.fromOpaque(data!).takeUnretainedValue() as! () -> \(handlerReturnType) - \(handlerCall) - } - let destroy: @convention(c) (UnsafeMutableRawPointer?) -> Void = { Unmanaged.fromOpaque($0!).release() } - return Int(g_signal_connect_data(pointer, "\(signal.name)", callback, boxed, destroy, 0)) - } - - - """ - } else { - let rawPointerParams = signal.parameters.map { _ in "UnsafeMutableRawPointer?" }.joined(separator: ", ") - let rawPointerNames = signal.parameters.enumerated().map { "p\($0.offset)" }.joined(separator: ", ") - let extractionExprs = signal.parameters.enumerated().map { i, p in - cSignalParameterExtraction(index: i, type: p.type) - }.joined(separator: ", ") - let callbackReturn = inhibit ? " -> gboolean" : " -> Void" - let handlerCall = inhibit - ? "let result = stored(\(extractionExprs)); return result ? 1 : 0" - : "stored(\(extractionExprs))" - return """ - public func connect\(signalName)(_ handler: @escaping (\(handlerArgs)) -> \(handlerReturnType)) -> Int { - let boxed = Unmanaged.passRetained(handler as AnyObject).toOpaque() - let callback: @convention(c) (\(rawPointerParams), UnsafeMutableRawPointer?)\(callbackReturn) = { (\(rawPointerNames), data) in - let stored = Unmanaged.fromOpaque(data!).takeUnretainedValue() as! (\(handlerArgs)) -> \(handlerReturnType) - \(handlerCall) - } - let destroy: @convention(c) (UnsafeMutableRawPointer?) -> Void = { Unmanaged.fromOpaque($0!).release() } - return Int(g_signal_connect_data(pointer, "\(signal.name)"\(detailClause), callback, boxed, destroy, 0)) - } - - - """ - } - } - - /// Generates a Swift expression to extract a signal parameter value from an - /// `UnsafeMutableRawPointer?` received in the C callback trampoline. - /// - /// - Parameters: - /// - index: The zero-based index of the signal parameter. - /// - type: The GIR type of the parameter. - /// - Returns: A Swift expression string that converts `p{index}` to the target type. - private static func cSignalParameterExtraction(index: Int, type: GIRType) -> String { - let p = "p\(index)" - switch type { - case .boolean: - return "Int(bitPattern: \(p)) != 0" - case .int8: - return "Int8(bitPattern: UInt8(bitPattern: Int8(truncatingIfNeeded: Int(bitPattern: \(p)))))" - case .int16: - return "Int16(bitPattern: UInt16(bitPattern: Int16(truncatingIfNeeded: Int(bitPattern: \(p)))))" - case .int32: - return "Int32(bitPattern: Int32(truncatingIfNeeded: Int(bitPattern: \(p))))" - case .int64: - return "\(p)!.load(as: Int64.self)" - case .uint8: - return "UInt8(bitPattern: UInt8(truncatingIfNeeded: Int(bitPattern: \(p))))" - case .uint16: - return "UInt16(bitPattern: UInt16(truncatingIfNeeded: Int(bitPattern: \(p))))" - case .uint32: - return "UInt32(bitPattern: UInt32(truncatingIfNeeded: Int(bitPattern: \(p))))" - case .uint64: - return "\(p)!.load(as: UInt64.self)" - case .float: - return "\(p)!.load(as: Float.self)" - case .double: - return "\(p)!.load(as: Double.self)" - case .string, .filename: - return "String(cString: \(p)!.assumingMemoryBound(to: CChar.self))" - case .typeRef(let name, _): - return "\(name)(pointer: \(p)!)" - case .pointer: - return "\(p)!" - case .optional(let inner): - if case .typeRef(let name, _) = inner { - return "\(p).map { \(name)(pointer: $0) }" - } - return cSignalParameterExtraction(index: index, type: inner) - default: - return "\(p)!" - } - } -} diff --git a/Sources/SwiftGtkGenCore/CodeGen.swift b/Sources/SwiftGtkGenCore/CodeGen.swift index 81b90f7..b2c51e3 100644 --- a/Sources/SwiftGtkGenCore/CodeGen.swift +++ b/Sources/SwiftGtkGenCore/CodeGen.swift @@ -1,1290 +1,27 @@ import Foundation -/// Errors that can occur during Swift source code generation. -public enum CodeGenError: Error, Equatable { - /// Generation failed with a descriptive message. - case generationFailed(String) -} - -/// Generates Swift source code from a parsed GIR repository and analysis results. -/// -/// Takes the intermediate representation produced by the XML parser, filtered -/// through an ``Analyzer``/``AnalysisResult``, and emits Swift source text -/// containing class wrappers (with GObject reference counting), enumerations, -/// and option sets for bitfields. Generated output targets a single Swift file -/// per invocation. +/// Minimal shim keeping the scaffolding extensions (`CodeGen+Scaffolding.swift`) +/// compilable. The old code-generation engine was deleted in B7; only the +/// Package.swift / module-map / umbrella-header generation survives here. public struct CodeGenerator { - /// The generation configuration controlling output behavior. - public let config: GenerationConfig + public init() {} - /// Creates a new code generator with the given configuration. - /// - Parameter config: The generation configuration. - public init(config: GenerationConfig) { - self.config = config - } - - /// Generates Swift source code for the specified repository. - /// - /// Iterates over all namespaces, classes, enumerations, and bitfields in - /// the repository, producing Swift declarations only for types included - /// in the analysis result. Generated classes include pointer-based storage - /// with `g_object_ref_sink`/`g_object_unref` lifetime management, computed - /// property accessors, method stubs, and signal connection methods. - /// - /// - Parameters: - /// - repository: The parsed GIR repository to generate code from. - /// - analysis: The analysis results specifying which types to generate - /// and any per-type overrides. - /// - Returns: A string containing the generated Swift source code. - /// - Throws: `CodeGenError` if generation fails. - public func generate(repository: Repository, analysis: AnalysisResult) throws -> String { - var output = """ - // Generated by SwiftGtkGen. DO NOT EDIT. - // Source: \(config.library) \(config.version) - - import C\(config.library) - import Foundation - - """ - - for ns in repository.namespaces where ns.name == config.library { - let classNames = Set(ns.classes.map { $0.name }) - - let shouldGenerateAll = analysis.generatedTypes.isEmpty - - for cls in ns.classes { - let fullName = "\(ns.name).\(cls.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateClass(cls, namespace: ns.name, analysis: analysis, classTypeNames: classNames) - } - for enm in ns.enumerations { - let fullName = "\(ns.name).\(enm.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateEnum(enm) - } - for bf in ns.bitfields { - let fullName = "\(ns.name).\(bf.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateBitfield(bf) - } - for iface in ns.interfaces { - let fullName = "\(ns.name).\(iface.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateInterface(iface) - } - for cb in ns.callbacks { - let fullName = "\(ns.name).\(cb.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateCallback(cb) - } - for fn in ns.functions { - let fullName = "\(ns.name).\(fn.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateGlobalFunction(fn, namespace: ns.name, classTypeNames: classNames) - } - for rec in ns.records { - let fullName = "\(ns.name).\(rec.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateRecord(rec, namespace: ns.name, analysis: analysis, classTypeNames: classNames) - } - for cst in ns.constants { - let fullName = "\(ns.name).\(cst.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateConstant(cst) - } - for alias in ns.aliases { - let fullName = "\(ns.name).\(alias.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - output += generateAlias(alias) - } - } - - return output - } - - /// Generates Swift source code split into one file per type. - /// - /// Returns a dictionary mapping filenames (e.g. `"Widget.swift"`) to their - /// generated Swift source code. Each file includes a standard header with - /// `import Foundation` and the generated C interop import, followed by the - /// declaration for that single type. Only types present in the analysis - /// result are included. - /// - /// - Parameters: - /// - repository: The parsed GIR repository to generate code from. - /// - analysis: The analysis results specifying which types to generate. - /// - Returns: A dictionary of filename to generated source code. - /// - Throws: `CodeGenError` if generation fails. - public func generateFiles(repository: Repository, analysis: AnalysisResult) throws -> [String: String] { - var bodies: [String: String] = [:] - - for ns in repository.namespaces where ns.name == config.library { - let classNames = Set(ns.classes.map { $0.name }) - - let shouldGenerateAll = analysis.generatedTypes.isEmpty - - for cls in ns.classes { - let fullName = "\(ns.name).\(cls.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(cls.name).swift"] = generateClass(cls, namespace: ns.name, analysis: analysis, classTypeNames: classNames) - } - for enm in ns.enumerations { - let fullName = "\(ns.name).\(enm.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(enm.name).swift"] = generateEnum(enm) - } - for bf in ns.bitfields { - let fullName = "\(ns.name).\(bf.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(bf.name).swift"] = generateBitfield(bf) - } - for iface in ns.interfaces { - let fullName = "\(ns.name).\(iface.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(iface.name).swift"] = generateInterface(iface) - } - for cb in ns.callbacks { - let fullName = "\(ns.name).\(cb.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(cb.name).swift"] = generateCallback(cb) - } - for fn in ns.functions { - let fullName = "\(ns.name).\(fn.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - let fnFilename = "\(Self.pascalCaseName(fn.name)).swift" - if !bodies.keys.contains(fnFilename) { - bodies[fnFilename] = generateGlobalFunction(fn, namespace: ns.name, classTypeNames: classNames) - } - } - for rec in ns.records { - let fullName = "\(ns.name).\(rec.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - bodies["\(rec.name).swift"] = generateRecord(rec, namespace: ns.name, analysis: analysis, classTypeNames: classNames) - } - for cst in ns.constants { - let fullName = "\(ns.name).\(cst.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - let cstFilename = "\(Self.pascalCaseName(cst.name)).swift" - if !bodies.keys.contains(cstFilename) { - bodies[cstFilename] = generateConstant(cst) - } - } - for alias in ns.aliases { - let fullName = "\(ns.name).\(alias.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - let aliasFilename = "\(Self.pascalCaseName(alias.name)).swift" - if !bodies.keys.contains(aliasFilename) { - bodies[aliasFilename] = generateAlias(alias) - } - } - } - - let header = """ - // Generated by SwiftGtkGen. DO NOT EDIT. - // Source: \(config.library) \(config.version) - - import C\(config.library) - import Foundation - - """ + "\n" + // MARK: - Re-export umbrella files + /// Generates `@_exported import` umbrella files so every dependency is + /// available through a single import of this module. + static func generateReexportUmbrellas(analysis: MultiPackageAnalysis) -> [String: String] { var files: [String: String] = [:] - for (name, body) in bodies { - files[name] = header + body - } - - return files - } - - /// Generates Swift source for all modules in a monorepo. - /// - /// Iterates over all packages in the analysis, producing per-type Swift - /// files for each module. Each file includes the appropriate `import` - /// statements for the module's direct dependencies. - /// - /// - Parameter analysis: The resolved multi-package analysis. - /// - Returns: Module name → (filename → source code) nested dictionary. - /// - Throws: `CodeGenError` if generation fails. - public func generateMonorepo(analysis: MultiPackageAnalysis) throws -> [String: [String: String]] { - var allOutputs: [String: [String: String]] = [:] - - for (moduleName, repo) in analysis.repositories { - guard let cfg = analysis.packageConfigs[moduleName] else { continue } - guard let ns = repo.namespaces.first(where: { $0.name == moduleName }) - ?? repo.namespaces.first else { continue } - - let directImports = analysis.directDependencies[moduleName] ?? [] - - let rootModuleName = moduleName - - let analyzer = Analyzer(config: cfg) - let singleAnalysis = analyzer.analyze(repository: repo) - - let classNames = Set(ns.classes.map(\.name)) - let shouldGenerateAll = singleAnalysis.generatedTypes.isEmpty - - var sourceFiles: [String: String] = [:] - - let header = fileHeader(moduleName: rootModuleName, directImports: directImports) - - for cls in ns.classes { - let fullName = "\(ns.name).\(cls.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(cls.name).swift"] = header + "\n" + generateClass(cls, namespace: ns.name, analysis: singleAnalysis, classTypeNames: classNames) - } - for enm in ns.enumerations { - let fullName = "\(ns.name).\(enm.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(enm.name).swift"] = header + "\n" + generateEnum(enm) - } - for bf in ns.bitfields { - let fullName = "\(ns.name).\(bf.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(bf.name).swift"] = header + "\n" + generateBitfield(bf) - } - for iface in ns.interfaces { - let fullName = "\(ns.name).\(iface.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(iface.name).swift"] = header + "\n" + generateInterface(iface) - } - for cb in ns.callbacks { - let fullName = "\(ns.name).\(cb.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(cb.name).swift"] = header + "\n" + generateCallback(cb) - } - for fn in ns.functions { - let fullName = "\(ns.name).\(fn.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - let funcFilename = "\(Self.pascalCaseName(fn.name)).swift" - if !sourceFiles.keys.contains(funcFilename) { - sourceFiles[funcFilename] = header + "\n" + generateGlobalFunction(fn, namespace: ns.name, classTypeNames: classNames) - } - } - for rec in ns.records { - let fullName = "\(ns.name).\(rec.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - sourceFiles["\(rec.name).swift"] = header + "\n" + generateRecord(rec, namespace: ns.name, analysis: singleAnalysis, classTypeNames: classNames) - } - for cst in ns.constants { - let fullName = "\(ns.name).\(cst.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - let cstFilename = "\(Self.pascalCaseName(cst.name)).swift" - if !sourceFiles.keys.contains(cstFilename) { - sourceFiles[cstFilename] = header + "\n" + generateConstant(cst) - } - } - for alias in ns.aliases { - let fullName = "\(ns.name).\(alias.name)" - if !shouldGenerateAll && !singleAnalysis.generatedTypes.contains(fullName) { continue } - let aliasFilename = "\(Self.pascalCaseName(alias.name)).swift" - if !sourceFiles.keys.contains(aliasFilename) { - sourceFiles[aliasFilename] = header + "\n" + generateAlias(alias) - } - } - - allOutputs[rootModuleName] = sourceFiles - } - - return allOutputs - } - - /// Generates re-export umbrella Swift files for each module in the monorepo. - /// - /// Each umbrella file (e.g., `"Sources/Gtk/Gtk.swift"`) contains - /// `@_exported import` statements for all transitive dependencies, - /// so that importing a higher-level module (e.g. `import Gtk`) - /// exposes the full type lattice. - /// - /// - Parameter analysis: The resolved multi-package analysis. - /// - Returns: A dictionary mapping relative file paths (e.g. - /// `"Sources/Gtk/Gtk.swift"`) to file content. - public static func generateReexportUmbrellas(analysis: MultiPackageAnalysis) -> [String: String] { - var umbrellas: [String: String] = [:] - - for (moduleName, _) in analysis.repositories { - let transitive = analysis.transitiveDependencies[moduleName] ?? [] - var content = "// Generated by SwiftGtkGen. DO NOT EDIT.\n\n" + let header = "// Generated by SwiftGtkGen. DO NOT EDIT.\n\n" + for (moduleName, transitive) in analysis.transitiveDependencies { + guard !transitive.isEmpty else { continue } + var content = header for dep in transitive.sorted() { content += "@_exported import \(dep)\n" } content += "\n" - umbrellas["Sources/\(moduleName)/\(moduleName).swift"] = content + files["Sources/\(moduleName)/\(moduleName).swift"] = content } - - return umbrellas - } - - /// Generates the standard file header for monorepo source files. - private func fileHeader(moduleName: String, directImports: Set) -> String { - var imports = "import C\(moduleName)\nimport Foundation\n" - for imp in directImports.sorted() { - imports += "import \(imp)\n" - } - return """ - // Generated by SwiftGtkGen. DO NOT EDIT. - - \(imports) - """ - } - - // MARK: - Class Generation - - /// Generates a Swift class declaration from a GIR class definition. - /// - /// Produces a `final class` or `open class` (depending on overrides) with: - /// - An `UnsafeMutableRawPointer` backing field and `init(pointer:)` that - /// calls `g_object_ref_sink` / `g_object_unref` in `deinit` - /// - Computed properties for readable/writable GObject properties - /// - Method stubs for each GIR method - /// - Signal connection methods for each GIR signal - /// - /// - Parameters: - /// - cls: The GIR class to generate. - /// - namespace: The GIR namespace the class belongs to (e.g. `"Gtk"`). - /// - analysis: The analysis result containing per-type overrides. - /// - Returns: A Swift class declaration as a string. - private func generateClass(_ cls: Class, namespace: String, analysis: AnalysisResult, classTypeNames: Set = []) -> String { - var swift = "" - let override = analysis.classOverrides["\(namespace).\(cls.name)"] - let concurrency = override?.concurrency ?? .none - let inheritedMethods = analysis.inheritedMethodNames["\(namespace).\(cls.name)"] ?? [] - - swift += Self.formatDocComment(cls.doc) - if concurrency == .mainActor { swift += "@MainActor\n" } - if let cfg = override?.cfgCondition { swift += "#if \(cfg)\n" } - let userWantsFinal = override?.finalType ?? true - let hasSubclasses = analysis.typesWithSubclasses.contains("\(namespace).\(cls.name)") - let isFinal = userWantsFinal && !hasSubclasses - // `open` is itself an access-level modifier (implies public visibility), - // so emit just `open class` (no `public` prefix) when the class is non-final. - // For `final class`, keep the `public` prefix. - let classKeyword = isFinal ? "public final class" : "open class" - let parentClause = cls.parent.map { ": \($0)" } ?? "" - swift += "\(classKeyword) \(cls.name)\(parentClause) {\n" - - let cPointer = "pointer.assumingMemoryBound(to: \(cls.cType).self)" - - // A class needs its own `pointer` if either: - // (a) it has no parent (true root), or - // (b) its parent lives in a different Swift module (cross-namespace - // reference like "GObject.InitiallyUnowned"). In that case the - // parent is just a typealias, not an inheritable Swift class. - let parent = cls.parent ?? "" - let isCrossNamespaceParent = parent.contains(".") - let isRootForNamespace = cls.parent == nil || isCrossNamespaceParent - if isRootForNamespace { - swift += """ - let pointer: UnsafeMutableRawPointer - - public init(pointer: UnsafeMutableRawPointer) { - g_object_ref_sink(\(cPointer)) - self.pointer = pointer - } - - deinit { - g_object_unref(\(cPointer)) - } - - - """ - } - - for ctor in cls.constructors { - swift += Self.formatDocComment(ctor.doc, indentation: 4) - swift += Self.generateConstructor(constructor: ctor, className: cls.name, classTypeNames: classTypeNames) - } - - for prop in cls.properties { - let propOverride = analysis.propertyOverrides["\(namespace).\(cls.name).\(prop.name)"] - var adjustedProp = prop - if let accessors = propOverride?.generate { - adjustedProp.isReadable = accessors.contains(.get) - adjustedProp.isWritable = accessors.contains(.set) - } - swift += Self.formatDocComment(prop.doc, indentation: 4) - swift += Self.generatePropertyAccessor(property: adjustedProp) - } - - // Class-level functions (static methods) - for fn in cls.functions { - swift += Self.formatDocComment(fn.doc, indentation: 4) - let params = Self.nonVarargParameters(fn.parameters) - let paramList = params.map { p -> String in - let type = Self.typeToSwift(p.type) - return "\(Self.swiftifyParameterName(p.name)): \(type)" - }.joined(separator: ", ") - 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, cType: p.cType) - }.joined(separator: ", ") - let cCall = "\(fn.cIdentifier)(\(args))" - let wrappedReturn = Self.wrapCReturnValue(callExpression: cCall, returnType: fn.returnType) - let staticOverride = inheritedMethods.contains(fn.name) ? "override " : "" - - swift += """ - public static \(staticOverride)func \(Self.swiftifyMethodName(fn.name))(\(paramList))\(returnTypeStr) { - \(returnStmt)\(wrappedReturn) - } - - - """ - } - - for method in cls.methods { - let methodOverride = analysis.functionOverrides["\(namespace).\(cls.name).\(method.name)"] - if methodOverride?.ignore == true { continue } - - var methodName = Self.swiftifyMethodName(method.name) - if let rename = methodOverride?.rename { - if let renamed = Self.applyRenameRule(rename, to: method.name) { - methodName = Self.swiftifyMethodName(renamed) - } - } - for pattern in analysis.functionPatterns where pattern.typeName == "\(namespace).\(cls.name)" { - if Self.globMatches(pattern.pattern, name: method.name) { - if let renamed = Self.applyRenameRule(pattern.rename, to: method.name) { - methodName = Self.swiftifyMethodName(renamed) - } - } - } - - swift += Self.formatDocComment(method.doc, indentation: 4) - - if let cfg = methodOverride?.cfgCondition { swift += "#if \(cfg)\n" } - - let methodVisibility = methodOverride?.visibility?.rawValue ?? "public" - - let isConstructor = methodOverride?.constructor ?? false - let needsOverride = !isConstructor && inheritedMethods.contains(method.name) - let overrideKeyword = needsOverride ? "override " : "" - if isConstructor { - let params = Self.nonVarargParameters(method.parameters.filter { !$0.isInstanceParameter }) - let paramList = params.map { p -> String in - "\(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, cType: p.cType) - }.joined(separator: ", ") - swift += """ - \(methodVisibility) convenience init(\(methodName): String? = nil, \(paramList)) { - let ptr = \(method.cIdentifier)(\(args)) - self.init(pointer: ptr!) - } - - """ - } else { - let params = Self.nonVarargParameters(method.parameters.filter { !$0.isInstanceParameter }) - let paramList = params.map { p -> String in - "\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))" - }.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, cType: cls.cType) - - swift += """ - \(methodVisibility) \(overrideKeyword)func \(methodName)(\(paramList))\(returnTypeStr) { - \(returnStmt)\(cCall) - } - - """ - } - - if let _ = methodOverride?.cfgCondition { swift += "#endif\n" } - } - - for signal in cls.signals { - let sigOverride = analysis.signalOverrides["\(namespace).\(cls.name).\(signal.name)"] - if sigOverride?.ignore == true { continue } - swift += Self.formatDocComment(signal.doc, indentation: 4) - swift += Self.generateSignalConnection(signal: signal, inhibit: sigOverride?.inhibit ?? false) - } - - while swift.hasSuffix("\n") { - swift = String(swift.dropLast()) - } - swift += "\n}\n" - if let _ = override?.cfgCondition { swift += "#endif\n" } - if concurrency == .sendable { - swift += "\nextension \(cls.name): Sendable {}\n" - } - return swift - } - - /// Applies a rename rule's regex replacement to the given string. - /// - Parameters: - /// - rule: The rename rule with regex and replacement. - /// - name: The original name to transform. - /// - Returns: The transformed name, or nil if the regex does not match. - private static func applyRenameRule(_ rule: RenameRule, to name: String) -> String? { - guard let regex = try? NSRegularExpression(pattern: rule.regex, options: []) else { return nil } - let range = NSRange(name.startIndex.. Bool { - var regexStr = "" - for ch in pattern { - if ch == "*" { - regexStr += ".*" - } else if ch == "?" { - regexStr += "." - } else { - regexStr += NSRegularExpression.escapedPattern(for: String(ch)) - } - } - regexStr = "^\(regexStr)$" - guard let regex = try? NSRegularExpression(pattern: regexStr, options: []) else { return false } - let range = NSRange(name.startIndex.. String { - var swift = "" - swift += Self.formatDocComment(enm.doc) - swift += "public enum \(enm.name): Int, Sendable {\n" - for member in enm.members { - let caseName = Self.swiftifyEnumCaseName(member.name) - let formattedValue = Self.formatNumericLiteral(member.value) - swift += " case \(caseName) = \(formattedValue)\n" - } - while swift.hasSuffix("\n") { swift = String(swift.dropLast()) } - swift += "\n}\n" - return swift - } - - // MARK: - Bitfield Generation - - /// Generates a Swift `OptionSet` conformance from a GIR bitfield definition. - /// - /// Produces a struct with an `Int` raw value and static constants using - /// bit-shifted literals (`1 << N`), matching the C bitmask semantics. - /// - /// - Parameter bf: The GIR bitfield to generate. - /// - Returns: A Swift `OptionSet` struct declaration as a string. - private func generateBitfield(_ bf: Bitfield) -> String { - var swift = "" - swift += Self.formatDocComment(bf.doc) - swift += "public struct \(bf.name): OptionSet, Sendable {\n" - swift += " public let rawValue: Int\n" - swift += " public init(rawValue: Int) { self.rawValue = rawValue }\n\n" - for member in bf.members { - let caseName = Self.swiftifyEnumCaseName(member.name) - let formattedValue = Self.formatNumericLiteral(member.value) - swift += " public static let \(caseName) = \(bf.name)(rawValue: 1 << \(formattedValue))\n" - } - while swift.hasSuffix("\n") { swift = String(swift.dropLast()) } - swift += "\n}\n" - return swift - } - - // MARK: - Interface Generation - - /// Generates a Swift protocol declaration from a GIR interface definition. - /// - /// Produces a `protocol` with method requirements (excluding the instance - /// parameter) and computed property requirements for readable/writable - /// properties. Signals are not included since protocol-based signal - /// connection is not directly expressible. - /// - /// - Parameter iface: The GIR interface to generate. - /// - Returns: A Swift protocol declaration as a string. - private func generateInterface(_ iface: Interface) -> String { - var swift = "" - swift += Self.formatDocComment(iface.doc) - swift += "public protocol \(iface.name) {\n" - - for method in iface.methods { - let params = Self.nonVarargParameters(method.parameters.filter { !$0.isInstanceParameter }) - let paramList = params.map { p -> String in - "\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))" - }.joined(separator: ", ") - let returnTypeStr = method.returnType == .void ? "" : " -> \(Self.typeToSwift(method.returnType))" - swift += " func \(Self.swiftifyMethodName(method.name))(\(paramList))\(returnTypeStr)\n" - } - - for prop in iface.properties { - let propName = Self.swiftifyPropertyName(prop.name) - let swiftType = Self.typeToSwift(prop.type) - if prop.isReadable && prop.isWritable { - swift += " var \(propName): \(swiftType) { get set }\n" - } else if prop.isReadable { - swift += " var \(propName): \(swiftType) { get }\n" - } - } - - while swift.hasSuffix("\n") { swift = String(swift.dropLast()) } - swift += "\n}\n" - return swift - } - - // MARK: - Callback Generation - - /// Generates a Swift `typealias` with `@convention(c)` from a GIR callback - /// definition. - /// - /// Produces a public typealias suitable for use as a C function pointer in - /// the generated GObject wrapper APIs. Each callback parameter is mapped - /// to its Swift type, and the return type is preserved. - /// - /// - Parameter cb: The GIR callback to generate. - /// - Returns: A Swift typealias declaration as a string. - private func generateCallback(_ cb: Callback) -> String { - var result = Self.formatDocComment(cb.doc) - let paramList = cb.parameters.map { p -> String in - let cType = Self.callbackParamType(p.type) - return "_ \(Self.swiftifyParameterName(p.name)): \(cType)" - }.joined(separator: ", ") - let returnType = cb.returnType == .void ? "Void" : Self.typeToSwift(cb.returnType) - result += "public typealias \(cb.name) = @convention(c) (\(paramList)) -> \(returnType)\n" - return result - } - - /// Maps a GIR type to the corresponding Swift type for `@convention(c)` callback parameters. - /// GObject type references become `UnsafeMutableRawPointer` since C callbacks - /// pass raw pointers. All other types pass through `typeToSwift` unchanged. - private static func callbackParamType(_ type: GIRType) -> String { - switch type { - case .typeRef: - return "UnsafeMutableRawPointer" - case .optional(let inner): - if case .typeRef = inner { - return "UnsafeMutableRawPointer?" - } - return typeToSwift(type) - default: - return typeToSwift(type) - } - } - - // MARK: - Global Function Generation - - /// Generates a Swift free function from a GIR global function definition. - /// - /// Produces a `public func` that wraps the underlying C function call, - /// including parameter passing (extracting `.pointer` from GObject types) - /// and return value conversion (e.g. `String(cString:)` for strings, - /// `!= 0` for booleans). - /// - /// - Parameters: - /// - fn: The GIR global function to generate. - /// - namespace: The GIR namespace the function belongs to. - /// - Returns: A Swift function declaration as a string. - private func generateGlobalFunction(_ fn: GlobalFunction, namespace: String, classTypeNames: Set = []) -> String { - let params = Self.nonVarargParameters(fn.parameters) - let paramList = params.map { p -> String in - "\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))" - }.joined(separator: ", ") - 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, cType: p.cType) - }.joined(separator: ", ") - let cCall = "\(fn.cIdentifier)(\(args))" - let wrappedReturn = Self.wrapCReturnValue(callExpression: cCall, returnType: fn.returnType) - - var result = Self.formatDocComment(fn.doc) - result += "public func \(Self.swiftifyMethodName(fn.name))(\(paramList))\(returnTypeStr) {\n" - result += " \(returnStmt)\(wrappedReturn)\n" - result += "}\n" - return result - } - - // MARK: - Property Accessor Generation - - /// Generates a Swift computed property declaration for a GObject property - /// using the `GValue` API (`g_object_get_property`/`g_object_set_property`). - /// - /// Construct-only properties return an empty string since they are handled - /// via constructor parameters rather than runtime setters. - /// - /// - Parameter property: The GIR property to generate an accessor for. - /// - Returns: A Swift computed property declaration string, or empty if - /// the property is construct-only. - public static func generatePropertyAccessor(property: Property) -> String { - guard !property.isConstructOnly else { return "" } - - let propName = swiftifyPropertyName(property.name) - let swiftType = typeToSwift(property.type) - let cTypeName = gValueTypeName(for: property.type) - let getterFunc = gValueGetterFunc(for: property.type) - let setterFunc = gValueSetterFunc(for: property.type) - let girPropName = property.name - - var swift = "" - - if property.isReadable && property.isWritable { - swift += """ - public var \(propName): \(swiftType) { - get { - var value = GValue() - g_value_init(&value, \(cTypeName)) - g_object_get_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value) - let result = \(getterFunc)(&value) - g_value_unset(&value) - return result - } - set { - var value = GValue() - g_value_init(&value, \(cTypeName)) - \(setterFunc)(&value, newValue) - g_object_set_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value) - g_value_unset(&value) - } - } - - - """ - } else if property.isReadable { - swift += """ - public var \(propName): \(swiftType) { - var value = GValue() - g_value_init(&value, \(cTypeName)) - g_object_get_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value) - let result = \(getterFunc)(&value) - g_value_unset(&value) - return result - } - - - """ - } else if property.isWritable { - swift += """ - public var \(propName): \(swiftType) { - set { - var value = GValue() - g_value_init(&value, \(cTypeName)) - \(setterFunc)(&value, newValue) - g_object_set_property(pointer.assumingMemoryBound(to: GObject.self), "\(girPropName)", &value) - g_value_unset(&value) - } - } - - - """ - } - - return swift - } - - /// Returns the GType name constant for the given GIR type. - private static func gValueTypeName(for type: GIRType) -> String { - switch type { - case .boolean: return "G_TYPE_BOOLEAN" - case .int8: return "G_TYPE_INT8" - case .int16: return "G_TYPE_INT16" - case .int32: return "G_TYPE_INT" - case .int64: return "G_TYPE_INT64" - case .uint8: return "G_TYPE_UINT8" - case .uint16: return "G_TYPE_UINT16" - case .uint32: return "G_TYPE_UINT" - case .uint64: return "G_TYPE_UINT64" - case .float: return "G_TYPE_FLOAT" - case .double: return "G_TYPE_DOUBLE" - case .string, .filename: return "G_TYPE_STRING" - case .typeRef: return "G_TYPE_OBJECT" - case .pointer: return "G_TYPE_POINTER" - case .array: return "G_TYPE_ARRAY" - case .cArray: return "G_TYPE_ARRAY" - case .void: return "G_TYPE_NONE" - case .optional: return "G_TYPE_NONE" - } - } - - /// Returns the GValue getter function name for the given GIR type. - private static func gValueGetterFunc(for type: GIRType) -> String { - switch type { - case .boolean: return "g_value_get_boolean" - case .int8: return "g_value_get_schar" - case .int16: return "g_value_get_int16" - case .int32: return "g_value_get_int" - case .int64: return "g_value_get_int64" - case .uint8: return "g_value_get_uchar" - case .uint16: return "g_value_get_uint16" - case .uint32: return "g_value_get_uint" - case .uint64: return "g_value_get_uint64" - case .float: return "g_value_get_float" - case .double: return "g_value_get_double" - case .string, .filename: return "g_value_get_string" - case .typeRef: return "g_value_get_object" - case .pointer: return "g_value_get_pointer" - case .array: return "g_value_get_boxed" - case .cArray: return "g_value_get_boxed" - default: return "g_value_get_pointer" - } - } - - /// Returns the GValue setter function name for the given GIR type. - private static func gValueSetterFunc(for type: GIRType) -> String { - switch type { - case .boolean: return "g_value_set_boolean" - case .int8: return "g_value_set_schar" - case .int16: return "g_value_set_int16" - case .int32: return "g_value_set_int" - case .int64: return "g_value_set_int64" - case .uint8: return "g_value_set_uchar" - case .uint16: return "g_value_set_uint16" - case .uint32: return "g_value_set_uint" - case .uint64: return "g_value_set_uint64" - case .float: return "g_value_set_float" - case .double: return "g_value_set_double" - case .string, .filename: return "g_value_set_string" - case .typeRef: return "g_value_set_object" - case .pointer: return "g_value_set_pointer" - default: return "g_value_set_pointer" - } - } - - // MARK: - Constructor Generation - - /// Generates a Swift convenience initializer for a GObject constructor. - /// - /// Calls the C constructor function (e.g. `gtk_button_new_with_label(label)`) - /// and handles the floating reference pattern by calling `g_object_ref_sink` - /// on the returned pointer before passing it to `self.init(pointer:)`. - /// This is correct for all `GtkWidget` subclasses and is harmless for - /// non-floating objects (where `g_object_ref_sink` simply refs once). - /// - /// - Parameters: - /// - constructor: The GIR constructor definition. - /// - className: The Swift class name. - /// - Returns: A convenience initializer declaration as a string. - public static func generateConstructor(constructor: Constructor, className: String, classTypeNames: Set? = nil) -> String { - let params = Self.nonVarargParameters(constructor.parameters) - let paramList = params.map { p -> String in - "\(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, cType: p.cType) - }.joined(separator: ", ") - - return """ - public convenience init(\(paramList)) { - let ptr = \(constructor.cIdentifier)(\(args)) - self.init(pointer: ptr!) - } - - - """ - } - - // MARK: - C Function Call Generation - - public static func generateCFunctionCall(method: Method, instancePointer: String, classTypeNames: Set? = 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 typedInstancePointer } - return cParameterExpression(name: Self.swiftifyParameterName(p.name), type: p.type, classTypeNames: classTypeNames, cType: p.cType) - }.joined(separator: ", ") - - let cFuncCall = "\(method.cIdentifier)(\(args))" - return wrapCReturnValue(callExpression: cFuncCall, returnType: method.returnType) - } - - /// Returns the Swift argument expression for a parameter of the given type. - /// - /// Extracts `.pointer` from GObject wrapper types and handles optional - /// GObject pointers with optional chaining. Boolean values are converted - /// from Swift `Bool` to C `gboolean` (Int32) via `? 1 : 0`. Optional - /// booleans use a nested ternary that yields `0` when the value is - /// `nil`. All other types (enums, bitfields, records) pass through as-is - /// since they are value types without a `.pointer` property. - /// - /// - Parameters: - /// - name: The Swift parameter name. - /// - type: The GIR type of the parameter. - /// - 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 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? = nil, cType: String = "") -> String { - let usesPointer: Bool - switch type { - case .typeRef(let refName, _): - // When classTypeNames is nil, default to .pointer (backward compatible). - // When set, only use .pointer for types in the set. - usesPointer = classTypeNames.map { $0.contains(refName) } ?? true - case .optional(let inner): - if case .typeRef(let refName, _) = inner { - usesPointer = classTypeNames.map { $0.contains(refName) } ?? true - } else { - usesPointer = false - } - default: - usesPointer = false - } - - switch type { - case .typeRef: - if usesPointer { - if !cType.isEmpty { - return Self.typedPointerCast(expression: "\(name).pointer", cType: cType) - } - return "\(name).pointer" - } - return name - case .boolean: - return "\(name) ? 1 : 0" - case .optional(let inner): - if case .typeRef = inner { - if usesPointer { - if !cType.isEmpty { - return "\(name)?.pointer.map { \(Self.typedPointerCast(expression: "$0", cType: cType)) }" - } - return "\(name)?.pointer" - } - return name - } - if case .boolean = inner { - return "\(name).map { $0 ? 1 : 0 } ?? 0" - } - return name - default: - return name - } - } - - /// Wraps a C function call expression to convert its return value to the - /// corresponding Swift type. - /// - /// - `.void` returns the bare call expression (no `return` statement). - /// - `.boolean` compares the result to `0` via `cFunc() != 0`. - /// - `.string` / `.filename` wraps with `String(cString:)`. - /// - `.typeRef` wraps in the Swift wrapper type's initializer. - /// - `.optional(.typeRef)` uses `Optional.map` to wrap non-nil results. - /// - All other types pass through directly. - /// - /// - Parameters: - /// - callExpression: The raw C function call expression. - /// - returnType: The GIR return type. - /// - Returns: A Swift expression string with appropriate type wrapping. - static func wrapCReturnValue(callExpression: String, returnType: GIRType) -> String { - switch returnType { - case .void: - return callExpression - case .boolean: - return "(\(callExpression) != 0)" - case .string, .filename: - return "String(cString: \(callExpression))" - case .typeRef(let name, _): - return "\(name)(pointer: \(callExpression))" - case .optional(let inner): - if case .typeRef(let name, _) = inner { - return "\(callExpression).map { \(name)(pointer: $0) }" - } - if case .string = inner { - return "\(callExpression).map { String(cString: $0) }" - } - if case .filename = inner { - return "\(callExpression).map { String(cString: $0) }" - } - if case .boolean = inner { - return "\(callExpression).map { $0 != 0 }" - } - return callExpression - default: - return callExpression - } - } - - // MARK: - Documentation Comment Formatting - - /// Formats a documentation string as DocC-compatible `///` comments. - /// - Parameter doc: The raw documentation text from the GIR file. - /// - Returns: A string of `///`-prefixed lines, or empty string if nil/empty. - private static func formatDocComment(_ doc: String?, indentation: Int = 0) -> String { - guard let doc = doc, !doc.isEmpty else { return "" } - let indent = String(repeating: " ", count: indentation) - let lines = doc.split(separator: "\n", omittingEmptySubsequences: false) - var result = "" - for line in lines { - let trimmed = line.trimmingCharacters(in: .whitespaces) - if trimmed.isEmpty { - result += "\(indent)///\n" - } else { - result += "\(indent)/// \(trimmed)\n" - } - } - return result - } - - // MARK: - Formatting Helpers - - /// Formats a numeric literal string with underscore separators for readability. - /// For example, `"4294967295"` becomes `"4_294_967_295"`. - private static func formatNumericLiteral(_ value: String) -> String { - guard value.count > 4, let _ = Int(value) else { return value } - var result = "" - var remaining = value - while remaining.count > 3 { - let chunk = remaining.suffix(3) - remaining = String(remaining.dropLast(3)) - result = "_\(chunk)" + result - } - return remaining + result - } - - // MARK: - Naming Helpers - - /// Maps a GIR type to its corresponding Swift type name string. - /// - /// Handles primitive types (`boolean` → `Bool`, `int32` → `Int32`, etc.), - /// type references (looked up by name), and compound types (arrays, - /// C-style arrays, optionals). Pointers and filenames map to - /// `UnsafeMutableRawPointer` and `String` respectively. - /// - /// - Parameter type: The GIR type to map. - /// - Returns: The Swift type name as a string. - static func typeToSwift(_ type: GIRType) -> String { - switch type { - case .void: return "Void" - case .boolean: return "Bool" - case .int8: return "Int8" - case .int16: return "Int16" - case .int32: return "Int32" - case .int64: return "Int64" - case .uint8: return "UInt8" - case .uint16: return "UInt16" - case .uint32: return "UInt32" - case .uint64: return "UInt64" - case .float: return "Float" - case .double: return "Double" - case .string: return "String" - case .filename: return "String" - case .pointer: return "UnsafeMutableRawPointer" - case .typeRef(let name, _): return name - case .array(let inner): return "[\(typeToSwift(inner))]" - case .cArray(let inner): return "UnsafeBufferPointer<\(typeToSwift(inner))>" - case .optional(let inner): return "\(typeToSwift(inner))?" - } - } - - /// Converts a GIR type to a Swift type string, qualifying cross-namespace - /// type references with their Swift module name prefix. - /// - /// Cross-namespace references (`.typeRef(name, namespace: "Gdk")`) produce - /// `Gdk.Rectangle` when the current module is not `Gdk`. Same-namespace - /// references produce the bare `name`. - /// - /// - Parameters: - /// - type: The GIR type to map. - /// - currentModule: The Swift module name currently being generated. - /// - nsToModule: Map from GIR namespace name to Swift module name. - /// - Returns: A qualified Swift type name. - static func qualifiedTypeToSwift(_ type: GIRType, currentModule: String, nsToModule: [String: String]) -> String { - switch type { - case .typeRef(let name, let namespace): - if let ns = namespace, let module = nsToModule[ns], module != currentModule { - return "\(module).\(name)" - } - return name - case .array(let inner): return "[\(qualifiedTypeToSwift(inner, currentModule: currentModule, nsToModule: nsToModule))]" - case .cArray(let inner): return "UnsafeBufferPointer<\(qualifiedTypeToSwift(inner, currentModule: currentModule, nsToModule: nsToModule))>" - case .optional(let inner): return "\(qualifiedTypeToSwift(inner, currentModule: currentModule, nsToModule: nsToModule))?" - default: return Self.typeToSwift(type) - } - } - - /// Converts a snake_case GIR name to a camelCase Swift property name. - /// - /// Splits on underscores and lowercases the first part while capitalizing - /// each subsequent part. For example, `"current_page"` becomes - /// `"currentPage"`. - /// - /// - Parameter name: The snake_case GIR property name. - /// - Returns: A camelCase Swift property name. - private static func swiftifyPropertyName(_ name: String) -> String { - name.split { $0 == "_" || $0 == "-" }.enumerated().map { i, part in - i == 0 ? String(part).lowercased() : String(part).capitalized - }.joined() - } - - /// The set of Swift reserved keywords that cannot be used as identifiers - /// without backtick escaping. - private static let reservedKeywords: Set = [ - "self", "type", "class", "default", "in", "for", "repeat", "while", - "switch", "case", "break", "continue", "return", "if", "else", - "guard", "defer", "do", "try", "throw", "catch", "import", "let", - "var", "func", "static", "struct", "enum", "protocol", "extension", - "init", "deinit", "subscript", "where", "operator", "Protocol", - "rethrows", "associatedtype", "precedencegroup", - "true", "false", "nil", "Self", "Type", - "private", "fileprivate", "internal", "public", "open", - "is", "as", "async", "await", "nonisolated", "throws", - ] - - /// Converts a GIR parameter name to a valid Swift identifier. - /// - /// Applies camelCase conversion (via ``swiftifyPropertyName(_:)``) and - /// backtick-escapes the result if it collides with a Swift reserved - /// keyword such as `self`, `class`, `default`, or `return`. - /// - /// - Parameter name: The raw GIR parameter name. - /// - Returns: A valid Swift parameter label, backtick-escaped if needed. - private static func swiftifyParameterName(_ name: String) -> String { - let swiftName = swiftifyPropertyName(name) - return reservedKeywords.contains(swiftName) ? "`\(swiftName)`" : swiftName - } - - private static func swiftifyMethodName(_ name: String) -> String { - let swiftName = Self.swiftifyPropertyName(name) - return reservedKeywords.contains(swiftName) ? "`\(swiftName)`" : swiftName - } - - /// Converts a GIR signal name (kebab-case) to a PascalCase Swift identifier. - /// - /// Splits on hyphens and capitalizes each component. For example, - /// `"page-changed"` becomes `"PageChanged"`, suitable for use in - /// `connectPageChanged(_:)`. - /// - /// - Parameter name: The kebab-case GIR signal name. - /// - Returns: A PascalCase Swift method name component. - static func swiftifySignalName(_ name: String) -> String { - name.split(separator: "-").map { $0.capitalized }.joined() - } - - /// Converts a GIR enum case name (SCREAMING_SNAKE_CASE) to a camelCase Swift case. - /// - /// Lowercases the entire string, splits on underscores, and lowercases the - /// first word while capitalizing subsequent words. For example, - /// `"GTK_WIDGET_HELP"` becomes `"gtkWidgetHelp"`. Handles reserved keyword - /// collisions (backtick-escapes) and identifiers starting with digits (prefixes - /// with underscore). - /// - /// - Parameter name: The GIR enum case name, typically in SCREAMING_SNAKE_CASE. - /// - Returns: A valid camelCase Swift enum case name. - private static func swiftifyEnumCaseName(_ name: String) -> String { - let lower = name.lowercased() - let parts = lower.split { $0 == "_" || $0 == "-" } - var result = parts.enumerated().map { i, p in - i == 0 ? String(p) : String(p).capitalized - }.joined() - - // Prefix with underscore if starts with a digit - if result.first?.isNumber == true { - result = "_" + result - } - - // Backtick-escape Swift keywords - if reservedKeywords.contains(result) { - result = "`\(result)`" - } - - return result - } - - /// Converts a snake_case or kebab-case name to PascalCase. - /// - /// Splits on underscores and hyphens and capitalizes each component. - /// For example, `"gtk_init"` becomes `"GtkInit"`. - private static func pascalCaseName(_ name: String) -> String { - name.split { $0 == "_" || $0 == "-" }.map { $0.capitalized }.joined() - } - - /// Filters out variadic C parameters (those named `"..."` or empty) from a parameter list. - private static func nonVarargParameters(_ params: [Parameter]) -> [Parameter] { - params.filter { $0.name != "..." && !$0.name.isEmpty } - } - - // MARK: - Record, Constant, Alias Generation - - /// Generates a Swift struct declaration from a GIR record definition. - /// - /// Produces a public struct with fields mapped to Swift `let` properties - /// and methods that operate on the record via inout `&self` pointer. - /// - /// - Parameters: - /// - rec: The GIR record to generate. - /// - namespace: The GIR namespace the record belongs to. - /// - analysis: The analysis result containing per-type overrides. - /// - Returns: A Swift struct declaration as a string. - private func generateRecord(_ rec: Record, namespace: String, analysis: AnalysisResult, classTypeNames: Set = []) -> String { - var swift = "" - swift += Self.formatDocComment(rec.doc) - - let override = analysis.classOverrides["\(namespace).\(rec.name)"] - let concurrency = override?.concurrency ?? .none - if concurrency == .mainActor { swift += "@MainActor " } - - swift += "public struct \(rec.name): Sendable {\n" - - for field in rec.fields { - swift += Self.formatDocComment(field.doc, indentation: 4) - swift += " public let \(Self.swiftifyPropertyName(field.name)): \(Self.typeToSwift(field.type))\n" - } - - for method in rec.methods { - swift += Self.formatDocComment(method.doc, indentation: 4) - let params = Self.nonVarargParameters(method.parameters.filter { !$0.isInstanceParameter }) - let paramList = params.map { p in - "\(Self.swiftifyParameterName(p.name)): \(Self.typeToSwift(p.type))" - }.joined(separator: ", ") - let returnTypeStr = method.returnType == .void ? "" : " -> \(Self.typeToSwift(method.returnType))" - let returnStmt = method.returnType == .void ? "" : "return " - let funcName = Self.swiftifyMethodName(method.name) - let cCall = Self.generateCFunctionCall(method: method, instancePointer: "&self", classTypeNames: classTypeNames) - swift += " public mutating func \(funcName)(\(paramList))\(returnTypeStr) {\n" - swift += " \(returnStmt)\(cCall)\n" - swift += " }\n\n" - } - - swift += "}\n" - return swift - } - - /// Generates a Swift constant declaration from a GIR constant definition. - /// - /// - Parameter cst: The GIR constant to generate. - /// - Returns: A Swift `public let` declaration as a string. - private func generateConstant(_ cst: Constant) -> String { - var swift = Self.formatDocComment(cst.doc) - let typeName = Self.typeToSwift(cst.type) - let name = Self.swiftifyPropertyName(cst.name) - let escapedName = Self.reservedKeywords.contains(name) ? "`\(name)`" : name - let formattedValue: String - switch cst.type { - case .string, .filename: - formattedValue = "\"\(cst.value)\"" - default: - formattedValue = cst.value - } - swift += "public let \(escapedName): \(typeName) = \(formattedValue)\n" - return swift - } - - /// Generates a Swift typealias declaration from a GIR alias definition. - /// - /// - Parameter alias: The GIR alias to generate. - /// - Returns: A Swift `public typealias` declaration as a string. - private func generateAlias(_ alias: Alias) -> String { - var swift = Self.formatDocComment(alias.doc) - swift += "public typealias \(alias.name) = \(Self.typeToSwift(alias.target))\n" - return swift + return files } } diff --git a/Sources/SwiftGtkGenCore/IRModel.swift b/Sources/SwiftGtkGenCore/IRModel.swift index cb23bb6..72020d0 100644 --- a/Sources/SwiftGtkGenCore/IRModel.swift +++ b/Sources/SwiftGtkGenCore/IRModel.swift @@ -102,7 +102,19 @@ public struct Class { /// The name of the parent class, or `nil` for the root `GObject` class. public let parent: String? /// Whether this class is abstract and cannot be instantiated directly. + /// + /// Abstract classes are emitted without constructors: the C library + /// provides no way to instantiate them directly. public var isAbstract: Bool + /// Whether GIR marks the class final (`final="1"`), forbidding subclassing. + public var isFinal: Bool + /// The `glib:get-type` function registering this class's GType, + /// e.g. `"gtk_widget_get_type"`. + public var getTypeFunction: String? + /// The registered GType name from `glib:type-name`, e.g. `"GtkWidget"`. + public var typeName: String? + /// GIR metadata governing whether this class should be bound at all. + public var symbolInfo: SymbolInfo /// The names of interfaces this class implements. public var implements: [String] /// The constructors for this class. @@ -123,6 +135,10 @@ public struct Class { /// - cType: The corresponding C type name, e.g. `"GtkWidget"`. /// - parent: The name of the parent class, or `nil` if root. /// - isAbstract: Whether the class is abstract. Defaults to `false`. + /// - isFinal: Whether GIR marks the class final. Defaults to `false`. + /// - getTypeFunction: The `glib:get-type` function name, if any. + /// - typeName: The registered GType name, if any. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - implements: The names of implemented interfaces. Defaults to empty. /// - constructors: The constructors. Defaults to empty. /// - methods: The methods. Defaults to empty. @@ -131,11 +147,15 @@ public struct Class { /// - functions: The associated functions. Defaults to empty. /// - doc: Documentation comment from the GIR XML. public init(name: String, cType: String, parent: String?, isAbstract: Bool = false, + isFinal: Bool = false, getTypeFunction: String? = nil, typeName: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), implements: [String] = [], constructors: [Constructor] = [], methods: [Method] = [], properties: [Property] = [], signals: [Signal] = [], functions: [GlobalFunction] = [], doc: String? = nil) { self.name = name; self.cType = cType; self.parent = parent - self.isAbstract = isAbstract; self.implements = implements + self.isAbstract = isAbstract; self.isFinal = isFinal + self.getTypeFunction = getTypeFunction; self.typeName = typeName + self.symbolInfo = symbolInfo; self.implements = implements self.constructors = constructors; self.methods = methods self.properties = properties; self.signals = signals; self.functions = functions self.doc = doc @@ -165,6 +185,12 @@ public struct Interface { public var functions: [GlobalFunction] /// The prerequisite types a class must satisfy to implement this interface. public var prereqs: [String] + /// The `glib:get-type` function registering this interface's GType. + public var getTypeFunction: String? + /// The registered GType name from `glib:type-name`, e.g. `"GtkBuildable"`. + public var typeName: String? + /// GIR metadata governing whether this interface should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new interface definition. /// - Parameters: /// - name: The interface name. @@ -174,12 +200,18 @@ public struct Interface { /// - signals: The signals declared by the interface. Defaults to empty. /// - functions: The functions associated with this interface. Defaults to empty. /// - prereqs: The prerequisite types. Defaults to empty. + /// - getTypeFunction: The `glib:get-type` function name, if any. + /// - typeName: The registered GType name, if any. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. public init(name: String, cType: String, methods: [Method] = [], properties: [Property] = [], - signals: [Signal] = [], functions: [GlobalFunction] = [], prereqs: [String] = [], doc: String? = nil) { + signals: [Signal] = [], functions: [GlobalFunction] = [], prereqs: [String] = [], + getTypeFunction: String? = nil, typeName: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { self.name = name; self.cType = cType; self.methods = methods self.properties = properties; self.signals = signals; self.functions = functions; self.prereqs = prereqs - self.doc = doc + self.getTypeFunction = getTypeFunction; self.typeName = typeName + self.symbolInfo = symbolInfo; self.doc = doc } } @@ -199,24 +231,72 @@ public struct Record { public var isOpaque: Bool /// Whether the record is disguised (typedef'd without the `struct` keyword). public var isDisguised: Bool + /// The class or interface whose GObject type struct this record is + /// (`glib:is-gtype-struct-for`), e.g. `"Widget"` for `GtkWidgetClass`. + /// + /// Type structs are implementation details of the GObject type system and + /// are never bound. + public var isGTypeStructFor: String? + /// The `glib:get-type` function registering this record's boxed GType. + /// + /// Its presence is what makes a record a *boxed* type — safely copyable + /// and freeable via `g_boxed_copy`/`g_boxed_free`, and therefore bindable + /// as an opaque pointer wrapper. Records without it are skipped. + public var getTypeFunction: String? + /// The registered GType name from `glib:type-name`, e.g. `"GdkRGBA"`. + public var typeName: String? + /// An explicit copy function from `copy-function`, if the GIR states one. + public var copyFunction: String? + /// An explicit free function from `free-function`, if the GIR states one. + public var freeFunction: String? + /// GIR metadata governing whether this record should be bound at all. + public var symbolInfo: SymbolInfo /// The fields of the record, if introspectable. public var fields: [Field] /// The methods operating on this record. public var methods: [Method] + /// The constructors for this record. + public var constructors: [Constructor] + /// The functions associated with this record. + public var functions: [GlobalFunction] /// Creates a new record definition. /// - Parameters: /// - name: The record name. /// - cType: The corresponding C type name. /// - isOpaque: Whether the record is opaque. Defaults to `false`. /// - isDisguised: Whether the record is disguised. Defaults to `false`. + /// - isGTypeStructFor: The type this record is the GObject type struct for, if any. + /// - getTypeFunction: The `glib:get-type` function name, if any. + /// - typeName: The registered GType name, if any. + /// - copyFunction: An explicit copy function, if stated. + /// - freeFunction: An explicit free function, if stated. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - fields: The fields of the record. Defaults to empty. /// - methods: The record methods. Defaults to empty. + /// - constructors: The record constructors. Defaults to empty. + /// - functions: The associated functions. Defaults to empty. /// - doc: Documentation comment from the GIR XML. public init(name: String, cType: String, isOpaque: Bool = false, isDisguised: Bool = false, - fields: [Field] = [], methods: [Method] = [], doc: String? = nil) { + isGTypeStructFor: String? = nil, getTypeFunction: String? = nil, typeName: String? = nil, + copyFunction: String? = nil, freeFunction: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), + fields: [Field] = [], methods: [Method] = [], constructors: [Constructor] = [], + functions: [GlobalFunction] = [], doc: String? = nil) { self.name = name; self.cType = cType; self.isOpaque = isOpaque - self.isDisguised = isDisguised; self.fields = fields; self.methods = methods; self.doc = doc + self.isDisguised = isDisguised; self.isGTypeStructFor = isGTypeStructFor + self.getTypeFunction = getTypeFunction; self.typeName = typeName + self.copyFunction = copyFunction; self.freeFunction = freeFunction + self.symbolInfo = symbolInfo + self.fields = fields; self.methods = methods + self.constructors = constructors; self.functions = functions; self.doc = doc } + + /// Whether this record is a boxed type with a registered GType. + /// + /// Boxed records can be wrapped as opaque pointer classes with + /// `g_boxed_copy`/`g_boxed_free` lifetimes. Non-boxed records are skipped + /// with ``SkipReason/plainRecord``. + public var isBoxed: Bool { getTypeFunction != nil } } /// A field within a C record. @@ -259,14 +339,33 @@ public struct Enumeration { public var doc: String? /// The members (enum values) of this enumeration. public var members: [EnumMember] + /// The `glib:get-type` function registering this enum's GType, if any. + /// + /// Its presence selects `g_value_get_enum`/`g_value_set_enum` for + /// property access; plain C enums without a GType cannot go through GValue. + public var getTypeFunction: String? + /// The registered GType name from `glib:type-name`, e.g. `"GtkAlign"`. + public var typeName: String? + /// The GLib error domain this enumeration defines, if it is an error enum. + public var errorDomain: String? + /// GIR metadata governing whether this enumeration should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new enumeration. /// - Parameters: /// - name: The enumeration name. /// - cType: The corresponding C type name. /// - members: The enum members. Defaults to empty. + /// - getTypeFunction: The `glib:get-type` function name, if any. + /// - typeName: The registered GType name, if any. + /// - errorDomain: The GLib error domain, if this is an error enum. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cType: String, members: [EnumMember] = [], doc: String? = nil) { - self.name = name; self.cType = cType; self.members = members; self.doc = doc + public init(name: String, cType: String, members: [EnumMember] = [], + getTypeFunction: String? = nil, typeName: String? = nil, errorDomain: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { + self.name = name; self.cType = cType; self.members = members + self.getTypeFunction = getTypeFunction; self.typeName = typeName + self.errorDomain = errorDomain; self.symbolInfo = symbolInfo; self.doc = doc } } @@ -304,15 +403,34 @@ public struct Bitfield { /// Documentation comment from the GIR XML `` element. public var doc: String? /// The individual flag members. + /// + /// Member values are the flag's actual numeric value (e.g. `4`), not a bit + /// position — they are used verbatim as `OptionSet` raw values. public var members: [EnumMember] + /// The `glib:get-type` function registering this bitfield's GType, if any. + /// + /// Its presence selects `g_value_get_flags`/`g_value_set_flags` for + /// property access. + public var getTypeFunction: String? + /// The registered GType name from `glib:type-name`, e.g. `"GtkStateFlags"`. + public var typeName: String? + /// GIR metadata governing whether this bitfield should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new bitfield type. /// - Parameters: /// - name: The bitfield type name. /// - cType: The corresponding C type name. /// - members: The flag members. Defaults to empty. + /// - getTypeFunction: The `glib:get-type` function name, if any. + /// - typeName: The registered GType name, if any. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cType: String, members: [EnumMember] = [], doc: String? = nil) { - self.name = name; self.cType = cType; self.members = members; self.doc = doc + public init(name: String, cType: String, members: [EnumMember] = [], + getTypeFunction: String? = nil, typeName: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { + self.name = name; self.cType = cType; self.members = members + self.getTypeFunction = getTypeFunction; self.typeName = typeName + self.symbolInfo = symbolInfo; self.doc = doc } } @@ -330,17 +448,35 @@ public struct Callback { public var doc: String? /// The parameters of the callback function. public var parameters: [Parameter] - /// The return type of the callback function. - public var returnType: GIRType + /// The return value of the callback function. + public var returnValue: ReturnValue + /// Whether the callback takes a trailing `GError**`. + public var throwsGError: Bool + /// GIR metadata governing whether this callback should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new callback type. /// - Parameters: /// - name: The callback type name. /// - cType: The corresponding C type name. /// - parameters: The callback parameters. Defaults to empty. - /// - returnType: The return type. Defaults to `.void`. + /// - returnValue: The return value. Defaults to a `void`, non-transferring return. + /// - throwsGError: Whether the callback takes a `GError**`. Defaults to `false`. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cType: String, parameters: [Parameter] = [], returnType: GIRType = .void, doc: String? = nil) { - self.name = name; self.cType = cType; self.parameters = parameters; self.returnType = returnType; self.doc = doc + public init(name: String, cType: String, parameters: [Parameter] = [], + returnValue: ReturnValue = ReturnValue(), throwsGError: Bool = false, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { + self.name = name; self.cType = cType; self.parameters = parameters + self.returnValue = returnValue; self.throwsGError = throwsGError + self.symbolInfo = symbolInfo; self.doc = doc + } + + /// The index of the parameter carrying user data, if the callback has one. + /// + /// Conventionally the trailing `gpointer user_data`. A callback without + /// such a slot cannot carry a Swift closure. + public var userDataParameterIndex: Int? { + parameters.lastIndex { $0.type == .pointer && $0.name.contains("data") } } } @@ -358,18 +494,32 @@ public struct Constructor { public var doc: String? /// The parameters accepted by the constructor. public var parameters: [Parameter] - /// The return type — typically the constructed object type. - public var returnType: GIRType + /// The return value — typically the constructed object type. + /// + /// Note that GIR declares most widget constructors `transfer-ownership="none"` + /// even though they return a *floating* reference. The planner therefore + /// derives sinking from the class's `InitiallyUnowned` ancestry rather than + /// from this transfer annotation alone. + public var returnValue: ReturnValue + /// Whether the constructor takes a trailing `GError**` and can fail. + public var throwsGError: Bool + /// GIR metadata governing whether this constructor should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new constructor definition. /// - Parameters: /// - name: The constructor name. /// - cIdentifier: The corresponding C function identifier. /// - parameters: The constructor parameters. Defaults to empty. - /// - returnType: The return type. Defaults to `.void`. + /// - returnValue: The return value. Defaults to a `void`, non-transferring return. + /// - throwsGError: Whether the constructor takes a `GError**`. Defaults to `false`. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cIdentifier: String, parameters: [Parameter] = [], returnType: GIRType = .void, doc: String? = nil) { + public init(name: String, cIdentifier: String, parameters: [Parameter] = [], + returnValue: ReturnValue = ReturnValue(), throwsGError: Bool = false, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { self.name = name; self.cIdentifier = cIdentifier - self.parameters = parameters; self.returnType = returnType; self.doc = doc + self.parameters = parameters; self.returnValue = returnValue + self.throwsGError = throwsGError; self.symbolInfo = symbolInfo; self.doc = doc } } @@ -387,18 +537,27 @@ public struct Method { public var doc: String? /// The parameters of the method, typically excluding the instance parameter. public var parameters: [Parameter] - /// The return type of the method. - public var returnType: GIRType + /// The return value of the method, with its ownership and nullability. + public var returnValue: ReturnValue + /// Whether the method takes a trailing `GError**` and can fail. + public var throwsGError: Bool + /// GIR metadata governing whether this method should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new method definition. /// - Parameters: /// - name: The method name. /// - cIdentifier: The corresponding C function identifier. /// - parameters: The method parameters. Defaults to empty. - /// - returnType: The return type. Defaults to `.void`. + /// - returnValue: The return value. Defaults to a `void`, non-transferring return. + /// - throwsGError: Whether the method takes a `GError**`. Defaults to `false`. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cIdentifier: String, parameters: [Parameter] = [], returnType: GIRType = .void, doc: String? = nil) { + public init(name: String, cIdentifier: String, parameters: [Parameter] = [], + returnValue: ReturnValue = ReturnValue(), throwsGError: Bool = false, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { self.name = name; self.cIdentifier = cIdentifier - self.parameters = parameters; self.returnType = returnType; self.doc = doc + self.parameters = parameters; self.returnValue = returnValue + self.throwsGError = throwsGError; self.symbolInfo = symbolInfo; self.doc = doc } } @@ -420,6 +579,22 @@ public struct Property { public var isWritable: Bool /// Whether the property can only be set during object construction. public var isConstructOnly: Bool + /// Whether the property may hold `NULL`. + public var isNullable: Bool + /// How ownership transfers when reading or writing the property. + public var transferOwnership: TransferOwnership + /// The name of the method implementing this property's getter, if GIR + /// states one via the `getter` attribute (e.g. `"get_label"`). + /// + /// When present, the accessor delegates to that already-planned method + /// instead of going through the GValue machinery — simpler and correct by + /// construction. + public var getter: String? + /// The name of the method implementing this property's setter, if GIR + /// states one via the `setter` attribute (e.g. `"set_label"`). + public var setter: String? + /// GIR metadata governing whether this property should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new property definition. /// - Parameters: /// - name: The property name. @@ -427,10 +602,23 @@ public struct Property { /// - isReadable: Whether the property is readable. Defaults to `true`. /// - isWritable: Whether the property is writable. Defaults to `false`. /// - isConstructOnly: Whether the property is construct-only. Defaults to `false`. + /// - isNullable: Whether the property may be `NULL`. Defaults to `false`. + /// - transferOwnership: Ownership transfer semantics. Defaults to `.none`. + /// - getter: The name of the getter method, if stated. + /// - setter: The name of the setter method, if stated. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, type: GIRType, isReadable: Bool = true, isWritable: Bool = false, isConstructOnly: Bool = false, doc: String? = nil) { + public init(name: String, type: GIRType, isReadable: Bool = true, isWritable: Bool = false, + isConstructOnly: Bool = false, isNullable: Bool = false, + transferOwnership: TransferOwnership = .none, + getter: String? = nil, setter: String? = nil, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { self.name = name; self.type = type - self.isReadable = isReadable; self.isWritable = isWritable; self.isConstructOnly = isConstructOnly; self.doc = doc + self.isReadable = isReadable; self.isWritable = isWritable + self.isConstructOnly = isConstructOnly; self.isNullable = isNullable + self.transferOwnership = transferOwnership + self.getter = getter; self.setter = setter + self.symbolInfo = symbolInfo; self.doc = doc } } @@ -444,21 +632,26 @@ public struct Signal { public let name: String /// The parameters emitted with the signal. public var parameters: [Parameter] - /// The return type of the signal handler. - public var returnType: GIRType + /// The return value of the signal handler. + public var returnValue: ReturnValue /// Whether the signal supports detail strings (e.g. `"notify::label"`). public var isDetailed: Bool + /// GIR metadata governing whether this signal should be bound at all. + public var symbolInfo: SymbolInfo /// Documentation comment from the GIR XML `` element. public var doc: String? /// Creates a new signal definition. /// - Parameters: /// - name: The signal name. /// - parameters: The signal parameters. Defaults to empty. - /// - returnType: The handler return type. Defaults to `.void`. + /// - returnValue: The handler return value. Defaults to a `void`, non-transferring return. /// - isDetailed: Whether the signal supports detail strings. Defaults to `false`. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, parameters: [Parameter] = [], returnType: GIRType = .void, isDetailed: Bool = false, doc: String? = nil) { - self.name = name; self.parameters = parameters; self.returnType = returnType; self.isDetailed = isDetailed; self.doc = doc + public init(name: String, parameters: [Parameter] = [], returnValue: ReturnValue = ReturnValue(), + isDetailed: Bool = false, symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { + self.name = name; self.parameters = parameters; self.returnValue = returnValue + self.isDetailed = isDetailed; self.symbolInfo = symbolInfo; self.doc = doc } } @@ -476,18 +669,27 @@ public struct GlobalFunction { public var doc: String? /// The parameters of the function. public var parameters: [Parameter] - /// The return type of the function. - public var returnType: GIRType + /// The return value of the function, with its ownership and nullability. + public var returnValue: ReturnValue + /// Whether the function takes a trailing `GError**` and can fail. + public var throwsGError: Bool + /// GIR metadata governing whether this function should be bound at all. + public var symbolInfo: SymbolInfo /// Creates a new global function definition. /// - Parameters: /// - name: The function name. /// - cIdentifier: The corresponding C function identifier. /// - parameters: The function parameters. Defaults to empty. - /// - returnType: The return type. Defaults to `.void`. + /// - returnValue: The return value. Defaults to a `void`, non-transferring return. + /// - throwsGError: Whether the function takes a `GError**`. Defaults to `false`. + /// - symbolInfo: GIR binding metadata. Defaults to introspectable and bindable. /// - doc: Documentation comment from the GIR XML. - public init(name: String, cIdentifier: String, parameters: [Parameter] = [], returnType: GIRType = .void, doc: String? = nil) { + public init(name: String, cIdentifier: String, parameters: [Parameter] = [], + returnValue: ReturnValue = ReturnValue(), throwsGError: Bool = false, + symbolInfo: SymbolInfo = SymbolInfo(), doc: String? = nil) { self.name = name; self.cIdentifier = cIdentifier - self.parameters = parameters; self.returnType = returnType; self.doc = doc + self.parameters = parameters; self.returnValue = returnValue + self.throwsGError = throwsGError; self.symbolInfo = symbolInfo; self.doc = doc } } @@ -566,6 +768,25 @@ public struct Parameter { public var transferOwnership: TransferOwnership /// Whether this is the implicit instance parameter (self) of a method. public var isInstanceParameter: Bool + /// The direction of data flow for this parameter. + public var direction: ParameterDirection + /// Whether the caller allocates the storage an out parameter writes into. + /// + /// Only meaningful when ``direction`` is `.out`. Caller-allocated out + /// parameters take a pointer to existing storage; callee-allocated ones + /// take a pointer to a pointer the callee fills in. + public var callerAllocates: Bool + /// The lifetime of this parameter's callback, when it is a callback. + public var scope: CallbackScope? + /// Index of the parameter carrying this callback's user data, if any. + /// + /// From the GIR `closure` attribute. A callback without a user-data slot + /// cannot carry a Swift closure and forces its callable to be skipped. + public var closureIndex: Int? + /// Index of the parameter carrying this callback's `DestroyNotify`, if any. + /// + /// From the GIR `destroy` attribute. + public var destroyIndex: Int? /// Creates a new parameter definition. /// - Parameters: /// - name: The parameter name. @@ -575,12 +796,24 @@ public struct Parameter { /// - isOptional: Whether the parameter is optional. Defaults to `false`. /// - transferOwnership: How ownership is transferred. Defaults to `.none`. /// - isInstanceParameter: Whether this is the instance parameter. Defaults to `false`. + /// - direction: The direction of data flow. Defaults to `.in`. + /// - callerAllocates: Whether the caller allocates out-parameter storage. + /// Defaults to `false`. + /// - scope: The callback lifetime, when this parameter is a callback. + /// - closureIndex: Index of the user-data parameter, if any. + /// - destroyIndex: Index of the `DestroyNotify` parameter, if any. /// - doc: Documentation comment from the GIR XML. public init(name: String, type: GIRType, cType: String = "", isNullable: Bool = false, isOptional: Bool = false, - transferOwnership: TransferOwnership = .none, isInstanceParameter: Bool = false, doc: String? = nil) { + transferOwnership: TransferOwnership = .none, isInstanceParameter: Bool = false, + direction: ParameterDirection = .in, callerAllocates: Bool = false, + scope: CallbackScope? = nil, closureIndex: Int? = nil, destroyIndex: Int? = nil, + doc: String? = nil) { self.name = name; self.type = type; self.cType = cType; self.isNullable = isNullable self.isOptional = isOptional; self.transferOwnership = transferOwnership - self.isInstanceParameter = isInstanceParameter; self.doc = doc + self.isInstanceParameter = isInstanceParameter + self.direction = direction; self.callerAllocates = callerAllocates + self.scope = scope; self.closureIndex = closureIndex; self.destroyIndex = destroyIndex + self.doc = doc } } @@ -590,7 +823,7 @@ public struct Parameter { /// management semantics: whether the caller must free the returned value /// (`.full`), whether only the container is owned (`.container`), or whether /// no ownership transfer occurs (`.none`). -public enum TransferOwnership: String { +public enum TransferOwnership: String, Sendable { /// No transfer; the caller does not own the value and must not free it. case none /// Full transfer; the caller owns the value and is responsible for freeing it. @@ -599,13 +832,169 @@ public enum TransferOwnership: String { case container } +/// The direction of data flow for a parameter. +/// +/// Maps to the `direction` attribute in GIR XML. Out and in-out parameters are +/// passed as pointers in C and require dedicated marshalling in Swift. +public enum ParameterDirection: String, Sendable { + /// The value flows from caller to callee (the default). + case `in` + /// The value flows from callee to caller via a pointer. + case out + /// The value flows in both directions via a pointer. + case inout_ = "inout" +} + +/// The lifetime of a callback parameter relative to the call it is passed to. +/// +/// Maps to the `scope` attribute in GIR XML. Determines how the generator must +/// box and release the Swift closure backing a C callback. +public enum CallbackScope: String, Sendable { + /// The callback is only invoked during the call; no box retention needed. + case call + /// The callback is invoked exactly once, later; the box is consumed then. + case async + /// The callback lives until its `DestroyNotify` fires. + case notified + /// The callback lives forever; the box is never released. + case forever +} + +/// Metadata describing how a GIR `` determines its length. +/// +/// Derived from the `length`, `fixed-size`, and `zero-terminated` attributes on +/// the GIR `` element. Without one of these, a C array cannot be safely +/// bridged and the enclosing callable must be skipped. +public struct ArrayInfo: Equatable, Sendable { + /// Index of the parameter carrying the array length, if length-delimited. + /// + /// The index refers to the enclosing callable's GIR parameter list, + /// excluding the instance parameter — matching GIR's own numbering. + public var lengthParameterIndex: Int? + /// The compile-time element count, if the array is fixed-size. + public var fixedSize: Int? + /// Whether the array is terminated by a `NULL`/zero element. + public var isZeroTerminated: Bool + /// The C type spelling of the array itself (e.g. `"char**"`), when present. + public var cType: String + + /// Creates array length metadata. + /// + /// - Parameters: + /// - lengthParameterIndex: Index of the length parameter, if any. + /// - fixedSize: The fixed element count, if any. + /// - isZeroTerminated: Whether a zero/NULL terminator delimits the array. + /// Defaults to `false`. + /// - cType: The C type spelling of the array. Defaults to `""`. + public init(lengthParameterIndex: Int? = nil, fixedSize: Int? = nil, + isZeroTerminated: Bool = false, cType: String = "") { + self.lengthParameterIndex = lengthParameterIndex + self.fixedSize = fixedSize + self.isZeroTerminated = isZeroTerminated + self.cType = cType + } + + /// Whether the array's length can be determined at all. + /// + /// Arrays failing this check cannot be bridged and cause their enclosing + /// callable to be skipped with ``SkipReason/arrayWithoutLength``. + public var hasKnownLength: Bool { + lengthParameterIndex != nil || fixedSize != nil || isZeroTerminated + } +} + +/// The return value of a callable, with its ownership and nullability. +/// +/// Corresponds to the `` element in GIR XML. Bundling the type +/// with its `transfer-ownership` and `nullable` attributes keeps the semantics +/// the binding planner needs attached to the type, rather than discarded. +public struct ReturnValue: Equatable, Sendable { + /// The GIR type of the returned value. + public var type: GIRType + /// Whether the callee may return `NULL`. + public var isNullable: Bool + /// How ownership of the returned value transfers to the caller. + public var transferOwnership: TransferOwnership + /// Documentation comment from the GIR XML `` element. + public var doc: String? + + /// Creates a return value description. + /// + /// - Parameters: + /// - type: The GIR type returned. Defaults to `.void`. + /// - isNullable: Whether `NULL` may be returned. Defaults to `false`. + /// - transferOwnership: Ownership transfer to the caller. Defaults to `.none`. + /// - doc: Documentation comment from the GIR XML. + public init(type: GIRType = .void, isNullable: Bool = false, + transferOwnership: TransferOwnership = .none, doc: String? = nil) { + self.type = type + self.isNullable = isNullable + self.transferOwnership = transferOwnership + self.doc = doc + } +} + +/// GIR metadata shared by every bindable symbol. +/// +/// Captures the attributes that determine whether a symbol should be bound at +/// all, independent of its type signature. The binding planner consults these +/// before attempting to plan a symbol. +public struct SymbolInfo: Equatable, Sendable { + /// Whether the symbol is introspectable (`introspectable="0"` means no). + /// + /// Non-introspectable symbols are outside the GIR ABI contract and are + /// never bound. + public var isIntrospectable: Bool + /// Whether the symbol is marked deprecated. + public var isDeprecated: Bool + /// The version in which the symbol was deprecated, if stated. + public var deprecatedVersion: String? + /// The name of the symbol that shadows this one, if any. + /// + /// GIR marks the lower-fidelity of two overlapping symbols with + /// `shadowed-by`; only the shadowing symbol should be bound. + public var shadowedBy: String? + /// The name this symbol shadows, if any. + public var shadows: String? + /// The symbol this one was renamed to (`moved-to`), if any. + public var movedTo: String? + + /// Creates symbol metadata. + /// + /// - Parameters: + /// - isIntrospectable: Whether the symbol is introspectable. Defaults to `true`. + /// - isDeprecated: Whether the symbol is deprecated. Defaults to `false`. + /// - deprecatedVersion: The deprecation version, if stated. + /// - shadowedBy: The name of the shadowing symbol, if any. + /// - shadows: The name of the shadowed symbol, if any. + /// - movedTo: The rename target, if any. + public init(isIntrospectable: Bool = true, isDeprecated: Bool = false, + deprecatedVersion: String? = nil, shadowedBy: String? = nil, + shadows: String? = nil, movedTo: String? = nil) { + self.isIntrospectable = isIntrospectable + self.isDeprecated = isDeprecated + self.deprecatedVersion = deprecatedVersion + self.shadowedBy = shadowedBy + self.shadows = shadows + self.movedTo = movedTo + } + + /// Whether the symbol is a candidate for binding at all. + /// + /// False for non-introspectable symbols, symbols shadowed by a + /// higher-fidelity variant, and symbols that have moved elsewhere. + public var isBindable: Bool { + isIntrospectable && shadowedBy == nil && movedTo == nil + } +} + /// A GIR type reference, covering primitives, named type references, arrays, and optionals. /// /// Corresponds to the `` element in GIR XML. This recursive enum models /// the full GIR type system: scalar primitives, named type references pointing /// to other GIR types, arrays (both GArray and C-style fixed arrays), and /// nullable/optional wrappers. -public indirect enum GIRType: Equatable { +public indirect enum GIRType: Equatable, Sendable { /// No return value (void). case void /// A boolean value, mapped from `gboolean`. @@ -626,6 +1015,22 @@ public indirect enum GIRType: Equatable { case uint32 /// An unsigned 64-bit integer, mapped from `guint64`. case uint64 + /// A platform-width signed integer, mapped from `glong`. + case long + /// A platform-width unsigned integer, mapped from `gulong`. + case ulong + /// A pointer-width unsigned size, mapped from `gsize`. + case size + /// A pointer-width signed size, mapped from `gssize`. + case ssize + /// A single C character, mapped from `gchar`. + case char + /// A single unsigned C character, mapped from `guchar`. + case uchar + /// A UCS-4 code point, mapped from `gunichar`. + case unichar + /// A GObject type identifier, mapped from `GType`. + case gtype /// A single-precision floating-point value, mapped from `gfloat`. case float /// A double-precision floating-point value, mapped from `gdouble`. @@ -636,15 +1041,22 @@ public indirect enum GIRType: Equatable { case filename /// An opaque pointer, mapped from `gpointer`. case pointer + /// A variadic argument list, mapped from `va_list`. Never bindable. + case vaList /// A reference to a named type, possibly from another namespace. /// - Parameters: /// - String: The type name, e.g. `"Widget"`. /// - namespace: The namespace qualifier, or `nil` for the current namespace. case typeRef(String, namespace: String?) - /// A dynamically-sized GArray of the given element type. - case array(GIRType) - /// A C-style fixed-size array of the given element type. - case cArray(GIRType) + /// A GLib container type (`GList`, `GSList`, `GHashTable`, …) with its + /// element types, in GIR declaration order. + /// + /// Kept distinct from ``typeRef(_:namespace:)`` so the planner can reason + /// about element bridging rather than treating a container as an opaque + /// named type. + case container(ContainerKind, elements: [GIRType]) + /// A C array of the given element type, with its length metadata. + case cArray(GIRType, ArrayInfo) /// An optional (nullable) value of the given type. case `optional`(GIRType) @@ -654,4 +1066,51 @@ public indirect enum GIRType: Equatable { public static func typeRef(_ name: String) -> GIRType { .typeRef(name, namespace: nil) } + + /// Creates a C array with no length metadata. + /// + /// Such arrays cannot be bridged; the planner skips callables using them + /// with ``SkipReason/arrayWithoutLength``. + /// + /// - Parameter element: The array's element type. + /// - Returns: A `cArray` with empty ``ArrayInfo``. + public static func cArray(_ element: GIRType) -> GIRType { + .cArray(element, ArrayInfo()) + } +} + +/// The kind of a GLib container type. +/// +/// Containers carry their elements' types separately from their own identity, +/// which is what lets the planner decide whether the elements can be bridged. +public enum ContainerKind: String, Equatable, Sendable { + /// A doubly-linked `GList`. + case list + /// A singly-linked `GSList`. + case slist + /// A `GHashTable` mapping keys to values. + case hashTable + /// A `GArray` of elements. + case array + /// A `GPtrArray` of pointers. + case ptrArray + /// A `GByteArray` of bytes. + case byteArray +} + +extension GIRType { + /// True for primitive types that don't need C enum/string/pointer bridging. + /// These can be used in function parameters without the complex C type + /// resolution that Phase C1 will provide. + var isSimplePrimitive: Bool { + switch self { + case .void, .boolean, .int8, .int16, .int32, .int64, + .uint8, .uint16, .uint32, .uint64, + .long, .ulong, .size, .ssize, + .float, .double: + return true + default: + return false + } + } } diff --git a/Sources/SwiftGtkGenCore/PlanRenderer.swift b/Sources/SwiftGtkGenCore/PlanRenderer.swift new file mode 100644 index 0000000..05d7470 --- /dev/null +++ b/Sources/SwiftGtkGenCore/PlanRenderer.swift @@ -0,0 +1,389 @@ +// PlanRenderer.swift +// Dumb string emitter: takes a finished `ModulePlan` and renders it to +// Swift source text. The renderer never sees `GIRType`, `IRModel`, or the +// registry — only the plan types from `BindingPlan.swift`. +// +// Rule 2 of the three rules: the renderer must never see `GIRType`. + +import Foundation + +// MARK: - Module Renderer + +/// Renders a module plan to a dictionary of filename → Swift source content. +/// +/// Each type gets its own file (e.g. `"Align.swift"`). The renderer does +/// NOT produce scaffolding files (Package.swift, module maps, umbrella +/// headers) — those come from `CodeGen+Scaffolding.swift` as before. +/// +/// - Parameter plan: The completed module plan. +/// - Returns: A dictionary of relative file path → source content. +public func renderModule(_ plan: ModulePlan) -> [String: String] { + var files: [String: String] = [:] + + let header = """ + // Generated by SwiftGtkGen. DO NOT EDIT. + + import C\(plan.module) + import Foundation + + """ + + for typePlan in plan.types { + let (baseName, body) = renderTypePlan(typePlan) + let content = header + body + "\n" + files["\(baseName).swift"] = content + } + + return files +} + +// MARK: - Type-level rendering + +/// Renders a single `TypePlan` into a base filename and Swift source body. +/// +/// - Parameter typePlan: The type to render. +/// - Returns: A tuple of base filename (without extension) and Swift source text. +private func renderTypePlan(_ typePlan: TypePlan) -> (String, String) { + switch typePlan { + case .enumeration(let p): return (p.name, renderEnum(p)) + case .bitfield(let p): return (p.name, renderBitfield(p)) + case .constant(let p): return (p.name, renderConstant(p)) + case .alias(let p): return (p.name, renderAlias(p)) + case .class(let p): return (p.name, renderClass(p)) + case .interface(let p): return (p.name, renderInterface(p)) + case .record(let p): return (p.name, renderRecord(p)) + case .callable(let p): return (p.name, renderCallable(p)) + } +} + +// ── Enumeration ── + +private func renderEnum(_ plan: EnumPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + lines.append("public enum \(plan.name): Int, Sendable {") + + for c in plan.cases { + lines.append(" case \(c.name) = \(c.rawValue)") + } + + if !plan.aliases.isEmpty { + lines.append("") + for alias in plan.aliases { + lines.append(" public static var \(alias.name): \(plan.name) { .\(alias.targetCaseName) }") + } + } + + lines.append("}") + + return lines.joined(separator: "\n") + "\n" +} + +// ── Bitfield ── + +private func renderBitfield(_ plan: BitfieldPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + lines.append("public struct \(plan.name): OptionSet, Sendable {") + lines.append(" public let rawValue: UInt32") + lines.append(" public init(rawValue: UInt32) { self.rawValue = rawValue }") + + for member in plan.members { + if member.rawValue == "0" { + lines.append(" public static let \(member.name): \(plan.name) = []") + } else { + let value = swiftBitfieldLiteral(member.rawValue) + lines.append(" public static let \(member.name) = \(plan.name)(rawValue: \(value))") + } + } + + lines.append("}") + return lines.joined(separator: "\n") + "\n" +} + +// ── Constant ── + +private func renderConstant(_ plan: ConstantPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + // String constants need quotes; numeric/literal values pass through + let valueExpr: String + if plan.swiftType == "String" { + valueExpr = "\"\(plan.value)\"" + } else { + valueExpr = plan.value + } + lines.append("public nonisolated let \(plan.name): \(plan.swiftType) = \(valueExpr)") + return lines.joined(separator: "\n") + "\n" +} + +// ── Alias ── + +private func renderAlias(_ plan: AliasPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + lines.append("public typealias \(plan.name) = \(plan.swiftType)") + return lines.joined(separator: "\n") + "\n" +} + +// ── Record (boxed) ── + +private func renderRecord(_ plan: RecordPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + + lines.append("public final class \(plan.name) {") + lines.append(" public let pointer: UnsafeMutableRawPointer") + lines.append("") + lines.append(" public init(takingOwnership pointer: UnsafeMutableRawPointer) {") + lines.append(" self.pointer = pointer") + lines.append(" }") + lines.append("}") + return lines.joined(separator: "\n") + "\n" +} + +// ── Interface ── + +private func renderInterface(_ plan: InterfacePlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + + var protocolInherits = "" + if !plan.prereqs.isEmpty { + protocolInherits = ": " + plan.prereqs.joined(separator: ", ") + } + + lines.append("public protocol \(plan.name)\(protocolInherits) {") + lines.append(" var pointer: UnsafeMutableRawPointer { get }") + lines.append("}") + return lines.joined(separator: "\n") + "\n" +} + +// ── Class ── + +private func renderClass(_ plan: ClassPlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + + let access = plan.isOpen ? "open" : "public" + let parentDecl = plan.parent.map { ": \($0)" } ?? "" + + lines.append("\(access) class \(plan.name)\(parentDecl) {") + + let isRoot = plan.parent == nil + + // Storage — only for root classes + if isRoot { + lines.append(" public let pointer: UnsafeMutableRawPointer") + lines.append("") + } + + // Root classes ALWAYS get inits (even abstract — subclasses need them for chaining). + // Non-root abstract classes skip inits (parent handles them). + let needsInits = isRoot || !plan.isAbstract + + if needsInits { + let initModifier = isRoot ? "" : "public override " + + // takingOwnership init + if isRoot { + let body = plan.descendsFromInitiallyUnowned + ? ["g_object_ref_sink(pointer)", "self.pointer = pointer"] + : ["self.pointer = pointer"] + lines.append(" public required init(takingOwnership pointer: UnsafeMutableRawPointer) {") + for line in body { lines.append(" \(line)") } + lines.append(" }") + } else { + let body = plan.descendsFromInitiallyUnowned + ? ["g_object_ref_sink(pointer)", "super.init(takingOwnership: pointer)"] + : ["super.init(takingOwnership: pointer)"] + lines.append(" \(initModifier)required init(takingOwnership pointer: UnsafeMutableRawPointer) {") + for line in body { lines.append(" \(line)") } + lines.append(" }") + } + lines.append("") + + // Retaining init + if isRoot { + lines.append(" public init(retaining pointer: UnsafeMutableRawPointer) {") + lines.append(" self.pointer = pointer") + lines.append(" g_object_ref(pointer)") + lines.append(" }") + } else { + lines.append(" public override init(retaining pointer: UnsafeMutableRawPointer) {") + lines.append(" g_object_ref(pointer)") + lines.append(" super.init(takingOwnership: pointer)") + lines.append(" }") + } + lines.append("") + } + + // deinit — skipped until Phase C (ownership semantics). + // A naive g_object_unref here would double-free if the C layer + // already released its reference. Proper ref-counting requires + // tracking transfer ownership from every C call path. + + lines.append("}") + return lines.joined(separator: "\n") + "\n" +} + +// ── Callable (function) ── + +private func renderCallable(_ plan: CallablePlan) -> String { + var lines: [String] = [] + + if let doc = plan.doc { + lines.append(contentsOf: renderDocComment(doc)) + } + + // Build parameter list for Swift signature + let swiftParams = plan.parameters.filter { !$0.isInstanceParameter }.map { param in + "\(param.swiftName): \(param.mapping.swiftType)" + }.joined(separator: ", ") + + // Return type + let returnDecl = plan.returnMapping.map { " -> \($0.swiftType)" } ?? "" + + // Assign a C-string local to each string parameter; those are bridged + // through `withCString`, so the C argument is the closure's pointer rather + // than the Swift `String`. + var stringParams: [(cName: String, swiftName: String)] = [] + let cArgExprs: [String] = plan.parameters.map { param in + if param.isInstanceParameter { return "self.pointer" } + if param.mapping.marshalIn == .stringToC { + let cName = "cString\(stringParams.count)" + stringParams.append((cName: cName, swiftName: param.swiftName)) + return cName + } + return marshalCallArg(param) + } + + let cCall = "\(plan.cIdentifier)(\(cArgExprs.joined(separator: ", ")))" + + // The statement evaluated in the innermost scope. + let hasReturn = plan.returnMapping != nil + let core = hasReturn ? "return \(marshalReturn(cCall, mapping: plan.returnMapping!))" : cCall + + lines.append("public func \(plan.name)(\(swiftParams))\(returnDecl) {") + + if stringParams.isEmpty { + lines.append(" \(core)") + } else { + // Wrap the call in one `withCString` closure per string parameter. + // With a return value, each level returns its inner closure's result. + var indent = " " + let openerPrefix = hasReturn ? "return " : "" + for sp in stringParams { + lines.append("\(indent)\(openerPrefix)\(sp.swiftName).withCString { \(sp.cName) in") + indent += " " + } + lines.append("\(indent)\(core)") + for _ in stringParams { + indent = String(indent.dropLast(4)) + lines.append("\(indent)}") + } + } + + lines.append("}") + return lines.joined(separator: "\n") + "\n" +} + +/// Generates the argument expression for a callable parameter. +private func marshalCallArg(_ param: ParameterPlan) -> String { + switch param.mapping.marshalIn { + case .direct: + return param.swiftName + case .numericCast: + // Let the compiler infer the C-imported integer type at the call site; + // this bridges width/signedness mismatches (e.g. gsize imported as Int) + // portably without hard-coding the platform's C type. + return "numericCast(\(param.swiftName))" + case .enumRaw: + // Convert our Swift enum to the C enum type as imported by Swift. + // e.g., ConnectFlags → GConnectFlags(rawValue: numericCast(flags.rawValue)) + let cType = param.mapping.cSwiftType + return "\(cType)(rawValue: numericCast(\(param.swiftName).rawValue))" + case .bitfieldRaw: + let cType = param.mapping.cSwiftType + return "\(cType)(rawValue: numericCast(\(param.swiftName).rawValue))" + case .boolToGboolean: + return "\(param.swiftName) ? 1 : 0" + case .stringToC: + return param.swiftName + case .objectPointer: + return "\(param.swiftName).pointer" + case .boxedPointer: + return "\(param.swiftName).pointer" + case .unsupported(let reason): + return "/* unsupported: \(reason) */" + } +} + +/// Generates the return expression for a callable. +private func marshalReturn(_ cCall: String, mapping: Mapping) -> String { + switch mapping.marshalOut { + case .direct: + return cCall + case .numericCast: + // Target type is the declared Swift return type; the compiler infers + // it, bridging any C width/signedness mismatch portably. + return "numericCast(\(cCall))" + case .gbooleanToBool: + return "\(cCall) != 0" + case .stringCopy(let free): + if free { + return "String(cString: \(cCall)) /* TODO: g_free */" + } + return "String(cString: \(cCall))" + case .objectWrap, .objectRetain, .boxedWrap: + return cCall // TODO: ownership wrapping + case .enumFromRaw(let swiftType): + // C function returns a C enum type; extract its rawValue to init our Swift enum. + // e.g., ConnectFlags(rawValue: numericCast((g_something(...)).rawValue)) + return "\(swiftType)(rawValue: numericCast((\(cCall)).rawValue))!" + case .bitfieldFromRaw(let swiftType): + // C function returns a C flags value; rebuild our OptionSet from its raw bits. + return "\(swiftType)(rawValue: numericCast((\(cCall)).rawValue))" + case .unsupported: + return cCall + " /* unsupported marshalOut */" + } +} + +// MARK: - Doc comment helper + +private func renderDocComment(_ text: String) -> [String] { + text.components(separatedBy: "\n").map { "/// \($0)" } +} + +/// Converts a raw GIR bitfield value string to a Swift `UInt32` literal. +/// +/// Negative values (masks with the high bit set) are emitted as +/// `UInt32(bitPattern: Int32(…))` so they don't overflow the unsigned type. +/// Positive values are passed through verbatim. +private func swiftBitfieldLiteral(_ rawValue: String) -> String { + if rawValue.hasPrefix("-") { + return "UInt32(bitPattern: Int32(\(rawValue)))" + } + return rawValue +} diff --git a/Sources/SwiftGtkGenCore/Planner.swift b/Sources/SwiftGtkGenCore/Planner.swift new file mode 100644 index 0000000..652c30b --- /dev/null +++ b/Sources/SwiftGtkGenCore/Planner.swift @@ -0,0 +1,624 @@ +// Planner.swift +// The binding planner: walks a parsed GIR namespace, resolves every type +// through the registry and TypeMapper, and produces either a complete +// `TypePlan` or a `SkipEntry` with a machine-readable reason. +// +// This is where Rule 3 of the rearchitecture lives: if any part of a symbol +// cannot be planned, the WHOLE symbol is skipped with a reason. There is no +// code path that emits a partially-understood binding. + +import Foundation + +// MARK: - Module Planner + +/// Plans every type in every namespace of a multi-package analysis, producing +/// a `ModulePlan` per generated Swift module. +/// +/// - Parameters: +/// - analysis: The resolved multi-package analysis with parsed repositories. +/// - registry: The global type registry built from those repositories. +/// - Returns: A dictionary mapping Swift module name to its `ModulePlan`. +public func planModules( + analysis: MultiPackageAnalysis, + registry: TypeRegistry +) -> [String: ModulePlan] { + var modulePlans: [String: ModulePlan] = [:] + + for (moduleName, repo) in analysis.repositories { + let ns = repo.namespaces.first { $0.name == moduleName } ?? repo.namespaces.first + guard let namespace = ns else { continue } + + let context = MapContext( + registry: registry, + currentModule: moduleName, + currentNamespace: namespace.name + ) + + let plan = planNamespace(namespace, context: context) + modulePlans[moduleName] = plan + } + + return modulePlans +} + +// MARK: - Namespace-level planning + +/// Plans every type in a single namespace, delegating to per-category helpers. +private func planNamespace(_ ns: Namespace, context: MapContext) -> ModulePlan { + var types: [TypePlan] = [] + var skips: [SkipEntry] = [] + var boundTypes = 0 + var totalTypes = 0 + var boundCallables = 0 + var totalCallables = 0 + + // ── Enumerations ── + for enumeration in ns.enumerations { + totalTypes += 1; boundTypes += planEnum(into: &types, skips: &skips, enumeration: enumeration, context: context) + } + + // ── Bitfields ── + for bitfield in ns.bitfields { + totalTypes += 1; boundTypes += planBit(into: &types, skips: &skips, bitfield: bitfield, context: context) + } + + // ── Constants ── + for constant in ns.constants { + totalTypes += 1; boundTypes += planConst(into: &types, skips: &skips, constant: constant, context: context) + } + + // ── Aliases ── + for alias in ns.aliases { + totalTypes += 1; boundTypes += planAliasType(into: &types, skips: &skips, alias: alias, context: context) + } + + // ── Classes, Interfaces, Records, Callbacks — skip with reasons (Phase B6+) ── + for klass in ns.classes { + totalTypes += 1; boundTypes += skipClass(into: &skips, into: &types, klass: klass, namespace: ns.name, context: context) + } + for iface in ns.interfaces { + totalTypes += 1; boundTypes += skipInterface(into: &skips, into: &types, iface: iface, namespace: ns.name, context: context) + } + for record in ns.records { + totalTypes += 1; boundTypes += skipRecord(into: &skips, into: &types, record: record, namespace: ns.name, context: context) + } + for callback in ns.callbacks { + totalTypes += 1; boundTypes += skipCallback(into: &skips, callback: callback, namespace: ns.name) + } + for fn in ns.functions { + totalCallables += 1 + boundCallables += planOrSkipFunction(into: &skips, into: &types, fn: fn, namespace: ns.name, context: context) + } + + let coverage = CoverageStats( + boundCallables: boundCallables, totalCallables: totalCallables, + boundTypes: boundTypes, totalTypes: totalTypes + ) + + return ModulePlan(module: context.currentModule, types: types, skips: skips, coverage: coverage) +} + +// MARK: - Per-category planning (returns 1 for bound, 0 for skipped) + +private func planEnum( + into types: inout [TypePlan], skips: inout [SkipEntry], + enumeration: Enumeration, context: MapContext +) -> Int { + let fullName = "\(context.currentNamespace).\(enumeration.name)" + if let skip = checkBindable(enumeration.symbolInfo, fullName: fullName, cIdentifier: enumeration.cType) { + skips.append(skip); return 0 + } + types.append(.enumeration(planEnumeration(enumeration, context: context))) + return 1 +} + +private func planBit( + into types: inout [TypePlan], skips: inout [SkipEntry], + bitfield: Bitfield, context: MapContext +) -> Int { + let fullName = "\(context.currentNamespace).\(bitfield.name)" + if let skip = checkBindable(bitfield.symbolInfo, fullName: fullName, cIdentifier: bitfield.cType) { + skips.append(skip); return 0 + } + types.append(.bitfield(planBitfield(bitfield, context: context))) + return 1 +} + +private func planConst( + into types: inout [TypePlan], skips: inout [SkipEntry], + constant: Constant, context: MapContext +) -> Int { + let fullName = "\(context.currentNamespace).\(constant.name)" + if let plan = planConstant(constant, context: context) { + types.append(.constant(plan)); return 1 + } + skips.append(SkipEntry(symbol: fullName, cIdentifier: constant.name, + reason: .configIgnored, detail: "constant type not mappable")) + return 0 +} + +private func planAliasType( + into types: inout [TypePlan], skips: inout [SkipEntry], + alias: Alias, context: MapContext +) -> Int { + let planResult = planAlias(alias, context: context) + switch planResult { + case .success(let plan): + types.append(.alias(plan)); return 1 + case .skip(let entry): + skips.append(entry); return 0 + } +} + +// MARK: - Skip helpers for not-yet-planned categories + +private func checkBindable(_ info: SymbolInfo, fullName: String, cIdentifier: String) -> SkipEntry? { + if !info.isBindable { + let reason: SkipReason = info.shadowedBy != nil ? .shadowedSymbol + : !info.isIntrospectable ? .notIntrospectable + : .deprecatedRemoved + return SkipEntry(symbol: fullName, cIdentifier: cIdentifier, reason: reason, detail: reason.rawValue) + } + return nil +} + +private func skipClass(into skips: inout [SkipEntry], into types: inout [TypePlan], klass: Class, namespace: String, context: MapContext) -> Int { + let fullName = "\(namespace).\(klass.name)" + if !klass.symbolInfo.isBindable { + skips.append(SkipEntry(symbol: fullName, cIdentifier: klass.cType, + reason: .notIntrospectable, detail: "non-introspectable class")) + return 0 + } + let plan = planClass(klass, context: context) + types.append(.class(plan)) + return 1 +} + +private func skipInterface(into skips: inout [SkipEntry], into types: inout [TypePlan], iface: Interface, namespace: String, context: MapContext) -> Int { + let fullName = "\(namespace).\(iface.name)" + if !iface.symbolInfo.isBindable { + skips.append(SkipEntry(symbol: fullName, cIdentifier: iface.cType, + reason: .notIntrospectable, detail: "non-introspectable interface")) + return 0 + } + types.append(.interface(planInterface(iface, context: context))) + return 1 +} + +private func skipRecord(into skips: inout [SkipEntry], into types: inout [TypePlan], record: Record, namespace: String, context: MapContext) -> Int { + let fullName = "\(namespace).\(record.name)" + if let forType = record.isGTypeStructFor { + skips.append(SkipEntry(symbol: fullName, cIdentifier: record.cType, + reason: .gtypeStruct, detail: "GObject class struct for '\(forType)'")) + return 0 + } + if record.isBoxed { + if reservedSwiftTypes.contains(record.name) { + skips.append(SkipEntry(symbol: fullName, cIdentifier: record.cType, + reason: .unknownType, + detail: "record name '\(record.name)' shadows Swift stdlib type")) + return 0 + } + types.append(.record(planRecord(record, context: context))) + return 1 + } + skips.append(SkipEntry(symbol: fullName, cIdentifier: record.cType, + reason: .plainRecord, detail: "no GType registration")) + return 0 +} + +private func skipCallback(into skips: inout [SkipEntry], callback: Callback, namespace: String) -> Int { + let fullName = "\(namespace).\(callback.name)" + skips.append(SkipEntry(symbol: fullName, cIdentifier: callback.cType, + reason: .callbackWithoutUserData, detail: "callback planned for Phase D2")) + return 0 +} + +/// Plans a namespace-level function, appending a `.callable` type plan on +/// success or a `SkipEntry` on failure. Returns 1 when bound, 0 when skipped. +private func planOrSkipFunction(into skips: inout [SkipEntry], into types: inout [TypePlan], fn: GlobalFunction, namespace: String, context: MapContext) -> Int { + let fullName = "\(namespace).\(fn.name)" + + // Symbols the system library does not export (macros, inline functions, + // or GType getters absent from the shared object) cannot be called. + if knownMissingCFunctions.contains(fn.cIdentifier) { + skips.append(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: .unknownType, detail: "C symbol '\(fn.cIdentifier)' is not exported by the system library")) + return 0 + } + + switch planFunction(fn, context: context) { + case .success(let plan): + types.append(.callable(plan)) + return 1 + case .skip(let entry): + skips.append(entry) + return 0 + } +} + +/// Known C symbols that aren't exported by the system library +/// (macros, inline functions, or GType getters for types not in the .so). +private let knownMissingCFunctions: Set = [ + "g_fsync", + "g_strv_get_type", + "g_variant_get_gtype", + "g_get_monotonic_time_ns", // returns uint64_t (UInt64), not guint64 (UInt) + // gstdio.h wrappers: on non-Windows these are `#define g_open open` macros, + // so no real symbol is exported and Swift cannot import them. + "g_access", "g_chdir", "g_chmod", "g_creat", "g_fopen", "g_freopen", + "g_fsync", "g_lstat", "g_mkdir", "g_open", "g_remove", "g_rename", + "g_rmdir", "g_stat", "g_unlink", "g_utime", +] + +/// Swift type names that boxed records must not shadow. +private let reservedSwiftTypes: Set = [ + "String", "Int", "Bool", "Double", "Float", "Array", "Dictionary", + "Set", "Optional", "Data", "Date", "URL", "Error", "Void", "Any", + "Object", "Type", "Protocol", +] + +/// Plans a boxed record as an opaque pointer wrapper. +func planRecord(_ record: Record, context: MapContext) -> RecordPlan { + return RecordPlan( + name: record.name, cType: record.cType, + getTypeFunction: record.getTypeFunction, + copyFunction: record.copyFunction, + freeFunction: record.freeFunction, + doc: record.doc + ) +} + +/// Plans an interface as a Swift protocol stub. +func planInterface(_ iface: Interface, context: MapContext) -> InterfacePlan { + let registry = context.registry + let girName = "\(context.currentNamespace).\(iface.name)" + + // Resolve prerequisite types through registry + let prereqSwiftNames: [String] = iface.prereqs.compactMap { prereq in + let qualified = prereq.contains(".") ? prereq : "\(context.currentNamespace).\(prereq)" + guard let resolved = registry.resolve(girName: qualified) else { return nil } + return registry.swiftTypeName(for: resolved, in: context.currentModule) + } + + return InterfacePlan( + name: iface.name, cType: iface.cType, + prereqs: prereqSwiftNames, + getTypeFunction: iface.getTypeFunction, + doc: iface.doc + ) +} + +/// Plans a class as a GObject wrapper with cross-module inheritance. +func planClass(_ klass: Class, context: MapContext) -> ClassPlan { + let girName = "\(context.currentNamespace).\(klass.name)" + let registry = context.registry + + // Resolve parent + let parentSwiftName: String? + if let parentGIR = klass.parent { + let qualifiedParent = parentGIR.contains(".") ? parentGIR : "\(context.currentNamespace).\(parentGIR)" + if let resolved = registry.resolve(girName: qualifiedParent) { + parentSwiftName = registry.swiftTypeName(for: resolved, in: context.currentModule) + } else { + parentSwiftName = nil // foreign or unknown — treat as root + } + } else { + parentSwiftName = nil + } + + let isOpen = registry.subclassedTypes().contains(girName) + let descendsIU = registry.descendsFromInitiallyUnowned(girName) + + // Resolve implemented interfaces to their Swift names + let interfaceNames: [String] = klass.implements.compactMap { ifaceName in + let qualified = ifaceName.contains(".") ? ifaceName : "\(context.currentNamespace).\(ifaceName)" + guard let resolved = registry.resolve(girName: qualified) else { return nil } + return registry.swiftTypeName(for: resolved, in: context.currentModule) + } + + return ClassPlan( + name: klass.name, cType: klass.cType, + parent: parentSwiftName, + isOpen: isOpen, + isAbstract: klass.isAbstract, + getTypeFunction: klass.getTypeFunction, + descendsFromInitiallyUnowned: descendsIU, + interfaces: interfaceNames, + constructors: [], + methods: [], + functions: [], + doc: klass.doc + ) +} + +/// Plans an enumeration, deduplicating raw values. +/// +/// Members with duplicate raw values become `public static var` aliases +/// pointing to the first case with that value. +func planEnumeration(_ enumeration: Enumeration, context: MapContext) -> EnumPlan { + var cases: [EnumCase] = [] + var aliases: [EnumAlias] = [] + var seenRawValues: [String: String] = [:] // rawValue → first case name + + for member in enumeration.members { + let swiftName = swiftEnumCaseName(member.name) + if let firstCase = seenRawValues[member.value] { + aliases.append(EnumAlias(name: swiftName, targetCaseName: firstCase)) + } else { + cases.append(EnumCase(name: swiftName, rawValue: member.value, cIdentifier: member.cIdentifier)) + seenRawValues[member.value] = swiftName + } + } + + return EnumPlan( + name: enumeration.name, cType: enumeration.cType, + cases: cases, aliases: aliases, + hasGType: enumeration.getTypeFunction != nil, + doc: enumeration.doc + ) +} + +/// Plans a bitfield as an `OptionSet` with verbatim raw values. +func planBitfield(_ bitfield: Bitfield, context: MapContext) -> BitfieldPlan { + let members = bitfield.members.map { member in + EnumCase( + name: swiftEnumCaseName(member.name), + rawValue: member.value, + cIdentifier: member.cIdentifier + ) + } + + return BitfieldPlan( + name: bitfield.name, cType: bitfield.cType, + members: members, + hasGType: bitfield.getTypeFunction != nil, + doc: bitfield.doc + ) +} + +/// Plans a global constant. Returns `nil` when the constant's type cannot +/// be mapped, so the caller records a skip entry. +func planConstant(_ constant: Constant, context: MapContext) -> ConstantPlan? { + let mappingResult = Result { try map(constant.type, nullable: false, transfer: .none, context: context) } + guard case .success(let mapping) = mappingResult else { return nil } + return ConstantPlan(name: constant.name, value: constant.value, swiftType: mapping.swiftType, doc: constant.doc) +} + +/// Outcome of alias planning: success with a plan, or skip with a reason. +enum AliasPlanResult { + case success(AliasPlan) + case skip(SkipEntry) +} + +/// Plans a type alias, resolving the target type through the mapper. +func planAlias(_ alias: Alias, context: MapContext) -> AliasPlanResult { + let fullName = "\(context.currentNamespace).\(alias.name)" + let mappingResult = Result { try map(alias.target, nullable: false, transfer: .none, context: context) } + + switch mappingResult { + case .success(let mapping): + return .success(AliasPlan(name: alias.name, swiftType: mapping.swiftType, doc: alias.doc)) + case .failure(let error as MapError): + return .skip(SkipEntry(symbol: fullName, cIdentifier: alias.cType, + reason: error.reason, detail: error.detail)) + case .failure: + return .skip(SkipEntry(symbol: fullName, cIdentifier: alias.cType, + reason: .unknownType, detail: "alias target type could not be mapped")) + } +} + +// MARK: - Callable planning + +/// Outcome of trying to plan a callable: either a complete plan or a skip entry. +enum CallablePlanResult { + case success(CallablePlan) + case skip(SkipEntry) +} + +/// Plans a namespace-level function, checking every parameter and the return +/// type for mappability. The whole function is skipped if any part fails. +func planFunction(_ fn: GlobalFunction, context: MapContext) -> CallablePlanResult { + let fullName = "\(context.currentNamespace).\(fn.name)" + let swiftName = swiftFunctionName(fn.name) + + // GError throws — deferred to Phase C2 + if fn.throwsGError { + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: .unknownType, detail: "GError throws planned for Phase C2")) + } + + // Check parameters + let paramPlanResult = planParameters(fn.parameters, context: context) + guard case .success(let paramPlans) = paramPlanResult else { + if case .skip(let entry) = paramPlanResult { + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: entry.reason, detail: entry.detail)) + } + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: .unknownType, detail: "parameter planning failed")) + } + + // Map return type + let returnMapping: Mapping? + if fn.returnValue.type != .void { + switch Result(catching: { try map(fn.returnValue.type, nullable: fn.returnValue.isNullable, + transfer: fn.returnValue.transferOwnership, context: context) }) { + case .success(let returnMap): + if !returnMap.isReadyForCallables { + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: .unknownType, + detail: "return type '\(returnMap.swiftType)' is not yet generated (category: \(returnMap.category))")) + } + returnMapping = returnMap + case .failure(let error as MapError): + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: error.reason, detail: error.detail)) + case .failure: + return .skip(SkipEntry(symbol: fullName, cIdentifier: fn.cIdentifier, + reason: .unknownType, detail: "return type mapping failed")) + } + } else { + returnMapping = nil + } + + return .success(CallablePlan( + name: swiftName, cIdentifier: fn.cIdentifier, + parameters: paramPlans, returnMapping: returnMapping, + isStatic: true, isConstructor: false, ownershipInit: nil, doc: fn.doc + )) +} + +/// Plans the parameters of a callable. Returns `.skip` if any parameter +/// has an unsupported direction, or if any type cannot be mapped. +func planParameters( + _ parameters: [Parameter], context: MapContext +) -> ParameterPlanResult { + var plans: [ParameterPlan] = [] + + for (index, param) in parameters.enumerated() { + // Variadic parameter (GIR names it "..." with a child): + // C variadic calls cannot be bridged from Swift. + if param.name == "..." { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .varargs, detail: "variadic ('...') parameter")) + } + + // Direction check + if param.direction == .out { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .outParameter, detail: "'\(param.name)' has direction=out")) + } + if param.direction == .inout_ { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .inoutParameter, detail: "'\(param.name)' has direction=inout")) + } + + // Map the type + let mappingResult = Result { try map(param.type, nullable: param.isNullable, + transfer: param.transferOwnership, context: context) } + switch mappingResult { + case .success(let paramMapping): + if !paramMapping.isReadyForCallables { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .unknownType, + detail: "parameter '\(param.name)' type '\(paramMapping.swiftType)' is not yet generated")) + } + + let isString = paramMapping.marshalIn == .stringToC + // A nullable string needs an optional-aware bridge; deferred. + if isString && paramMapping.swiftType.hasSuffix("?") { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .unknownType, detail: "parameter '\(param.name)' is a nullable string")) + } + // Only a single-level `const gchar*` input string can be bridged + // from an immutable Swift `String` via `withCString`. A mutable + // `gchar*` is a caller-allocated output buffer, and a `gchar**` + // (two pointer levels, e.g. `const char* const*`) is a string + // vector — both are deferred to array/out-parameter handling. + if isString { + let pointerLevels = param.cType.filter { $0 == "*" }.count + if !param.cType.contains("const") || pointerLevels != 1 { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .unknownType, detail: "parameter '\(param.name)' is not a single const input string ('\(param.cType)')")) + } + } + // Non-string pointer parameters (e.g. `gatomicrefcount*`) need + // address-of / wrapper marshalling — deferred to Phase C3. + // Strings are pointers too but are bridged via `withCString`. + if param.cType.hasSuffix("*") && !isString { + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .unknownType, detail: "parameter '\(param.name)' C type '\(param.cType)' is a pointer")) + } + + let swiftName = swiftParameterName(param.name) + plans.append(ParameterPlan( + swiftName: swiftName, cArgIndex: index, + mapping: paramMapping, isInstanceParameter: param.isInstanceParameter + )) + case .failure(let error as MapError): + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: error.reason, detail: "parameter '\(param.name)': \(error.detail)")) + case .failure: + return .skip(SkipEntry(symbol: "", cIdentifier: nil, + reason: .unknownType, detail: "parameter '\(param.name)' type not mappable")) + } + } + + return .success(plans) +} + +enum ParameterPlanResult { + case success([ParameterPlan]) + case skip(SkipEntry) +} + +// MARK: - Naming helpers + +/// Converts a C function name to a Swift function name (camelCase). +/// Example: `"gtk_widget_show"` → `"show"`, `"g_list_length"` → `"length"`. +func swiftFunctionName(_ cName: String) -> String { + // Strip common prefixes and convert snake_case to camelCase + var parts = cName.split(separator: "_").map(String.init) + // Drop leading prefixes like "g_", "gtk_", "gdk_" — keep only the meaningful parts + // Strategy: drop the first segment if it looks like a namespace prefix (< 3 chars) + if parts.count > 1 && parts[0].count < 5 && parts[0].allSatisfy({ $0.isLowercase }) { + parts = Array(parts.dropFirst()) + } + // If the result starts with the first part being very generic (e.g. "object", "type"), + // we might need to keep more context. For now, just camelCase what remains. + guard !parts.isEmpty else { return cName } + let camel = parts.enumerated().map { idx, word in + idx == 0 ? word.lowercased() : word.capitalized + }.joined() + return swiftKeywords.contains(camel) ? "`\(camel)`" : camel +} + +/// Converts a GIR parameter name to a Swift parameter name, escaping keywords. +func swiftParameterName(_ girName: String) -> String { + if swiftKeywords.contains(girName) { return "`\(girName)`" } + return girName +} + +/// Converts a GIR member name to a Swift enum case name, escaping keywords. +/// +/// Swift keywords and names starting with a digit are escaped with backticks. +/// The `_` prefix is stripped from GObject naming conventions (e.g. `_normal` +/// → `normal`). +func swiftEnumCaseName(_ girName: String) -> String { + var name = girName + // Strip leading underscore (GObject naming convention) + if name.hasPrefix("_") { + let stripped = String(name.dropFirst()) + // If stripping the underscore leaves a name starting with a digit, + // keep the underscore — Swift requires identifiers to start with a + // letter or underscore, and backtick escaping doesn't lift this + // restriction. + if stripped.first?.isNumber != true { + name = stripped + } + } + // Names starting with a digit cannot be identifiers even backtick-escaped; + // prefix with underscore. + if name.first?.isNumber == true { + name = "_\(name)" + } + // Escaped keyword + if swiftKeywords.contains(name) { return "`\(name)`" } + return name +} + +/// Swift reserved words that need backtick escaping when used as identifiers. +private let swiftKeywords: Set = [ + "as", "associativity", "break", "case", "catch", "class", "continue", + "default", "defer", "deinit", "do", "else", "enum", "extension", + "fallthrough", "false", "fileprivate", "for", "func", "get", "guard", + "if", "import", "in", "init", "inout", "internal", "is", "let", "nil", + "open", "operator", "optional", "override", "postfix", "prefix", + "private", "protocol", "public", "repeat", "required", "return", + "self", "set", "static", "struct", "subscript", "super", "switch", + "throw", "throws", "true", "try", "typealias", "var", "weak", "where", + "while", "willSet", "didSet", "PrecedenceGroup", "indirect", "left", + "none", "nonmutating", "precedencegroup", "right", + "Any", "Self", "Type", "Protocol", +] diff --git a/Sources/SwiftGtkGenCore/TypeMapper.swift b/Sources/SwiftGtkGenCore/TypeMapper.swift new file mode 100644 index 0000000..fa80e3e --- /dev/null +++ b/Sources/SwiftGtkGenCore/TypeMapper.swift @@ -0,0 +1,372 @@ +// TypeMapper.swift +// The ONE switch on GIRType — every other component goes through here and +// only sees finished `Mapping` values. This centralisation eliminates the +// regression pattern where a type-mapping fix had to touch ~16 parallel +// switches, and missing one *was* the regression. +// +// Rule 2 of the three rules: TypeMapper is the only place allowed to switch +// on GIRType. The renderer must never see a GIRType — only finished plans. + +import Foundation + +// MARK: - Mapping Output + +/// The complete Swift-side description of a GIR type: what Swift type name to +/// emit, how to pass values to C, how to receive values from C, and how to +/// go through the GValue machinery for properties. +public struct Mapping: Equatable, Sendable { + /// The public Swift type name, module-qualified via the registry when + /// the type lives in another module (e.g. `"GObject.Object"`). + public let swiftType: String + /// The type as Swift imports the C declaration. Used in trampoline + /// signatures and `@convention(c)` callback types where the raw C + /// type is what matters, not the wrapper. + public let cSwiftType: String + /// How to marshal a Swift value into the C call. + public let marshalIn: MarshalIn + /// How to marshal a C return value into Swift. + public let marshalOut: MarshalOut + /// How to access this type through GValue, or `nil` when GValue is + /// not supported for the type. + public let gvalue: GValueOps? + /// The underlying type category, for use by the planner to decide + /// whether dependent types have already been generated. + /// - `.needsClass`: object/interface — needs a class declaration before + /// callables referencing it can be emitted. + /// - `.needsRecord`: boxed record — needs a record wrapper. + /// - `.ready`: enum/bitfield/primitive/string — no dependency. + public let category: BindingCategory + + public init(swiftType: String, cSwiftType: String, + marshalIn: MarshalIn, marshalOut: MarshalOut, + gvalue: GValueOps? = nil, + category: BindingCategory = .ready) { + self.swiftType = swiftType; self.cSwiftType = cSwiftType + self.marshalIn = marshalIn; self.marshalOut = marshalOut + self.gvalue = gvalue + self.category = category + } + + /// Wraps the Swift type in `Optional` when the GIR marks it nullable, + /// returning a new `Mapping` with the optionalised type. + /// Already-optional types (e.g., `UnsafeMutableRawPointer?`) are not + /// double-wrapped. + public func optionalised(nullable: Bool) -> Mapping { + guard nullable else { return self } + // Don't double-wrap types that are already optional. + guard !swiftType.hasSuffix("?") else { return self } + let newCST = cSwiftType.hasSuffix("?") ? cSwiftType : "\(cSwiftType)?" + return Mapping( + swiftType: "\(swiftType)?", + cSwiftType: newCST, + marshalIn: marshalIn, + marshalOut: marshalOut, + gvalue: gvalue, + category: category + ) + } + + /// True when this mapping references a type that is already generated + /// (primitive, enum, bitfield, string) and does not require a class or + /// record declaration to be emitted first. + public var isReadyForCallables: Bool { + category == .ready + } +} + +// MARK: - Error + +/// A typed error from `map(…)`, carrying the skip reason and human detail +/// so the planner can record a `SkipEntry` without inspecting strings. +public struct MapError: Error, Equatable, Sendable { + public let reason: SkipReason + public let detail: String + + public init(reason: SkipReason, detail: String) { + self.reason = reason; self.detail = detail + } +} + +// MARK: - Map Context + +/// The contextual information needed to resolve a GIR type reference: +/// the registry that knows every loaded type, the current Swift module +/// (for qualifying cross-module references), and the current GIR namespace +/// (for resolving unqualified name lookups). +public struct MapContext: Sendable { + public let registry: TypeRegistry + public let currentModule: String + public let currentNamespace: String + + public init(registry: TypeRegistry, currentModule: String, currentNamespace: String) { + self.registry = registry; self.currentModule = currentModule + self.currentNamespace = currentNamespace + } +} + +// MARK: - The Mapper + +/// Maps a `GIRType` to its complete Swift-side representation — the one +/// and only place in the codebase that switches on `GIRType`. +/// +/// Every other component (planner, renderer, signal trampoline builder) calls +/// through this function and receives a finished `Mapping`. This is Rule 2 of +/// the three rearchitecture rules: the renderer must never see `GIRType`. +/// +/// Types the mapper does not yet support throw `MapError` with a precise +/// `SkipReason`, so the planner records a `SkipEntry` and the whole callable +/// is skipped — Rule 3: skip, never guess. +/// +/// - Parameters: +/// - type: The GIR type to map. +/// - nullable: Whether the GIR marks the value as potentially `NULL`. +/// - transfer: Ownership transfer semantics for the value. +/// - context: The resolution context (registry + current module/namespace). +/// - Returns: A complete `Mapping` ready for plan consumption. +/// - Throws: `MapError` with a `SkipReason` when the type is not yet supported. +public func map( + _ type: GIRType, + nullable: Bool, + transfer: TransferOwnership, + context: MapContext +) throws(MapError) -> Mapping { + let result: Mapping = try _mapValue(type: type, transfer: transfer, context: context) + return result.optionalised(nullable: nullable) +} + +// MARK: - Internal dispatch + +/// Top-level dispatch: one switch with thin per-category delegation so that +/// cyclomatic complexity stays within project limits. +private func _mapValue( + type: GIRType, + transfer: TransferOwnership, + context: MapContext +) throws(MapError) -> Mapping { + + switch type { + case .void: + return .voidMapping + case .boolean: + return .booleanMapping + case .int8, .int16, .int32, .int64, + .uint8, .uint16, .uint32, .uint64, + .long, .ulong, .size, .ssize, + .char, .uchar, .unichar: + return try mapPrimitive(type) + case .gtype: + return .gtypeMapping + case .float, .double: + return try mapPrimitive(type) + case .string: + return .stringMapping(free: transfer == .full) + case .filename: + return .filenameMapping(free: transfer == .full) + case .pointer: + return .pointerMapping + case .vaList: + throw MapError(reason: .varargs, + detail: "va_list parameters are permanently unbridgeable") + case .typeRef(let name, let namespace): + return try mapTypeRef(name: name, namespace: namespace ?? context.currentNamespace, + transfer: transfer, context: context) + case .container(let kind, let elements): + throw MapError(reason: .containerType, + detail: "\(kind.rawValue) container with \(elements.count) element(s) not yet bridged") + case .cArray(_, let info): + if !info.hasKnownLength { + throw MapError(reason: .arrayWithoutLength, + detail: "C array has no length annotation") + } + throw MapError(reason: .arrayWithoutLength, + detail: "C array bridging not yet implemented") + case .optional(let inner): + let innerMap = try _mapValue(type: inner, transfer: transfer, context: context) + return innerMap.optionalised(nullable: true) + } +} + +// MARK: - Primitives + +private func mapPrimitive(_ type: GIRType) throws(MapError) -> Mapping { + switch type { + case .int8: return .int8Mapping + case .int16: return .int16Mapping + case .int32: return .int32Mapping + case .int64: return .int64Mapping + case .uint8: return .uint8Mapping + case .uint16: return .uint16Mapping + case .uint32: return .uint32Mapping + case .uint64: return .uint64Mapping + case .long: return .longMapping + case .ulong: return .ulongMapping + case .size: return Mapping(swiftType: "UInt", cSwiftType: "UInt", marshalIn: .numericCast(targetType: "UInt"), marshalOut: .numericCast(fromType: "UInt")) + case .ssize: return Mapping(swiftType: "Int", cSwiftType: "Int", marshalIn: .numericCast(targetType: "Int"), marshalOut: .numericCast(fromType: "Int")) + case .char: return Mapping(swiftType: "Int8", cSwiftType: "Int8", marshalIn: .direct, marshalOut: .direct) + case .uchar: return Mapping(swiftType: "UInt8", cSwiftType: "UInt8", marshalIn: .direct, marshalOut: .direct) + case .unichar: return Mapping(swiftType: "UInt32", cSwiftType: "UInt32", marshalIn: .direct, marshalOut: .direct) + case .float: return .floatMapping + case .double: return .doubleMapping + default: throw MapError(reason: .unknownType, detail: "not a primitive: \(type)") + } +} + +// MARK: - Named type references + +private func mapTypeRef( + name: String, + namespace: String, + transfer: TransferOwnership, + context: MapContext +) throws(MapError) -> Mapping { + guard let resolved = context.registry.resolve(name: name, namespace: namespace) else { + throw MapError(reason: .unknownType, + detail: "unresolved type '\(namespace).\(name)'") + } + + switch resolved.category { + case .foreign(let foreignNS): + throw MapError(reason: .foreignNamespace, + detail: "type '\(namespace).\(name)' lives in unavailable namespace '\(foreignNS)'") + + case .object, .interface: + let swiftType = context.registry.swiftTypeName(for: resolved, in: context.currentModule) + return Mapping(swiftType: swiftType, cSwiftType: "UnsafeMutableRawPointer?", + marshalIn: .objectPointer, marshalOut: .objectWrap(sink: false), + category: .needsClass) + + case .enumeration: + let swiftType = context.registry.swiftTypeName(for: resolved, in: context.currentModule) + // cSwiftType is the C enum type name as Swift imports it (e.g., "GConnectFlags") + let cEnumType = resolved.cType.isEmpty ? "Int32" : resolved.cType + return Mapping( + swiftType: swiftType, cSwiftType: cEnumType, + marshalIn: .enumRaw, marshalOut: .enumFromRaw(swiftType: swiftType), + gvalue: GValueOps(typeMacro: "G_TYPE_ENUM", + getterSuffix: "enum", setterSuffix: "enum", needsCast: true)) + + case .bitfield: + let swiftType = context.registry.swiftTypeName(for: resolved, in: context.currentModule) + let cEnumType = resolved.cType.isEmpty ? "UInt32" : resolved.cType + return Mapping( + swiftType: swiftType, cSwiftType: cEnumType, + marshalIn: .bitfieldRaw, marshalOut: .bitfieldFromRaw(swiftType: swiftType), + gvalue: GValueOps(typeMacro: "G_TYPE_FLAGS", + getterSuffix: "flags", setterSuffix: "flags", needsCast: true)) + + case .boxedRecord: + let swiftType = context.registry.swiftTypeName(for: resolved, in: context.currentModule) + return Mapping( + swiftType: swiftType, cSwiftType: "UnsafeMutableRawPointer?", + marshalIn: .boxedPointer, marshalOut: .boxedWrap(copy: transfer != .full), + gvalue: GValueOps(typeMacro: "G_TYPE_BOXED", + getterSuffix: "boxed", setterSuffix: "boxed", needsCast: true), + category: .needsRecord) + + case .gtypeStruct: + throw MapError(reason: .gtypeStruct, + detail: "'\(namespace).\(name)' is a GObject class/interface structure") + + case .plainRecord: + throw MapError(reason: .plainRecord, + detail: "'\(namespace).\(name)' has no GType registration or lifetime functions") + + case .callback: + throw MapError(reason: .callbackWithoutUserData, + detail: "callback '\(namespace).\(name)' not yet supported as a mapped type") + + case .alias(let target): + return try _mapValue(type: target, transfer: transfer, context: context) + } +} + +// MARK: - Mapping factories (static, to keep per-type noise compact) + +extension Mapping { + fileprivate static let voidMapping = Mapping( + swiftType: "Void", cSwiftType: "Void", + marshalIn: .direct, marshalOut: .direct) + + fileprivate static let booleanMapping = Mapping( + swiftType: "Bool", cSwiftType: "Int32", + marshalIn: .boolToGboolean, marshalOut: .gbooleanToBool, + gvalue: GValueOps(typeMacro: "G_TYPE_BOOLEAN", + getterSuffix: "boolean", setterSuffix: "boolean")) + + static let int8Mapping = Mapping( + swiftType: "Int8", cSwiftType: "Int8", + marshalIn: .direct, marshalOut: .direct) + static let int16Mapping = Mapping( + swiftType: "Int16", cSwiftType: "Int16", + marshalIn: .direct, marshalOut: .direct) + static let int32Mapping = Mapping( + swiftType: "Int32", cSwiftType: "Int32", + marshalIn: .direct, marshalOut: .direct, + gvalue: GValueOps(typeMacro: "G_TYPE_INT", + getterSuffix: "int", setterSuffix: "int", needsCast: true)) + static let int64Mapping = Mapping( + swiftType: "Int", cSwiftType: "Int", // gint64 → Int on LP64, Int64 on LLP64 + marshalIn: .numericCast(targetType: "Int"), marshalOut: .numericCast(fromType: "Int"), + gvalue: GValueOps(typeMacro: "G_TYPE_INT64", + getterSuffix: "int64", setterSuffix: "int64")) + static let uint8Mapping = Mapping( + swiftType: "UInt8", cSwiftType: "UInt8", + marshalIn: .direct, marshalOut: .direct) + static let uint16Mapping = Mapping( + swiftType: "UInt16", cSwiftType: "UInt16", + marshalIn: .direct, marshalOut: .direct) + static let uint32Mapping = Mapping( + swiftType: "UInt32", cSwiftType: "UInt32", + marshalIn: .direct, marshalOut: .direct, + gvalue: GValueOps(typeMacro: "G_TYPE_UINT", + getterSuffix: "uint", setterSuffix: "uint", needsCast: true)) + static let uint64Mapping = Mapping( + swiftType: "UInt", cSwiftType: "UInt", // guint64 → UInt on LP64, UInt64 on LLP64 + marshalIn: .numericCast(targetType: "UInt"), marshalOut: .numericCast(fromType: "UInt"), + gvalue: GValueOps(typeMacro: "G_TYPE_UINT64", + getterSuffix: "uint64", setterSuffix: "uint64")) + static let longMapping = Mapping( + swiftType: "Int", cSwiftType: "Int", + marshalIn: .numericCast(targetType: "Int"), marshalOut: .numericCast(fromType: "Int"), + gvalue: GValueOps(typeMacro: "G_TYPE_LONG", + getterSuffix: "long", setterSuffix: "long")) + static let ulongMapping = Mapping( + swiftType: "UInt", cSwiftType: "UInt", + marshalIn: .numericCast(targetType: "UInt"), marshalOut: .numericCast(fromType: "UInt"), + gvalue: GValueOps(typeMacro: "G_TYPE_ULONG", + getterSuffix: "ulong", setterSuffix: "ulong")) + static let gtypeMapping = Mapping( + swiftType: "UInt", cSwiftType: "UInt", + marshalIn: .numericCast(targetType: "UInt"), marshalOut: .numericCast(fromType: "UInt"), + gvalue: GValueOps(typeMacro: "G_TYPE_GTYPE", + getterSuffix: "gtype", setterSuffix: "gtype")) + static let floatMapping = Mapping( + swiftType: "Float", cSwiftType: "Float", + marshalIn: .direct, marshalOut: .direct, + gvalue: GValueOps(typeMacro: "G_TYPE_FLOAT", + getterSuffix: "float", setterSuffix: "float")) + static let doubleMapping = Mapping( + swiftType: "Double", cSwiftType: "Double", + marshalIn: .direct, marshalOut: .direct, + gvalue: GValueOps(typeMacro: "G_TYPE_DOUBLE", + getterSuffix: "double", setterSuffix: "double")) + static let pointerMapping = Mapping( + swiftType: "UnsafeMutableRawPointer?", cSwiftType: "UnsafeMutableRawPointer?", + marshalIn: .direct, marshalOut: .direct, + gvalue: GValueOps(typeMacro: "G_TYPE_POINTER", + getterSuffix: "pointer", setterSuffix: "pointer")) + + static func stringMapping(free: Bool) -> Mapping { + Mapping( + swiftType: "String", cSwiftType: "UnsafePointer?", + marshalIn: .stringToC, marshalOut: .stringCopy(free: free), + gvalue: GValueOps(typeMacro: "G_TYPE_STRING", + getterSuffix: "string", setterSuffix: "string")) + } + + static func filenameMapping(free: Bool) -> Mapping { + Mapping( + swiftType: "String", cSwiftType: "UnsafePointer?", + marshalIn: .stringToC, marshalOut: .stringCopy(free: free)) + } +} diff --git a/Sources/SwiftGtkGenCore/TypeRegistry.swift b/Sources/SwiftGtkGenCore/TypeRegistry.swift new file mode 100644 index 0000000..f59be18 --- /dev/null +++ b/Sources/SwiftGtkGenCore/TypeRegistry.swift @@ -0,0 +1,402 @@ +// TypeRegistry.swift +// The single source of truth for "what is this GIR type?". Built once from every +// loaded repository, it resolves type references across namespace boundaries and +// classifies each type by what the generator can actually do with it. +// +// This replaces two ad-hoc mechanisms: string-set membership tests +// (`classTypeNames.contains(...)`) for deciding whether a type is pointer-backed, +// and the `parent.contains(".")` check that treated every cross-namespace parent +// as a root — severing the inheritance chain at module boundaries. + +import Foundation + +/// What a resolved GIR type is, and what the generator can do with it. +/// +/// Classification is driven entirely by GIR metadata (GType registration, +/// `glib:is-gtype-struct-for`, element kind), never by name matching. +public enum TypeCategory: Equatable, Sendable { + /// A GObject class. + /// - Parameters: + /// - parentGIRName: The fully qualified parent class, e.g. `"GObject.InitiallyUnowned"`. + /// - isAbstract: Whether the class cannot be instantiated directly. + /// - isFinal: Whether GIR forbids subclassing. + /// - interfaces: Fully qualified names of implemented interfaces. + case object(parentGIRName: String?, isAbstract: Bool, isFinal: Bool, interfaces: [String]) + /// A GObject interface. + /// - Parameter prereqs: Fully qualified prerequisite type names. + case interface(prereqs: [String]) + /// An enumeration. + /// - Parameter hasGType: Whether it is GType-registered (enabling GValue access). + case enumeration(hasGType: Bool) + /// A flags type. + /// - Parameter hasGType: Whether it is GType-registered (enabling GValue access). + case bitfield(hasGType: Bool) + /// A boxed record: GType-registered, so copyable and freeable. + /// - Parameters: + /// - copyFunction: An explicit copy function, if GIR states one. + /// - freeFunction: An explicit free function, if GIR states one. + case boxedRecord(copyFunction: String?, freeFunction: String?) + /// A GObject class or interface structure. Never bound. + /// - Parameter forType: The type this is the type struct for. + case gtypeStruct(forType: String) + /// A record with no GType registration and no configured lifetime + /// functions. Cannot be safely wrapped; skipped. + case plainRecord + /// A callback function type. + case callback + /// A type alias. + /// - Parameter target: The aliased type. + case alias(target: GIRType) + /// A type from a namespace with no loaded GIR (e.g. `cairo` on systems + /// shipping no `cairo-1.0.gir`). + /// + /// Resolving to `foreign` rather than failing lets the planner skip + /// affected callables with a precise ``SkipReason/foreignNamespace`` + /// instead of emitting a fabricated type reference that fails to compile. + /// - Parameter namespace: The unavailable namespace. + case foreign(namespace: String) +} + +/// A GIR type resolved to everything the generator needs to emit it. +public struct ResolvedType: Equatable, Sendable { + /// The fully qualified GIR name, e.g. `"Gtk.Widget"`. + public let girName: String + /// The Swift module the type lives in, e.g. `"Gtk"`. + public let swiftModule: String + /// The unqualified Swift type name, e.g. `"Widget"`. + public let swiftName: String + /// The C type name, e.g. `"GtkWidget"`. + public let cType: String + /// The `glib:get-type` function, if the type is GType-registered. + public let getTypeFunction: String? + /// What kind of type this is, and what can be done with it. + public let category: TypeCategory + + /// Creates a resolved type. + /// + /// - Parameters: + /// - girName: The fully qualified GIR name. + /// - swiftModule: The owning Swift module. + /// - swiftName: The unqualified Swift type name. + /// - cType: The C type name. + /// - getTypeFunction: The `glib:get-type` function, if any. + /// - category: The type's classification. + public init( + girName: String, swiftModule: String, swiftName: String, cType: String, + getTypeFunction: String? = nil, category: TypeCategory + ) { + self.girName = girName + self.swiftModule = swiftModule + self.swiftName = swiftName + self.cType = cType + self.getTypeFunction = getTypeFunction + self.category = category + } + + /// Whether values of this type are backed by a pointer. + /// + /// Determines call-site marshalling: pointer-backed values pass their + /// underlying pointer, while enums, flags, and aliases pass by value. + public var isPointerBacked: Bool { + switch category { + case .object, .interface, .boxedRecord: return true + case .enumeration, .bitfield, .gtypeStruct, .plainRecord, .callback, .alias, .foreign: return false + } + } +} + +/// A global symbol table over every loaded GIR namespace. +/// +/// The registry is the only component that answers "what is `Gtk.Widget`?" — +/// including across module boundaries, which is what makes cross-namespace +/// inheritance (`open class Widget: GObject.InitiallyUnowned`) expressible. +/// +/// ### Example +/// ```swift +/// let registry = TypeRegistry(repositories: analysis.repositories) +/// let widget = registry.resolve(.typeRef("Widget", namespace: "Gtk"), from: "Gtk") +/// registry.descendsFromInitiallyUnowned("Gtk.Widget") // true → constructors sink +/// ``` +public struct TypeRegistry: Sendable { + /// Every resolved type, keyed by fully qualified GIR name. + private var types: [String: ResolvedType] = [:] + /// Namespaces whose GIR was loaded and whose types are therefore known. + /// + /// A reference into any namespace outside this set is foreign by + /// definition; a reference into a namespace *inside* it that names no + /// known type is genuinely unknown. + private let loadedNamespaces: Set + /// Namespaces known to be referenced but deliberately or unavoidably not + /// generated. Reported so coverage gaps are visible. + private let foreignNamespaces: Set + /// Maps a GIR namespace name to its Swift module name. + private let namespaceToModule: [String: String] + + /// The fully qualified name of the GObject root class. + public static let objectGIRName = "GObject.Object" + /// The fully qualified name of the class whose descendants have floating + /// references, and whose constructors must therefore sink. + public static let initiallyUnownedGIRName = "GObject.InitiallyUnowned" + + /// Builds a registry from every parsed repository in the monorepo. + /// + /// Namespaces referenced via `` but absent from `repositories` + /// are recorded as foreign, so references into them resolve to + /// ``TypeCategory/foreign(namespace:)`` rather than failing. + /// + /// - Parameters: + /// - repositories: Parsed repositories keyed by Swift module name. + /// - manualNamespaces: Namespaces deliberately excluded from generation + /// and treated as foreign even when a GIR is present. Defaults to empty. + public init(repositories: [String: Repository], manualNamespaces: Set = []) { + var namespaceToModule: [String: String] = [:] + for (module, repo) in repositories { + for ns in repo.namespaces { + namespaceToModule[ns.name] = module + } + } + self.namespaceToModule = namespaceToModule + self.loadedNamespaces = Set(namespaceToModule.keys).subtracting(manualNamespaces) + + var foreign = manualNamespaces + for repo in repositories.values { + for include in repo.includedPackages where namespaceToModule[include.name] == nil { + foreign.insert(include.name) + } + } + self.foreignNamespaces = foreign + + for (module, repo) in repositories { + for ns in repo.namespaces where !manualNamespaces.contains(ns.name) { + register(namespace: ns, module: module) + } + } + } + + /// Registers every type in one namespace. + /// + /// - Parameters: + /// - ns: The namespace whose types to register. + /// - module: The Swift module the namespace maps to. + private mutating func register(namespace ns: Namespace, module: String) { + /// Qualifies a possibly-unqualified GIR name against this namespace. + func qualify(_ name: String) -> String { + name.contains(".") ? name : "\(ns.name).\(name)" + } + + for cls in ns.classes { + let girName = "\(ns.name).\(cls.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: cls.name, cType: cls.cType, + getTypeFunction: cls.getTypeFunction, + category: .object( + parentGIRName: cls.parent.map(qualify), + isAbstract: cls.isAbstract, + isFinal: cls.isFinal, + interfaces: cls.implements.map(qualify) + ) + ) + } + for iface in ns.interfaces { + let girName = "\(ns.name).\(iface.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: iface.name, cType: iface.cType, + getTypeFunction: iface.getTypeFunction, + category: .interface(prereqs: iface.prereqs.map(qualify)) + ) + } + for e in ns.enumerations { + let girName = "\(ns.name).\(e.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: e.name, cType: e.cType, + getTypeFunction: e.getTypeFunction, + category: .enumeration(hasGType: e.getTypeFunction != nil) + ) + } + for b in ns.bitfields { + let girName = "\(ns.name).\(b.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: b.name, cType: b.cType, + getTypeFunction: b.getTypeFunction, + category: .bitfield(hasGType: b.getTypeFunction != nil) + ) + } + for rec in ns.records { + let girName = "\(ns.name).\(rec.name)" + let category: TypeCategory + if let forType = rec.isGTypeStructFor { + category = .gtypeStruct(forType: qualify(forType)) + } else if rec.isBoxed { + category = .boxedRecord(copyFunction: rec.copyFunction, freeFunction: rec.freeFunction) + } else { + category = .plainRecord + } + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: rec.name, cType: rec.cType, + getTypeFunction: rec.getTypeFunction, category: category + ) + } + for cb in ns.callbacks { + let girName = "\(ns.name).\(cb.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: cb.name, cType: cb.cType, + category: .callback + ) + } + for alias in ns.aliases { + let girName = "\(ns.name).\(alias.name)" + types[girName] = ResolvedType( + girName: girName, swiftModule: module, swiftName: alias.name, cType: alias.cType, + category: .alias(target: alias.target) + ) + } + } + + /// Resolves a GIR type reference to its declaration. + /// + /// Unqualified references resolve against `namespace` — the namespace of + /// the GIR that wrote them — which is how GIR itself scopes bare names. + /// References into a namespace with no loaded GIR resolve to a + /// ``TypeCategory/foreign(namespace:)`` placeholder. + /// + /// - Parameters: + /// - type: The type reference to resolve. + /// - namespace: The GIR namespace the reference was written in. + /// - Returns: The resolved type, or `nil` if the name is unknown — which + /// the planner reports as ``SkipReason/unknownType`` rather than guessing. + public func resolve(_ type: GIRType, from namespace: String) -> ResolvedType? { + guard case .typeRef(let name, let ns) = type else { return nil } + return resolve(name: name, namespace: ns ?? namespace) + } + + /// Resolves a type by name and namespace. + /// + /// A reference into a namespace whose GIR was not loaded is foreign — this + /// covers namespaces reached transitively (Gtk names `Gio.Application` + /// without including Gio directly) as well as ones with no GIR at all + /// (cairo). A reference into a *loaded* namespace that names no known type + /// is genuinely unknown and returns `nil`, so the planner reports it rather + /// than papering over it. + /// + /// - Parameters: + /// - name: The unqualified type name, e.g. `"Widget"`. + /// - namespace: The GIR namespace, e.g. `"Gtk"`. + /// - Returns: The resolved type, or `nil` if unknown. + public func resolve(name: String, namespace: String) -> ResolvedType? { + if let known = types["\(namespace).\(name)"] { return known } + if !loadedNamespaces.contains(namespace) { + return ResolvedType( + girName: "\(namespace).\(name)", swiftModule: namespace, swiftName: name, + cType: "", category: .foreign(namespace: namespace) + ) + } + return nil + } + + /// Resolves a fully qualified GIR name, e.g. `"Gtk.Widget"`. + /// + /// - Parameter girName: The qualified name. + /// - Returns: The resolved type, or `nil` if unknown. + public func resolve(girName: String) -> ResolvedType? { + guard let dot = girName.firstIndex(of: ".") else { return nil } + return resolve( + name: String(girName[girName.index(after: dot)...]), + namespace: String(girName[.. [ResolvedType] { + var result: [ResolvedType] = [] + var seen: Set = [girName] + var current = girName + while let resolved = resolve(girName: current), + case .object(let parent, _, _, _) = resolved.category, + let parentName = parent, + !seen.contains(parentName), + let parentType = resolve(girName: parentName) + { + result.append(parentType) + seen.insert(parentName) + current = parentName + } + return result + } + + /// Whether a class descends from `GObject.InitiallyUnowned`. + /// + /// This is the sole basis for deciding that a constructor's result must be + /// sunk with `g_object_ref_sink`. GIR annotates most widget constructors + /// `transfer-ownership="none"` despite returning a *floating* reference, so + /// the transfer annotation alone cannot be trusted for this decision. + /// + /// - Parameter girName: The fully qualified class name. + /// - Returns: `true` when the class is, or descends from, `InitiallyUnowned`. + public func descendsFromInitiallyUnowned(_ girName: String) -> Bool { + if girName == Self.initiallyUnownedGIRName { return true } + return ancestry(of: girName).contains { $0.girName == Self.initiallyUnownedGIRName } + } + + /// Whether a class is, or descends from, `GObject.Object`. + /// + /// - Parameter girName: The fully qualified class name. + /// - Returns: `true` for every GObject-derived class. + public func isGObject(_ girName: String) -> Bool { + if girName == Self.objectGIRName { return true } + return ancestry(of: girName).contains { $0.girName == Self.objectGIRName } + } + + /// The Swift spelling of a resolved type as written from `module`. + /// + /// Types from another module are qualified (`GObject.Object`); types from + /// the current module are bare (`Widget`). + /// + /// - Parameters: + /// - type: The resolved type to spell. + /// - module: The Swift module the reference is being written in. + /// - Returns: The Swift type name to emit. + public func swiftTypeName(for type: ResolvedType, in module: String) -> String { + type.swiftModule == module ? type.swiftName : "\(type.swiftModule).\(type.swiftName)" + } + + /// Every class that is subclassed by some other loaded class. + /// + /// Such classes must be emitted `open` so subclasses — including those in + /// *other* modules — can inherit from them. Computing this registry-wide is + /// what fixes the previous same-namespace-only analysis, under which + /// `GObject.Object` was never `open` and `Gtk.Widget` could not inherit it. + /// + /// - Returns: Fully qualified names of all subclassed classes. + public func subclassedTypes() -> Set { + var result: Set = [] + for type in types.values { + if case .object(let parent, _, _, _) = type.category, let parent { + result.insert(parent) + } + } + return result + } + + /// All registered types, sorted by GIR name for stable iteration. + public var allTypes: [ResolvedType] { + types.values.sorted { $0.girName < $1.girName } + } + + /// The namespaces referenced via `` but not generated, plus any + /// namespaces excluded by configuration. + /// + /// Namespaces reached only transitively (never named in a loaded GIR's + /// includes) still resolve as foreign; they simply are not enumerated here. + public var foreign: Set { foreignNamespaces } + + /// The namespaces whose GIR was loaded and whose types are fully known. + public var loaded: Set { loadedNamespaces } +} diff --git a/Sources/SwiftGtkGenCore/XMLParser.swift b/Sources/SwiftGtkGenCore/XMLParser.swift index e95956b..4b30c89 100644 --- a/Sources/SwiftGtkGenCore/XMLParser.swift +++ b/Sources/SwiftGtkGenCore/XMLParser.swift @@ -1,3 +1,9 @@ +// XMLParser.swift +// GIR XML → IR. The delegate maintains an explicit element stack so that every +// element attaches to its true parent, and nested constructs (container element +// types, callback-typed parameters, virtual-method bodies) nest correctly +// instead of leaking into whatever `current*` slot happened to be set. + import Foundation #if canImport(FoundationXML) import FoundationXML @@ -18,10 +24,21 @@ public enum GIRParserError: Error { /// Parses GIR XML files into the intermediate representation model. /// -/// Uses Foundation's `XMLParser` in a SAX-style delegate pattern. The parser -/// handles all GIR element types including classes, interfaces, records, -/// enumerations, bitfields, callbacks, methods, properties, signals, functions, -/// constants, and aliases. +/// Uses Foundation's `XMLParser` in a SAX-style delegate pattern, driving an +/// explicit element stack. All GIR element types are handled: classes, +/// interfaces, records, enumerations, bitfields, callbacks, methods, +/// properties, signals, functions, constants, and aliases. +/// +/// The parser is deliberately non-judgemental: it records what the GIR says, +/// including symbols that cannot be bound. Deciding what to *bind* is the +/// planner's job, which reports skips with reasons. +/// +/// ### Example +/// ```swift +/// let parser = GIRParser() +/// let repo = try parser.parse(fileURL: URL(fileURLWithPath: "/usr/share/gir-1.0/GLib-2.0.gir")) +/// print(repo.namespaces.first?.classes.count ?? 0) +/// ``` public struct GIRParser { /// Creates a new GIR parser. public init() {} @@ -61,396 +78,575 @@ public struct GIRParser { } } +// MARK: - Element Stack + +/// A partially-built `` element. +/// +/// Nested `` children supply container element types, e.g. +/// ``. +struct TypeBuilder { + /// The GIR type name attribute, e.g. `"utf8"` or `"GLib.List"`. + var name: String + /// The `c:type` attribute, e.g. `"gchar*"`. + var cType: String + /// Element types collected from nested `` children. + var children: [GIRType] = [] +} + +/// A partially-built `` element. +struct ArrayBuilder { + /// The array's `name` attribute; set for GLib container arrays. + var name: String? + /// Length metadata gathered from the element's attributes. + var info: ArrayInfo + /// The element type, from the nested `` or `` child. + var children: [GIRType] = [] +} + +/// One open XML element during parsing. +/// +/// The delegate pushes a frame on every element it tracks and pops it on close, +/// attaching the completed value to the frame beneath. Untracked elements push +/// ``ignored`` so that their children attach to nothing rather than leaking into +/// an ancestor. +indirect enum Frame { + case namespace(Namespace) + case klass(Class) + case interface(Interface) + case record(Record) + case enumeration(Enumeration) + case bitfield(Bitfield) + case callback(Callback) + case constructor(Constructor) + case method(Method) + case function(GlobalFunction) + case signal(Signal) + case property(Property) + case parameterList([Parameter]) + case parameter(Parameter) + case returnValue(ReturnValue) + case field(Field) + case constant(Constant) + case alias(Alias) + case type(TypeBuilder) + case array(ArrayBuilder) + case doc + /// An element whose content is deliberately discarded (virtual methods, + /// unions, source positions, and anything else not modelled). + case ignored(String) +} + // MARK: - XMLParser Delegate /// SAX-style delegate for `XMLParser` that builds a `Repository` from GIR XML. /// -/// Tracks a stack of currently-open GIR elements via `current*` properties. -/// On `didStartElement` it creates the corresponding model object and populates -/// attributes. On `didEndElement` it appends the completed object to its parent. -/// The final `repository` property contains the fully parsed GIR document. +/// Maintains an explicit ``Frame`` stack: `didStartElement` pushes a frame, +/// `didEndElement` pops it and attaches the finished value to its parent. This +/// makes parent-child relationships exact, which flat `current*` slots could not +/// express for nested constructs. final class GIRXMLDelegate: NSObject, XMLParserDelegate { /// The repository being populated during parsing. var repository = Repository() /// Set to the first error encountered, or `nil` if parsing succeeds. var parseError: GIRParserError? - var currentNamespace: Namespace? - var currentClass: Class? - var currentInterface: Interface? - var currentRecord: Record? - var currentEnum: Enumeration? - var currentBitfield: Bitfield? - var currentMethod: Method? - var currentConstructor: Constructor? - var currentSignal: Signal? - var currentProperty: Property? - var currentFunction: GlobalFunction? - var currentParameter: Parameter? - var currentCallback: Callback? - var currentConstant: Constant? - var currentAlias: Alias? - var currentReturnType: GIRType? - var currentText: String = "" - /// Counter for nested untracked elements that contain child elements. - /// When > 0, `` elements belong to untracked parents and should be discarded. - var untrackedDepth: Int = 0 + /// The stack of currently-open elements, outermost first. + private var stack: [Frame] = [] + /// Accumulated character data for the innermost `` element. + private var currentText: String = "" + + // MARK: Element start - /// Called when the XML parser encounters an opening element tag. - /// - /// Creates the corresponding model object for the element and populates it - /// from XML attributes. Maintains a stack of `current*` properties so that - /// nested elements can attach themselves to their parent on close. - /// - Parameters: - /// - parser: The XML parser. - /// - elementName: The name of the XML element. - /// - namespaceURI: The namespace URI of the element. - /// - qualifiedName: The qualified name of the element. - /// - attributeDict: The element's attributes. func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName: String?, attributes attributeDict: [String: String] = [:]) { switch elementName { case "c:include": - guard let name = attributeDict["name"] else { return } - repository.cHeaderPath = name + if let name = attributeDict["name"] { repository.cHeaderPath = name } + stack.append(.ignored(elementName)) case "package": - guard let name = attributeDict["name"] else { return } - repository.packageName = name + if let name = attributeDict["name"] { repository.packageName = name } + stack.append(.ignored(elementName)) case "include": - guard let name = attributeDict["name"], let version = attributeDict["version"] else { return } - // GIR dependency includes appear before the element - // Derive link name: lowercase(library) + "-" + major version (e.g. "Gdk-4.0" → "gdk-4") - let majorVersion = version.split(separator: ".").first.map(String.init) ?? version - let linkName = "\(name.lowercased())-\(majorVersion)" - repository.includedLibraryLinks.append(linkName) - repository.includedPackages.append(IncludeEntry(name: name, version: version)) + // GIR dependency includes appear before the element. + // Derive the link name as lowercase(library) + "-" + major version, + // e.g. "Gdk-4.0" → "gdk-4". + if let name = attributeDict["name"], let version = attributeDict["version"] { + let majorVersion = version.split(separator: ".").first.map(String.init) ?? version + repository.includedLibraryLinks.append("\(name.lowercased())-\(majorVersion)") + repository.includedPackages.append(IncludeEntry(name: name, version: version)) + } + stack.append(.ignored(elementName)) case "namespace": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let version = requireAttribute("version", from: attributeDict, for: elementName, parser: parser) else { return } - let sharedLibrary = attributeDict["shared-library"] ?? "" - let cIdentifierPrefix = attributeDict["c:identifier-prefixes"] ?? "" - currentNamespace = Namespace(name: name, version: version, cSharedLibrary: sharedLibrary, cIdentifierPrefix: cIdentifierPrefix) + stack.append(.namespace(Namespace( + name: name, version: version, + cSharedLibrary: attributeDict["shared-library"] ?? "", + cIdentifierPrefix: attributeDict["c:identifier-prefixes"] ?? "" + ))) case "class": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - let parent = attributeDict["parent"] - let isAbstract = attributeDict["abstract"] == "1" - currentClass = Class(name: name, cType: cType, parent: parent, isAbstract: isAbstract) + stack.append(.klass(Class( + name: name, + cType: attributeDict["c:type"] ?? "", + parent: attributeDict["parent"], + isAbstract: attributeDict["abstract"] == "1", + isFinal: attributeDict["final"] == "1", + getTypeFunction: attributeDict["glib:get-type"], + typeName: attributeDict["glib:type-name"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "interface": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - let prereqs = attributeDict["prerequisite"]?.components(separatedBy: ",").map { $0.trimmingCharacters(in: .whitespaces) } ?? [] - currentInterface = Interface(name: name, cType: cType, prereqs: prereqs) + stack.append(.interface(Interface( + name: name, + cType: attributeDict["c:type"] ?? "", + getTypeFunction: attributeDict["glib:get-type"], + typeName: attributeDict["glib:type-name"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) + + case "prerequisite": + // GIR spells prerequisites as child elements, not an attribute. + if let name = attributeDict["name"] { + mutateTop { if case .interface(var iface) = $0 { iface.prereqs.append(name); $0 = .interface(iface) } } + } + stack.append(.ignored(elementName)) case "record": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - currentRecord = Record(name: name, cType: cType, isOpaque: attributeDict["opaque"] == "1", - isDisguised: attributeDict["disguised"] == "1") + stack.append(.record(Record( + name: name, + cType: attributeDict["c:type"] ?? "", + isOpaque: attributeDict["opaque"] == "1", + isDisguised: attributeDict["disguised"] == "1", + isGTypeStructFor: attributeDict["glib:is-gtype-struct-for"], + getTypeFunction: attributeDict["glib:get-type"], + typeName: attributeDict["glib:type-name"], + copyFunction: attributeDict["copy-function"], + freeFunction: attributeDict["free-function"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "enumeration": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - currentEnum = Enumeration(name: name, cType: cType) + stack.append(.enumeration(Enumeration( + name: name, + cType: attributeDict["c:type"] ?? "", + getTypeFunction: attributeDict["glib:get-type"], + typeName: attributeDict["glib:type-name"], + errorDomain: attributeDict["glib:error-domain"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "bitfield": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - currentBitfield = Bitfield(name: name, cType: cType) + stack.append(.bitfield(Bitfield( + name: name, + cType: attributeDict["c:type"] ?? "", + getTypeFunction: attributeDict["glib:get-type"], + typeName: attributeDict["glib:type-name"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "member": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let value = requireAttribute("value", from: attributeDict, for: elementName, parser: parser), let cid = requireAttribute("c:identifier", from: attributeDict, for: elementName, parser: parser) else { return } let member = EnumMember(name: name, value: value, cIdentifier: cid) - currentEnum?.members.append(member) - currentBitfield?.members.append(member) + mutateTop { + switch $0 { + case .enumeration(var e): e.members.append(member); $0 = .enumeration(e) + case .bitfield(var b): b.members.append(member); $0 = .bitfield(b) + default: break + } + } + stack.append(.ignored(elementName)) case "callback": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let cType = attributeDict["c:type"] ?? "" - currentCallback = Callback(name: name, cType: cType) + stack.append(.callback(Callback( + name: name, + cType: attributeDict["c:type"] ?? "", + throwsGError: attributeDict["throws"] == "1", + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "constructor": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let cid = requireAttribute("c:identifier", from: attributeDict, for: elementName, parser: parser) else { return } - currentConstructor = Constructor(name: name, cIdentifier: cid) + stack.append(.constructor(Constructor( + name: name, cIdentifier: cid, + throwsGError: attributeDict["throws"] == "1", + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "method": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let cid = requireAttribute("c:identifier", from: attributeDict, for: elementName, parser: parser) else { return } - currentMethod = Method(name: name, cIdentifier: cid) + stack.append(.method(Method( + name: name, cIdentifier: cid, + throwsGError: attributeDict["throws"] == "1", + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "function": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let cid = requireAttribute("c:identifier", from: attributeDict, for: elementName, parser: parser) else { return } - currentFunction = GlobalFunction(name: name, cIdentifier: cid) + stack.append(.function(GlobalFunction( + name: name, cIdentifier: cid, + throwsGError: attributeDict["throws"] == "1", + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) - case "signal": - guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - currentSignal = Signal(name: name, isDetailed: attributeDict["detailed"] == "1") - - case "glib:signal": - guard let name = attributeDict["name"] ?? attributeDict["glib:name"] else { return } - currentSignal = Signal(name: name, isDetailed: attributeDict["detailed"] == "1") + case "signal", "glib:signal": + guard let name = attributeDict["name"] ?? attributeDict["glib:name"] else { + parseError = .missingAttribute("Missing 'name' on <\(elementName)>") + parser.abortParsing() + return + } + stack.append(.signal(Signal( + name: name, + isDetailed: attributeDict["detailed"] == "1", + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) case "property": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - currentProperty = Property(name: name, type: .void, - isReadable: attributeDict["readable"] != "0", - isWritable: attributeDict["writable"] == "1", - isConstructOnly: attributeDict["construct-only"] == "1") + stack.append(.property(Property( + name: name, type: .void, + isReadable: attributeDict["readable"] != "0", + isWritable: attributeDict["writable"] == "1", + isConstructOnly: attributeDict["construct-only"] == "1", + isNullable: attributeDict["nullable"] == "1", + transferOwnership: TransferOwnership(rawValue: attributeDict["transfer-ownership"] ?? "none") ?? .none, + getter: attributeDict["getter"], + setter: attributeDict["setter"], + symbolInfo: Self.symbolInfo(from: attributeDict) + ))) + + case "parameters": + stack.append(.parameterList([])) case "parameter", "instance-parameter": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let transfer = TransferOwnership(rawValue: attributeDict["transfer-ownership"] ?? "none") ?? .none - let cType = attributeDict["c:type"] ?? "" - currentParameter = Parameter(name: name, type: .void, cType: cType, - isNullable: attributeDict["nullable"] == "1", - isOptional: attributeDict["optional"] == "1", - transferOwnership: transfer, - isInstanceParameter: elementName == "instance-parameter") + stack.append(.parameter(Parameter( + name: name, type: .void, + cType: attributeDict["c:type"] ?? "", + isNullable: attributeDict["nullable"] == "1", + isOptional: attributeDict["optional"] == "1", + transferOwnership: TransferOwnership(rawValue: attributeDict["transfer-ownership"] ?? "none") ?? .none, + isInstanceParameter: elementName == "instance-parameter", + direction: ParameterDirection(rawValue: attributeDict["direction"] ?? "in") ?? .in, + callerAllocates: attributeDict["caller-allocates"] == "1", + scope: attributeDict["scope"].flatMap(CallbackScope.init(rawValue:)), + closureIndex: attributeDict["closure"].flatMap(Int.init), + destroyIndex: attributeDict["destroy"].flatMap(Int.init) + ))) case "return-value": - currentReturnType = .void + stack.append(.returnValue(ReturnValue( + type: .void, + isNullable: attributeDict["nullable"] == "1", + transferOwnership: TransferOwnership(rawValue: attributeDict["transfer-ownership"] ?? "none") ?? .none + ))) 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 { - currentProperty?.type = resolvedType - } else if currentConstant != nil { - currentConstant?.type = resolvedType - } else if currentAlias != nil { - currentAlias?.target = resolvedType - } + stack.append(.type(TypeBuilder( + name: attributeDict["name"] ?? "none", + cType: attributeDict["c:type"] ?? "" + ))) case "array": - if let param = currentParameter { - currentParameter?.type = .array(param.type) - } + stack.append(.array(ArrayBuilder( + name: attributeDict["name"], + info: ArrayInfo( + lengthParameterIndex: attributeDict["length"].flatMap(Int.init), + fixedSize: attributeDict["fixed-size"].flatMap(Int.init), + isZeroTerminated: attributeDict["zero-terminated"] == "1", + cType: attributeDict["c:type"] ?? "" + ) + ))) case "constant": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let value = requireAttribute("value", from: attributeDict, for: elementName, parser: parser) else { return } - currentConstant = Constant(name: name, value: value, type: .void) + stack.append(.constant(Constant(name: name, value: value, type: .void))) case "alias": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser), let cType = requireAttribute("c:type", from: attributeDict, for: elementName, parser: parser) else { return } - currentAlias = Alias(name: name, cType: cType, target: .void) + stack.append(.alias(Alias(name: name, cType: cType, target: .void))) case "implements": if let name = attributeDict["name"] { - currentClass?.implements.append(name) + mutateTop { if case .klass(var cls) = $0 { cls.implements.append(name); $0 = .klass(cls) } } } - - case "doc-version", "doc-deprecated", "doc-stability", "source-position": - break - - case "doc": - currentText = "" - break + stack.append(.ignored(elementName)) case "field": guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } - let isReadable = attributeDict["readable"] != "0" - let isWritable = attributeDict["writable"] == "1" - currentRecord?.fields.append(Field(name: name, type: .void, isReadable: isReadable, isWritable: isWritable)) - - case "virtual-method", "parameters": - untrackedDepth += 1 - - default: - break - } - } - - /// Called when the XML parser encounters a closing element tag. - /// - /// Finalizes the current model object, resolves the return type if one was - /// collected, appends the object to its parent container, and clears the - /// corresponding `current*` property. - /// - Parameters: - /// - parser: The XML parser. - /// - elementName: The name of the XML element. - /// - namespaceURI: The namespace URI of the element. - /// - qualifiedName: The qualified name of the element. - func parser(_ parser: XMLParser, didEndElement elementName: String, - namespaceURI: String?, qualifiedName: String?) { - switch elementName { - case "namespace": - if let ns = currentNamespace { repository.namespaces.append(ns) } - currentNamespace = nil - - case "class": - if let cls = currentClass { currentNamespace?.classes.append(cls) } - currentClass = nil - - case "interface": - if let iface = currentInterface { currentNamespace?.interfaces.append(iface) } - currentInterface = nil - - case "record": - if let record = currentRecord { currentNamespace?.records.append(record) } - currentRecord = nil - - case "enumeration": - if let enm = currentEnum { currentNamespace?.enumerations.append(enm) } - currentEnum = nil - - case "bitfield": - if let bf = currentBitfield { currentNamespace?.bitfields.append(bf) } - currentBitfield = nil - - case "callback": - if let cb = currentCallback { - // Only add to namespace when at the top level (not inside a class/interface/record) - if currentClass == nil && currentInterface == nil && currentRecord == nil { - currentNamespace?.callbacks.append(cb) - } - } - currentCallback = nil - - case "constructor": - if var ctor = currentConstructor { - if let rt = currentReturnType, rt != .void { - ctor.returnType = rt - } - currentClass?.constructors.append(ctor) - } - currentConstructor = nil - currentReturnType = nil - - case "method": - if var method = currentMethod { - if let rt = currentReturnType, rt != .void { - method.returnType = rt - } - currentClass?.methods.append(method) - currentInterface?.methods.append(method) - currentRecord?.methods.append(method) - } - currentMethod = nil - currentReturnType = nil - - case "function": - if var fn = currentFunction { - if let rt = currentReturnType, rt != .void { - fn.returnType = rt - } - // Class/interface/record-level functions are not globals - if currentClass != nil { - currentClass?.functions.append(fn) - } else if currentRecord != nil { - currentRecord?.methods.append(Method(name: fn.name, cIdentifier: fn.cIdentifier, - parameters: fn.parameters, returnType: fn.returnType)) - } else if currentInterface != nil { - currentInterface?.functions.append(fn) - } else { - currentNamespace?.functions.append(fn) - } - } - currentFunction = nil - currentReturnType = nil - - case "signal", "glib:signal": - if var sig = currentSignal { - if let rt = currentReturnType, rt != .void { - sig.returnType = rt - } - currentClass?.signals.append(sig) - currentInterface?.signals.append(sig) - } - currentSignal = nil - currentReturnType = nil - - case "property": - if let prop = currentProperty { - currentClass?.properties.append(prop) - currentInterface?.properties.append(prop) - } - currentProperty = nil - - case "parameter", "instance-parameter": - if let param = currentParameter { - currentMethod?.parameters.append(param) - currentConstructor?.parameters.append(param) - currentSignal?.parameters.append(param) - currentFunction?.parameters.append(param) - currentCallback?.parameters.append(param) - } - currentParameter = nil - - case "return-value": - break - - case "constant": - if let c = currentConstant { currentNamespace?.constants.append(c) } - currentConstant = nil - - case "alias": - if let a = currentAlias { currentNamespace?.aliases.append(a) } - currentAlias = nil - - case "virtual-method", "parameters": - untrackedDepth -= 1 + stack.append(.field(Field( + name: name, type: .void, + isReadable: attributeDict["readable"] != "0", + isWritable: attributeDict["writable"] == "1" + ))) case "doc": - let text = currentText.trimmingCharacters(in: .whitespacesAndNewlines) - guard !text.isEmpty else { return } - // Skip doc inside untracked elements (virtual-method, field, etc.) - guard untrackedDepth == 0 else { return } - // Check innermost (most nested) elements first to handle hierarchy - // e.g. a signal inside a class → check currentSignal before currentClass - if currentParameter != nil { currentParameter?.doc = text } - else if currentMethod != nil { currentMethod?.doc = text } - else if currentConstructor != nil { currentConstructor?.doc = text } - else if currentSignal != nil { currentSignal?.doc = text } - else if currentProperty != nil { currentProperty?.doc = text } - else if currentCallback != nil { currentCallback?.doc = text } - else if currentFunction != nil { currentFunction?.doc = text } - else if currentInterface != nil { currentInterface?.doc = text } - else if currentEnum != nil { currentEnum?.doc = text } - else if currentBitfield != nil { currentBitfield?.doc = text } - else if currentRecord != nil { currentRecord?.doc = text } - else if currentClass != nil { currentClass?.doc = text } - else if currentConstant != nil { currentConstant?.doc = text } - else if currentAlias != nil { currentAlias?.doc = text } + currentText = "" + stack.append(.doc) default: + stack.append(.ignored(elementName)) + } + } + + // MARK: Element end + + func parser(_ parser: XMLParser, didEndElement elementName: String, + namespaceURI: String?, qualifiedName: String?) { + guard let frame = stack.popLast() else { return } + + switch frame { + case .namespace(let ns): + repository.namespaces.append(ns) + + case .klass(let cls): + mutateTop { if case .namespace(var ns) = $0 { ns.classes.append(cls); $0 = .namespace(ns) } } + + case .interface(let iface): + mutateTop { if case .namespace(var ns) = $0 { ns.interfaces.append(iface); $0 = .namespace(ns) } } + + case .record(let record): + mutateTop { if case .namespace(var ns) = $0 { ns.records.append(record); $0 = .namespace(ns) } } + + case .enumeration(let e): + mutateTop { if case .namespace(var ns) = $0 { ns.enumerations.append(e); $0 = .namespace(ns) } } + + case .bitfield(let b): + mutateTop { if case .namespace(var ns) = $0 { ns.bitfields.append(b); $0 = .namespace(ns) } } + + case .callback(let cb): + // Namespace-level callbacks are bindable types in their own right. + // A callback nested in a is a function-pointer member of a + // C struct (vtables such as GIOFuncs): at the ABI level that field + // is exactly an opaque pointer, which is what it is recorded as. + // Callbacks nested anywhere else describe a signature in place and + // are not separate declarations. + mutateTop { + switch $0 { + case .namespace(var ns): ns.callbacks.append(cb); $0 = .namespace(ns) + case .field(var f): + f = Field(name: f.name, type: .pointer, isReadable: f.isReadable, + isWritable: f.isWritable, doc: f.doc) + $0 = .field(f) + default: break + } + } + + case .constructor(let ctor): + mutateTop { + switch $0 { + case .klass(var cls): cls.constructors.append(ctor); $0 = .klass(cls) + case .record(var rec): rec.constructors.append(ctor); $0 = .record(rec) + default: break + } + } + + case .method(let method): + mutateTop { + switch $0 { + case .klass(var cls): cls.methods.append(method); $0 = .klass(cls) + case .interface(var iface): iface.methods.append(method); $0 = .interface(iface) + case .record(var rec): rec.methods.append(method); $0 = .record(rec) + default: break + } + } + + case .function(let fn): + mutateTop { + switch $0 { + case .klass(var cls): cls.functions.append(fn); $0 = .klass(cls) + case .interface(var iface): iface.functions.append(fn); $0 = .interface(iface) + case .record(var rec): rec.functions.append(fn); $0 = .record(rec) + case .namespace(var ns): ns.functions.append(fn); $0 = .namespace(ns) + default: break + } + } + + case .signal(let sig): + mutateTop { + switch $0 { + case .klass(var cls): cls.signals.append(sig); $0 = .klass(cls) + case .interface(var iface): iface.signals.append(sig); $0 = .interface(iface) + default: break + } + } + + case .property(let prop): + mutateTop { + switch $0 { + case .klass(var cls): cls.properties.append(prop); $0 = .klass(cls) + case .interface(var iface): iface.properties.append(prop); $0 = .interface(iface) + default: break + } + } + + case .parameterList(let params): + mutateTop { + switch $0 { + case .method(var m): m.parameters = params; $0 = .method(m) + case .constructor(var c): c.parameters = params; $0 = .constructor(c) + case .function(var f): f.parameters = params; $0 = .function(f) + case .signal(var s): s.parameters = params; $0 = .signal(s) + case .callback(var cb): cb.parameters = params; $0 = .callback(cb) + default: break + } + } + + case .parameter(let param): + mutateTop { if case .parameterList(var list) = $0 { list.append(param); $0 = .parameterList(list) } } + + case .returnValue(let rv): + mutateTop { + switch $0 { + case .method(var m): m.returnValue = rv; $0 = .method(m) + case .constructor(var c): c.returnValue = rv; $0 = .constructor(c) + case .function(var f): f.returnValue = rv; $0 = .function(f) + case .signal(var s): s.returnValue = rv; $0 = .signal(s) + case .callback(var cb): cb.returnValue = rv; $0 = .callback(cb) + default: break + } + } + + case .field(let field): + mutateTop { if case .record(var rec) = $0 { rec.fields.append(field); $0 = .record(rec) } } + + case .constant(let c): + mutateTop { if case .namespace(var ns) = $0 { ns.constants.append(c); $0 = .namespace(ns) } } + + case .alias(let a): + mutateTop { if case .namespace(var ns) = $0 { ns.aliases.append(a); $0 = .namespace(ns) } } + + case .type(let builder): + assignType(Self.buildType(from: builder), cType: builder.cType) + + case .array(let builder): + let element = builder.children.first ?? .pointer + if let name = builder.name, let kind = Self.containerKind(forTypeName: name) { + assignType(.container(kind, elements: builder.children), cType: builder.info.cType) + } else { + assignType(.cArray(element, builder.info), cType: builder.info.cType) + } + + case .doc: + assignDoc(currentText.trimmingCharacters(in: .whitespacesAndNewlines)) + currentText = "" + + case .ignored: break } } - /// Called when the XML parser encounters character data between elements. - /// - /// Accumulates text content for the current element, used primarily for - /// capturing `` element text content. - /// - Parameters: - /// - parser: The XML parser. - /// - string: The character data found. func parser(_ parser: XMLParser, foundCharacters string: String) { currentText += string } - // MARK: - Helpers + // MARK: - Attachment helpers - /// Requires that an attribute exists in the given dictionary, or aborts parsing. + /// Mutates the innermost open frame in place. + /// + /// - Parameter body: A closure receiving the top frame for mutation. Not + /// called when the stack is empty. + private func mutateTop(_ body: (inout Frame) -> Void) { + guard !stack.isEmpty else { return } + body(&stack[stack.count - 1]) + } + + /// Assigns a resolved type to whichever construct encloses it. + /// + /// Handles every element that has a `` or `` child: parameters, + /// return values, properties, constants, aliases, record fields, and nested + /// container/array element types. + /// + /// - Parameters: + /// - type: The resolved GIR type. + /// - cType: The `c:type` spelling, applied to parameters when non-empty. + private func assignType(_ type: GIRType, cType: String) { + mutateTop { + switch $0 { + case .parameter(var p): + p.type = type + if !cType.isEmpty { p.cType = cType } + $0 = .parameter(p) + case .returnValue(var rv): + rv.type = type + $0 = .returnValue(rv) + case .property(var prop): + prop.type = type + $0 = .property(prop) + case .constant(var c): + c.type = type + $0 = .constant(c) + case .alias(var a): + a.target = type + $0 = .alias(a) + case .field(var f): + // Field is immutable in the IR, so rebuild it with the type + // that only becomes known when the child closes. + f = Field(name: f.name, type: type, isReadable: f.isReadable, + isWritable: f.isWritable, doc: f.doc) + $0 = .field(f) + case .type(var builder): + builder.children.append(type) + $0 = .type(builder) + case .array(var builder): + builder.children.append(type) + $0 = .array(builder) + default: + break + } + } + } + + /// Attaches documentation text to whichever construct encloses the ``. + /// + /// - Parameter text: The trimmed documentation text; ignored when empty. + private func assignDoc(_ text: String) { + guard !text.isEmpty else { return } + mutateTop { + switch $0 { + case .klass(var x): x.doc = text; $0 = .klass(x) + case .interface(var x): x.doc = text; $0 = .interface(x) + case .record(var x): x.doc = text; $0 = .record(x) + case .enumeration(var x): x.doc = text; $0 = .enumeration(x) + case .bitfield(var x): x.doc = text; $0 = .bitfield(x) + case .callback(var x): x.doc = text; $0 = .callback(x) + case .constructor(var x): x.doc = text; $0 = .constructor(x) + case .method(var x): x.doc = text; $0 = .method(x) + case .function(var x): x.doc = text; $0 = .function(x) + case .signal(var x): x.doc = text; $0 = .signal(x) + case .property(var x): x.doc = text; $0 = .property(x) + case .parameter(var x): x.doc = text; $0 = .parameter(x) + case .returnValue(var x): x.doc = text; $0 = .returnValue(x) + case .constant(var x): x.doc = text; $0 = .constant(x) + case .alias(var x): x.doc = text; $0 = .alias(x) + case .field(var x): + x = Field(name: x.name, type: x.type, isReadable: x.isReadable, + isWritable: x.isWritable, doc: text) + $0 = .field(x) + default: break + } + } + } + + /// Requires that an attribute exists, or aborts parsing with an error. /// - Parameters: /// - key: The attribute name to look up. /// - dict: The attribute dictionary from the current XML element. @@ -466,14 +662,64 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate { return value } - /// Maps a GIR type name string to the corresponding `GIRType` enum case. + // MARK: - Type mapping + + /// Extracts the binding-relevant GIR metadata common to all symbols. + /// + /// - Parameter dict: The element's attribute dictionary. + /// - Returns: The parsed ``SymbolInfo``. + static func symbolInfo(from dict: [String: String]) -> SymbolInfo { + SymbolInfo( + isIntrospectable: dict["introspectable"] != "0", + isDeprecated: dict["deprecated"] == "1", + deprecatedVersion: dict["deprecated-version"], + shadowedBy: dict["shadowed-by"], + shadows: dict["shadows"], + movedTo: dict["moved-to"] + ) + } + + /// Builds a `GIRType` from a completed `` element. + /// + /// Container type names (`GLib.List`, `GLib.HashTable`, …) become + /// ``GIRType/container(_:elements:)`` carrying their nested element types; + /// everything else maps through ``girType(forName:)``. + /// + /// - Parameter builder: The accumulated `` element state. + /// - Returns: The resolved GIR type. + static func buildType(from builder: TypeBuilder) -> GIRType { + if let kind = containerKind(forTypeName: builder.name) { + return .container(kind, elements: builder.children) + } + return girType(forName: builder.name) + } + + /// Maps a GIR container type name to its ``ContainerKind``. + /// + /// - Parameter name: A GIR type name, e.g. `"GLib.List"`. + /// - Returns: The container kind, or `nil` if the name is not a container. + static func containerKind(forTypeName name: String) -> ContainerKind? { + switch name { + case "GLib.List": return .list + case "GLib.SList": return .slist + case "GLib.HashTable": return .hashTable + case "GLib.Array": return .array + case "GLib.PtrArray": return .ptrArray + case "GLib.ByteArray": return .byteArray + default: return nil + } + } + + /// Maps a GIR type name string to the corresponding `GIRType` case. + /// + /// Recognizes the full set of GLib primitive names and dotted + /// namespace-qualified references (e.g. `Gtk.Widget`). Unknown names become + /// an unqualified `.typeRef`, which the ``TypeRegistry`` later resolves — + /// or reports as unresolvable, rather than fabricating a Swift type. /// - /// Recognizes primitive GLib types (`gboolean`, `gint32`, `utf8`, etc.) and - /// dotted namespace-qualified type references (e.g. `Gtk.Widget`). Unknown - /// names are returned as an unqualified `.typeRef`. /// - Parameter name: The GIR type name (e.g. `"gint32"`, `"utf8"`, `"Gtk.Widget"`). /// - Returns: The corresponding `GIRType` value. - private func parseGIRType(_ name: String) -> GIRType { + static func girType(forName name: String) -> GIRType { switch name { case "none": return .void case "gboolean": return .boolean @@ -485,11 +731,20 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate { case "guint16": return .uint16 case "guint", "guint32": return .uint32 case "guint64": return .uint64 + case "glong", "gintptr", "time_t": return .long + case "gulong", "guintptr": return .ulong + case "gsize": return .size + case "gssize", "goffset": return .ssize + case "gchar", "gshort": return .char + case "guchar", "gushort": return .uchar + case "gunichar", "gunichar2": return .unichar + case "GType": return .gtype case "gfloat": return .float case "gdouble": return .double case "utf8": return .string case "filename": return .filename case "gpointer", "gconstpointer": return .pointer + case "va_list": return .vaList default: if let dotIndex = name.firstIndex(of: ".") { let ns = String(name[.. CLIArgs { - /// Safely pops the next argument, returning nil if none remain. - func nextArg(_ args: inout [String], for flag: String) -> String? { - guard !args.isEmpty else { return nil } - return args.removeFirst() - } var args = Array(CommandLine.arguments.dropFirst()) var cli = CLIArgs() while let flag = args.first { args.removeFirst() switch flag { - case "--emit-single-file": - cli.emitSingleFile = true - case "--list-output-files": - cli.listOutputFiles = true case "--help", "-h": cli.showHelp = true - case "--gir-file": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.girFile = val - case "--output": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.output = val - case "--config-toml": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.configTOML = val - case "--namespace": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.namespaceOverride = val - case "--girs-dirs": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.girsDirs = val.components(separatedBy: ",") - case "--external-libs": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.externalLibs = val.components(separatedBy: ",") - case "--generate-all": - cli.generateAll = true - case "--generate": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.generate = val.components(separatedBy: ",") - case "--manual": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.manual = val.components(separatedBy: ",") - case "--ignore": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.ignore = val.components(separatedBy: ",") case "--monorepo-config": - guard let val = nextArg(&args, for: flag) else { return CLIArgs(showHelp: true, girFile: "") } - cli.monorepoConfigTOML = val + cli.monorepoConfigTOML = args.isEmpty ? "" : args.removeFirst() + case "--output": + cli.output = args.isEmpty ? "." : args.removeFirst() + case "--skip-report": + cli.emitSkipReport = true default: break } @@ -248,100 +132,12 @@ struct SwiftGtkGenCLI { return cli } - /// Lists the expected output file paths to stdout, one per line, - /// applying the same config filtering as the main generation pipeline. - /// Used by build tool plugins to declare outputs that match what Phase 2 - /// will actually produce. - static func listAndPrintOutputFiles(repository: Repository, config: GenerationConfig) throws { - let analyzer = Analyzer(config: config) - let analysis = analyzer.analyze(repository: repository) - let shouldGenerateAll = analysis.generatedTypes.isEmpty - let sourcesPrefix = "Sources/\(config.library)/" - - for ns in repository.namespaces where ns.name == config.library { - for cls in ns.classes { - let fullName = "\(ns.name).\(cls.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - if analysis.manualTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(cls.name).swift") - } - for iface in ns.interfaces { - let fullName = "\(ns.name).\(iface.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - if analysis.manualTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(iface.name).swift") - } - for enm in ns.enumerations { - let fullName = "\(ns.name).\(enm.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(enm.name).swift") - } - for bf in ns.bitfields { - let fullName = "\(ns.name).\(bf.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(bf.name).swift") - } - for cb in ns.callbacks { - let fullName = "\(ns.name).\(cb.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(cb.name).swift") - } - for fn in ns.functions { - let fullName = "\(ns.name).\(fn.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(pascalCaseName(fn.name)).swift") - } - for rec in ns.records { - let fullName = "\(ns.name).\(rec.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - if analysis.manualTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(rec.name).swift") - } - for cst in ns.constants { - let fullName = "\(ns.name).\(cst.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(cst.name).swift") - } - for alias in ns.aliases { - let fullName = "\(ns.name).\(alias.name)" - if !shouldGenerateAll && !analysis.generatedTypes.contains(fullName) { continue } - if analysis.ignoredTypes.contains(fullName) { continue } - print("\(sourcesPrefix)\(alias.name).swift") - } - } - let cName = "C\(config.library)" - print("Sources/\(cName)/module.modulemap") - print("Sources/\(cName)/\(cName).h") - } - - private static func pascalCaseName(_ name: String) -> String { - name.split { $0 == "_" || $0 == "-" }.map { $0.capitalized }.joined() - } - - /// Prints usage information and the list of accepted flags to stdout. + /// Prints usage information to stdout. static func printHelp() { - print("Usage: swift-gtk-gen --gir-file PATH [options]") - print(" --gir-file PATH Path to the .gir file (required)") - print(" --output DIR Output directory (default: .)") - print(" --config-toml PATH Path to config.toml (default: config.toml)") - print(" --namespace NAME Namespace to use (for multi-namespace GIR files)") - print(" --list-output-files Print expected output file paths and exit") - print(" --girs-dirs DIRS Comma-separated GIR directories") - print(" --external-libs LIBS Comma-separated external libraries") - print(" --generate TYPES Comma-separated types to generate") - print(" --generate-all Generate all types in the namespace (default)") - print(" --manual TYPES Comma-separated types to mark manual") - print(" --ignore TYPES Comma-separated types to ignore") - print(" --emit-single-file Emit a single file instead of per-type files") - print(" --monorepo-config PATH Generate a monorepo using this TOML config") - print(" --help, -h Show this help") + print("Usage: swift-gtk-gen --monorepo-config PATH [options]") + print(" --monorepo-config PATH Monorepo TOML config (required)") + print(" --output DIR Output directory (default: .)") + print(" --skip-report Write skip-reports/.json and coverage-summary.json") + print(" --help, -h Show this help") } } diff --git a/Tests/IntegrationTests/CLIGenerationLintTests.swift b/Tests/IntegrationTests/CLIGenerationLintTests.swift deleted file mode 100644 index 47ac3d8..0000000 --- a/Tests/IntegrationTests/CLIGenerationLintTests.swift +++ /dev/null @@ -1,92 +0,0 @@ -import Testing -import Foundation - -/// End-to-end test: invoke the real `swift-gtk-gen` binary, generate Gtk -/// wrappers into a temp directory, and verify the output passes swift-format -/// lint with `--strict`. Does not require GTK headers — only checks formatting. -@Suite("CLI generation + lint") -struct CLIGenerationLintTests { - - /// Path to the built `swift-gtk-gen` binary. - var binaryURL: URL { - let candidates = [ - URL(fileURLWithPath: ".build/x86_64-unknown-linux-gnu/debug/swift-gtk-gen"), - URL(fileURLWithPath: ".build/debug/swift-gtk-gen"), - ] - return candidates.first { FileManager.default.fileExists(atPath: $0.path) } - ?? URL(fileURLWithPath: "/nonexistent") - } - - @Test("CLI generates clean Swift wrappers for a subset of Gtk types") - func testCLIGenerateAndLint() throws { - let bin = binaryURL - guard FileManager.default.fileExists(atPath: bin.path) else { - Issue.record("swift-gtk-gen binary not found at \(bin.path)") - return - } - - let suffix = UUID().uuidString.prefix(8) - let outputDir = URL(fileURLWithPath: "/tmp/swift-gtk-gen-cli-test-\(suffix)") - defer { try? FileManager.default.removeItem(at: outputDir) } - - let girFile = "/usr/share/gir-1.0/Gtk-4.0.gir" - guard FileManager.default.fileExists(atPath: girFile) else { - Issue.record("Gtk-4.0.gir not found at \(girFile)") - return - } - - // Phase 1: Generate the wrapper package - let genProcess = Process() - genProcess.executableURL = bin - genProcess.arguments = [ - "--gir-file", girFile, - "--output", outputDir.path, - "--generate", "Gtk.Widget,Gtk.Window,Gtk.Button,Gtk.Label,Gtk.Box", - ] - let genPipe = Pipe() - genProcess.standardOutput = genPipe - genProcess.standardError = genPipe - try genProcess.run() - genProcess.waitUntilExit() - - guard genProcess.terminationStatus == 0 else { - let output = String(data: genPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? "" - Issue.record("Generation failed with output:\n\(output)") - return - } - - // Verify key files exist - let sourcesDir = outputDir.appendingPathComponent("Sources/Gtk") - #expect(FileManager.default.fileExists(atPath: sourcesDir.appendingPathComponent("Widget.swift").path)) - #expect(FileManager.default.fileExists(atPath: sourcesDir.appendingPathComponent("Window.swift").path)) - #expect(FileManager.default.fileExists(atPath: sourcesDir.appendingPathComponent("Button.swift").path)) - #expect(FileManager.default.fileExists(atPath: outputDir.appendingPathComponent("Package.swift").path)) - - // Phase 2: Lint the generated output with --strict - let lintLog = URL(fileURLWithPath: "/tmp/swift-gtk-gen-lint-\(suffix).log") - let lintProcess = Process() - lintProcess.executableURL = URL(fileURLWithPath: "/usr/bin/swift") - lintProcess.arguments = [ - "format", "lint", - "--configuration", ".swift-format", - "--recursive", - "--strict", - outputDir.path, - ] - let lintPipe = Pipe() - lintProcess.standardOutput = lintPipe - lintProcess.standardError = lintPipe - DispatchQueue.global().async { - let data = lintPipe.fileHandleForReading.readDataToEndOfFile() - try? data.write(to: lintLog) - } - try lintProcess.run() - lintProcess.waitUntilExit() - - let lintOutput = (try? String(contentsOf: lintLog, encoding: .utf8)) ?? "" - if lintProcess.terminationStatus != 0 { - Issue.record("Lint failed with exit \(lintProcess.terminationStatus):\n\(lintOutput)") - } - #expect(lintProcess.terminationStatus == 0, "Generated code must pass swift format lint --strict") - } -} diff --git a/Tests/IntegrationTests/CompileGateTests.swift b/Tests/IntegrationTests/CompileGateTests.swift new file mode 100644 index 0000000..e97d1bc --- /dev/null +++ b/Tests/IntegrationTests/CompileGateTests.swift @@ -0,0 +1,43 @@ +// CompileGateTests.swift +// Wraps scripts/compile-gate.sh as a test so CI can run the compile gate via +// `swift test`. Gated behind SWIFT_GTK_GEN_COMPILE_GATE=1 so the default +// `swift test` run stays fast and does not require system GIR files. + +import Foundation +import Testing + +/// Integration test that runs the compile gate: generate a tier's monorepo +/// and require the generated package to build with zero errors. +/// +/// Enable with `SWIFT_GTK_GEN_COMPILE_GATE=1 swift test`; select a tier with +/// `SWIFT_GTK_GEN_GATE_TIER` (defaults to `"1"`, accepts `"all"`). +@Suite struct CompileGateTests { + /// Whether the gate is enabled for this test run. + private nonisolated static var gateEnabled: Bool { + ProcessInfo.processInfo.environment["SWIFT_GTK_GEN_COMPILE_GATE"] == "1" + } + + /// The tier argument passed to the gate script. + private nonisolated static var tier: String { + ProcessInfo.processInfo.environment["SWIFT_GTK_GEN_GATE_TIER"] ?? "1" + } + + @Test(.enabled(if: gateEnabled, "set SWIFT_GTK_GEN_COMPILE_GATE=1 to run the compile gate")) + func generatedPackageCompiles() throws { + // #filePath = .../Tests/IntegrationTests/CompileGateTests.swift + let packageRoot = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() // IntegrationTests + .deletingLastPathComponent() // Tests + .deletingLastPathComponent() // package root + let script = packageRoot.appendingPathComponent("scripts/compile-gate.sh") + + let process = Process() + process.executableURL = script + process.arguments = [Self.tier] + process.currentDirectoryURL = packageRoot + try process.run() + process.waitUntilExit() + + #expect(process.terminationStatus == 0, "compile gate failed for tier \(Self.tier)") + } +} diff --git a/Tests/IntegrationTests/GIRSpecAccuracyTests.swift b/Tests/IntegrationTests/GIRSpecAccuracyTests.swift deleted file mode 100644 index e2fae9a..0000000 --- a/Tests/IntegrationTests/GIRSpecAccuracyTests.swift +++ /dev/null @@ -1,311 +0,0 @@ -import Foundation -import Testing -@testable import SwiftGtkGenCore - -/// Systematically validates that every type, method, property, signal, and -/// constant in the generator's output matches the corresponding element in -/// the input `Gtk-4.0.gir`. Catches omissions, misnamed symbols, wrong -/// superclasses, missing methods, and incorrect parameter names. -/// -/// The assertions are deliberate substring checks — they verify the generator -/// emits a corresponding declaration for each GIR element, but do not deeply -/// verify parameter types, return types, etc. Construct-only properties and -/// abstract class restrictions are reported as "expected" failures and signal -/// areas for future work. -@Suite("GIR spec accuracy") -struct GIRSpecAccuracyTests { - - private static let girURL = URL(fileURLWithPath: "/usr/share/gir-1.0/Gtk-4.0.gir") - - private struct GeneratedGtk { - let repo: Repository - let output: String - let files: [String: String] - let gtk: Namespace - } - - private static func setup() throws -> GeneratedGtk { - try requireGtkGir() - let parser = GIRParser() - let repo = try parser.parse(fileURL: girURL) - let config = GenerationConfig( - library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [] - ) - let analysis = Analyzer(config: config).analyze(repository: repo) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: analysis) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - guard let gtk = repo.namespaces.first(where: { $0.name == "Gtk" }) else { - throw IntegrationTestEnvironmentError.missingNamespace("Gtk") - } - return GeneratedGtk(repo: repo, output: output, files: files, gtk: gtk) - } - - @Test("Every Gtk class appears in generated output") - func testEveryClassGenerated() throws { - let g = try Self.setup() - - var missing: [String] = [] - for cls in g.gtk.classes { - let inOwnFile = Self.containsClassDeclaration(in: g.files["\(cls.name).swift"] ?? "", name: cls.name) - let inAggregate = Self.containsClassDeclaration(in: g.output, name: cls.name) - if !inOwnFile && !inAggregate { - missing.append(cls.name) - } - } - #expect(missing.isEmpty, "Missing classes in generated output: \(missing.prefix(10))…") - } - - @Test("Class parent is encoded in the generated declaration") - func testClassParentMatchesGIR() throws { - let g = try Self.setup() - - var wrongParent: [String] = [] - for cls in g.gtk.classes { - guard let parent = cls.parent else { continue } - // Skip cross-namespace parents — those become typealiases, not inheritance. - if parent.contains(".") { continue } - - let classFile = g.files["\(cls.name).swift"] ?? "" - // Generator emits "class Name: Parent {" (no space before colon). - let inOwnFile = Self.containsParentReference( - in: classFile, child: cls.name, parent: parent) - let inAggregate = Self.containsParentReference( - in: g.output, child: cls.name, parent: parent) - if !inOwnFile && !inAggregate { - wrongParent.append("\(cls.name) → expected `\(parent)`") - } - } - #expect(wrongParent.isEmpty, "Classes with missing/wrong parents: \(wrongParent.prefix(10))…") - } - - /// Returns `true` if `source` contains a class declaration for `name`. - /// The generator emits `class : {` (no space before the - /// colon when there's a parent) or `class {` (space before `{` - /// when there's no parent). Either form counts as a match. - private static func containsClassDeclaration(in source: String, name: String) -> Bool { - let escaped = NSRegularExpression.escapedPattern(for: name) - let pattern = #"\b(class|public final class|open class)\s+"# + escaped + #"(\W|$)"# - guard let regex = try? NSRegularExpression(pattern: pattern) else { return false } - let range = NSRange(source.startIndex..: {` so the - /// name is followed by a non-word character (typically `:` or `{`). - private static func containsRecordDeclaration(in source: String, name: String) -> Bool { - let escaped = NSRegularExpression.escapedPattern(for: name) - let pattern = #"\bstruct\s+"# + escaped + #"(\W|$)"# - guard let regex = try? NSRegularExpression(pattern: pattern) else { return false } - let range = NSRange(source.startIndex.. Bool { - let escapedChild = NSRegularExpression.escapedPattern(for: child) - let escapedParent = NSRegularExpression.escapedPattern(for: parent) - let pattern = #"\bclass\s+"# + escapedChild + #"\s*:\s*"# + escapedParent + #"\s*\{"# - guard let regex = try? NSRegularExpression(pattern: pattern) else { return false } - let range = NSRange(source.startIndex.. String { - name.split { $0 == "_" || $0 == "-" }.enumerated().map { i, part in - i == 0 ? String(part).lowercased() : String(part).capitalized - }.joined() - } - - /// Mirrors `CodeGenerator.swiftifyMethodName` — same as property naming, - /// plus backtick-escape for reserved Swift keywords. - private static func swiftifyMethodName(_ name: String) -> String { - let swiftName = swiftifyPropertyName(name) - return Self.reservedKeywords.contains(swiftName) ? "`\(swiftName)`" : swiftName - } - - /// Mirrors `CodeGenerator.swiftifySignalName` — splits on `-` and - /// capitalizes each component (PascalCase). - private static func swiftifySignalName(_ name: String) -> String { - name.split(separator: "-").map { $0.capitalized }.joined() - } - - /// Mirrors `CodeGenerator.pascalCaseName` — used for constants/aliases. - private static func pascalCaseName(_ name: String) -> String { - name.split { $0 == "_" || $0 == "-" }.map { $0.capitalized }.joined() - } - - private static let reservedKeywords: Set = [ - "self", "type", "class", "default", "in", "for", "repeat", "while", - "switch", "case", "break", "continue", "return", "if", "else", - "guard", "defer", "do", "try", "throw", "catch", "import", "let", - "var", "func", "static", "struct", "enum", "protocol", "extension", - "init", "deinit", "subscript", "where", "operator", "Protocol", - "rethrows", "associatedtype", "precedencegroup", - "true", "false", "nil", "Self", "Type", - "private", "fileprivate", "internal", "public", "open", - "is", "as", "async", "await", "nonisolated", "throws", - ] -} diff --git a/Tests/IntegrationTests/GtkGenerationTests.swift b/Tests/IntegrationTests/GtkGenerationTests.swift deleted file mode 100644 index 49fa332..0000000 --- a/Tests/IntegrationTests/GtkGenerationTests.swift +++ /dev/null @@ -1,182 +0,0 @@ -import Testing -import Foundation -@testable import SwiftGtkGenCore - -@Test("Full pipeline: generate complete Gtk 4.0 wrapper package") -func testFullGtkGeneration() throws { - let girURL = URL(fileURLWithPath: "/usr/share/gir-1.0/Gtk-4.0.gir") - guard FileManager.default.fileExists(atPath: girURL.path) else { - throw IntegrationTestEnvironmentError.missingGIRFile("Gtk-4.0.gir not found") - } - - let parser = GIRParser() - let repo = try parser.parse(fileURL: girURL) - guard let gtk = repo.namespaces.first(where: { $0.name == "Gtk" }) else { - throw IntegrationTestEnvironmentError.missingNamespace("Gtk") - } - - let config = GenerationConfig( - library: "Gtk", version: "4.0", - girsDirectories: ["/usr/share/gir-1.0"], - targetDirectory: "", - externalLibraries: ["Gdk-4.0", "Gsk-4.0"], - generate: ["Gtk.Widget", "Gtk.Window", "Gtk.Button", "Gtk.Label", - "Gtk.Box", "Gtk.Align", "Gtk.Application"], - manual: [], - ignore: [], - objects: [] - ) - let analysis = Analyzer(config: config).analyze(repository: repo) - - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - // Verify per-file generation - #expect(files.keys.contains("Widget.swift")) - #expect(files.keys.contains("Window.swift")) - #expect(files.keys.contains("Button.swift")) - #expect(files.keys.contains("Label.swift")) - #expect(files.keys.contains("Box.swift")) - #expect(files.keys.contains("Align.swift")) - #expect(files.keys.contains("Application.swift")) - - // Verify no fatalError() stubs remain in any file - for (name, content) in files { - #expect(!content.contains("fatalError"), "File \(name) still contains fatalError stub") - } - - // Verify real C function calls - #expect(files["Widget.swift"]?.contains("gtk_widget_show(pointer.assumingMemoryBound(to: GtkWidget.self)") == true) - #expect(files["Widget.swift"]?.contains("gtk_widget_get_visible(pointer.assumingMemoryBound(to: GtkWidget.self)") == true) - - // Verify real property accessors via GValue - #expect(files["Widget.swift"]?.contains("g_value_init") == true) - #expect(files["Widget.swift"]?.contains("g_object_get_property") == true) - #expect(files["Widget.swift"]?.contains("g_object_set_property") == true) - - // Verify real signal connections - #expect(files["Widget.swift"]?.contains("g_signal_connect_data") == true) - #expect(files["Widget.swift"]?.contains("Unmanaged.passRetained") == true) - - // Verify constructors - #expect(files["Button.swift"]?.contains("convenience init") == true) - #expect(files["Button.swift"]?.contains("gtk_button_new") == true) - // Subclass inherits pointer/init/deinit from parent - #expect(files["Widget.swift"]?.contains("g_object_ref_sink") == true) - #expect(files["Button.swift"]?.contains("g_object_ref_sink") == false) - - // Verify scaffolding - let scaffolding = CodeGenerator.generatePackageScaffolding(config: config, repository: repo) - #expect(scaffolding.keys.contains("Package.swift")) - #expect(scaffolding.keys.contains("Sources/CGtk/module.modulemap")) - #expect(scaffolding.keys.contains("Sources/CGtk/CGtk.h")) -} - -@Test("Full pipeline: parse GLib-2.0.gir and verify analysis") -func testFullGLibParsing() throws { - let girURL = URL(fileURLWithPath: "/usr/share/gir-1.0/GLib-2.0.gir") - guard FileManager.default.fileExists(atPath: girURL.path) else { - throw IntegrationTestEnvironmentError.missingGIRFile("GLib-2.0.gir not found") - } - - let parser = GIRParser() - let repo = try parser.parse(fileURL: girURL) - #expect(!repo.namespaces.isEmpty) - guard let glib = repo.namespaces.first(where: { $0.name == "GLib" }) else { - throw IntegrationTestEnvironmentError.missingNamespace("GLib") - } - - // Verify parsing of records, functions, enumerations - #expect(!glib.records.isEmpty, "Expected records in GLib namespace") - #expect(!glib.functions.isEmpty, "Expected functions in GLib namespace") - #expect(!glib.enumerations.isEmpty, "Expected enumerations in GLib namespace") - - // Check specific well-known records exist - let recordNames = glib.records.map { $0.name } - #expect(recordNames.contains("String")) - #expect(recordNames.contains("List")) - #expect(recordNames.contains("MainLoop")) - - // Verify analysis works for GLib types - let config = GenerationConfig( - library: "GLib", version: "2.0", - girsDirectories: [girURL.deletingLastPathComponent().path], - targetDirectory: "", - externalLibraries: [], - generate: ["GLib.String", "GLib.List", "GLib.MainLoop"], - manual: [], - ignore: [], - objects: [] - ) - - let analyzer = Analyzer(config: config) - let analysis = analyzer.analyze(repository: repo) - - #expect(analysis.generatedTypes.contains("GLib.String")) - #expect(analysis.generatedTypes.contains("GLib.List")) - #expect(analysis.generatedTypes.contains("GLib.MainLoop")) - - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - #expect(files.keys.contains("String.swift")) - #expect(files.keys.contains("List.swift")) - #expect(files.keys.contains("MainLoop.swift")) -} - -@Test("Full pipeline: generate ALL Gtk types when generate list is empty") -func testGenerateAllGtkTypes() throws { - let girURL = URL(fileURLWithPath: "/usr/share/gir-1.0/Gtk-4.0.gir") - guard FileManager.default.fileExists(atPath: girURL.path) else { - throw IntegrationTestEnvironmentError.missingGIRFile("Gtk-4.0.gir not found") - } - let parser = GIRParser() - let repo = try parser.parse(fileURL: girURL) - guard let gtk = repo.namespaces.first(where: { $0.name == "Gtk" }) else { - throw IntegrationTestEnvironmentError.missingNamespace("Gtk") - } - - // Empty generate list = generate ALL - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: []) - let analysis = Analyzer(config: config).analyze(repository: repo) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - // Get expected counts from parsed GIR data - let expectedClasses = gtk.classes.count - let expectedInterfaces = gtk.interfaces.count - let expectedEnums = gtk.enumerations.count - let expectedBitfields = gtk.bitfields.count - - // Count generated files by type - let generatedClasses = files.values.filter { $0.contains("public final class") || $0.contains("open class") }.count - let generatedInterfaces = files.values.filter { $0.contains("public protocol") }.count - let generatedEnums = files.values.filter { $0.contains("public enum") && !$0.contains("OptionSet") }.count - let generatedBitfields = files.values.filter { $0.contains("OptionSet") }.count - let generatedCallbacks = files.values.filter { $0.contains("public typealias") }.count - let totalGenerated = files.count - - // Verify counts match GIR exactly - #expect(generatedClasses == expectedClasses, - "Expected \(expectedClasses) classes, got \(generatedClasses)") - #expect(generatedInterfaces == expectedInterfaces, - "Expected \(expectedInterfaces) interfaces, got \(generatedInterfaces)") - #expect(generatedEnums == expectedEnums, - "Expected \(expectedEnums) enums, got \(generatedEnums)") - #expect(generatedBitfields == expectedBitfields, - "Expected \(expectedBitfields) bitfields, got \(generatedBitfields)") - #expect(generatedCallbacks > 0, - "Expected at least 1 callback typealias, got \(generatedCallbacks)") - #expect(totalGenerated > 200, - "Expected 200+ total files, got \(totalGenerated)") - - // Verify specific well-known files exist - #expect(files.keys.contains("Widget.swift"), "Missing Widget.swift") - #expect(files.keys.contains("Window.swift"), "Missing Window.swift") - #expect(files.keys.contains("Button.swift"), "Missing Button.swift") - #expect(files.keys.contains("Buildable.swift"), "Missing Buildable.swift (interface)") - // Verify interface is generated as a protocol - #expect(files["Buildable.swift"]?.contains("public protocol") == true) -} diff --git a/Tests/IntegrationTests/MonorepoGenerationTests.swift b/Tests/IntegrationTests/MonorepoGenerationTests.swift deleted file mode 100644 index 7103fe8..0000000 --- a/Tests/IntegrationTests/MonorepoGenerationTests.swift +++ /dev/null @@ -1,143 +0,0 @@ -import Foundation -import Testing -@testable import SwiftGtkGenCore - -@Suite("MonorepoGeneration") -struct MonorepoGenerationTests { - - private static func tempDir() -> String { - let d = NSTemporaryDirectory() + "monorepo_integ_\(UUID().uuidString)" - try? FileManager.default.createDirectory(atPath: d, withIntermediateDirectories: true) - return d - } - - /// Creates two mock GIR files: a root (GLib) and a dependent (GObject). - private func buildTwoPackageConfig() throws -> (MonorepoConfig, MultiPackageAnalyzer) { - let tmp = Self.tempDir() - - let glibXML = """ - - - - - - - - - - - """ - - let gobjXML = """ - - - - - - - - - - - - - - - - - - - - - """ - - let glibPath = tmp + "/GLib-2.0.gir" - let gobjPath = tmp + "/GObject-2.0.gir" - try glibXML.write(toFile: glibPath, atomically: true, encoding: .utf8) - try gobjXML.write(toFile: gobjPath, atomically: true, encoding: .utf8) - - let entries: [PackageEntry] = [ - PackageEntry(name: "GLib", girPath: glibPath), - PackageEntry(name: "GObject", girPath: gobjPath), - ] - let config = MonorepoConfig(outputDir: tmp, packages: entries) - let analyzer = MultiPackageAnalyzer(config: config) - return (config, analyzer) - } - - @Test func generatesSwiftFilesForBothPackages() throws { - let (_, analyzer) = try buildTwoPackageConfig() - let analysis = try analyzer.analyze() - - let generator = CodeGenerator(config: GenerationConfig( - library: "GObject", version: "2.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [] - )) - let outputs = try generator.generateMonorepo(analysis: analysis) - - #expect(outputs.count == 2, "Both GLib and GObject should produce output") - let glibFiles = outputs["GLib"] ?? [:] - #expect(glibFiles.keys.contains("LogLevel.swift"), "GLib enum should be generated") - - let gobjFiles = outputs["GObject"] ?? [:] - #expect(gobjFiles.keys.contains("Object.swift"), "GObject class should be generated") - } - - @Test func generatesPackageSwiftWithAllTargets() throws { - let (_, analyzer) = try buildTwoPackageConfig() - let analysis = try analyzer.analyze() - - let scaffolding = CodeGenerator.generateMonorepoScaffolding(analysis: analysis) - - let pkgSwift = scaffolding["Package.swift"] - #expect(pkgSwift != nil) - #expect(pkgSwift?.contains(".systemLibrary(name: \"CGLib\"") == true) - #expect(pkgSwift?.contains(".systemLibrary(name: \"CGObject\"") == true) - #expect(pkgSwift?.contains("name: \"GLib\",") == true) - #expect(pkgSwift?.contains("name: \"GObject\",") == true) - #expect(pkgSwift?.contains("dependencies: [\"CGLib\"]") == true) - } - - @Test func generatesReexportUmbrellaForDependent() throws { - let (_, analyzer) = try buildTwoPackageConfig() - let analysis = try analyzer.analyze() - - let scaffolding = CodeGenerator.generateMonorepoScaffolding(analysis: analysis) - - let gobjUmbrella = scaffolding["Sources/GObject/GObject.swift"] - #expect(gobjUmbrella?.contains("@_exported import GLib") == true) - - let glibUmbrella = scaffolding["Sources/GLib/GLib.swift"] - #expect(glibUmbrella?.contains("@_exported import") == false, - "GLib is root, should not re-export anything") - } - - @Test func generatedFilesHaveCrossModuleImports() throws { - let (_, analyzer) = try buildTwoPackageConfig() - let analysis = try analyzer.analyze() - - let generator = CodeGenerator(config: GenerationConfig( - library: "GObject", version: "2.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [] - )) - let outputs = try generator.generateMonorepo(analysis: analysis) - - let gobjFile = outputs["GObject"]?["Object.swift"] ?? "" - #expect(gobjFile.contains("import CGLib") || gobjFile.contains("import CGObject"), - "Should import its own C bridge") - #expect(gobjFile.contains("import GLib"), - "GObject dep should import GLib") - } -} diff --git a/Tests/IntegrationTests/PluginGenerationTests.swift b/Tests/IntegrationTests/PluginGenerationTests.swift deleted file mode 100644 index 08a2753..0000000 --- a/Tests/IntegrationTests/PluginGenerationTests.swift +++ /dev/null @@ -1,102 +0,0 @@ -import Testing -import Foundation - -/// End-to-end test: verify the BuildToolPlugin works by building a synthetic -/// SwiftPM package that uses the plugin, then linting the plugin output. -/// -/// The plugin generates files before compilation — even if compilation fails -/// (e.g. due to missing type references in generated code), the generated -/// files are still produced. This test verifies both plugin execution and -/// output formatting correctness. -@Suite("Build tool plugin generation + lint") -struct PluginGenerationTests { - - @Test("Build tool plugin generates and lints clean wrappers") - func testPluginBuildAndLint() throws { - let pluginPkgDir = URL(fileURLWithPath: "/tmp/test-plugin-pkg") - - guard FileManager.default.fileExists(atPath: pluginPkgDir.appendingPathComponent("Package.swift").path) else { - Issue.record("Test package scaffold not found at /tmp/test-plugin-pkg") - return - } - - // Phase 1: Build the test package (triggers the plugin). - // The plugin runs as a build-tool step before compilation; - // generated files exist in .build/ even if compilation fails. - let buildLog = URL(fileURLWithPath: "/tmp/test-plugin-build.log") - try? FileManager.default.removeItem(at: buildLog) - let buildProcess = Process() - buildProcess.executableURL = URL(fileURLWithPath: "/usr/bin/swift") - buildProcess.arguments = ["build"] - buildProcess.currentDirectoryURL = pluginPkgDir - let buildPipe = Pipe() - buildProcess.standardOutput = buildPipe - buildProcess.standardError = buildPipe - // Drain pipe to file in background to avoid buffer deadlock - DispatchQueue.global().async { - let data = buildPipe.fileHandleForReading.readDataToEndOfFile() - try? data.write(to: buildLog) - } - try buildProcess.run() - buildProcess.waitUntilExit() - let buildOutput = (try? String(contentsOf: buildLog, encoding: .utf8)) ?? "" - - - // Find generated Swift files under .build/ containing the "Generated by SwiftGtkGen" header - let buildDir = pluginPkgDir.appendingPathComponent(".build") - let generatedFiles = findGeneratedFiles(in: buildDir) - - if generatedFiles.isEmpty { - Issue.record( - "No generated files found. Build may not have triggered the plugin.\nBuild output:\n\(buildOutput)" - ) - return - } - - // Phase 2: Lint all generated files - let configPath = "/home/echo/Projects/Swift/gtk-swift/swift-gtk-gen/.swift-format" - for file in generatedFiles { - let lintLog = URL(fileURLWithPath: "/tmp/test-plugin-lint.log") - let lintProcess = Process() - lintProcess.executableURL = URL(fileURLWithPath: "/usr/bin/swift") - lintProcess.arguments = [ - "format", "lint", - "--configuration", configPath, - "--strict", - file.path, - ] - let lintPipe = Pipe() - lintProcess.standardOutput = lintPipe - lintProcess.standardError = lintPipe - DispatchQueue.global().async { - let data = lintPipe.fileHandleForReading.readDataToEndOfFile() - try? data.write(to: lintLog) - } - try lintProcess.run() - lintProcess.waitUntilExit() - - let lintOutput = (try? String(contentsOf: lintLog, encoding: .utf8)) ?? "" - if lintProcess.terminationStatus != 0 { - Issue.record("Lint failed for \(file.lastPathComponent):\n\(lintOutput)") - } - #expect(lintProcess.terminationStatus == 0, "\(file.lastPathComponent) must pass swift format lint --strict") - } - } - - /// Recursively finds `.swift` files under a directory that look like - /// generated output (contain "Generated by SwiftGtkGen"). - private func findGeneratedFiles(in directory: URL) -> [URL] { - guard let enumerator = FileManager.default.enumerator( - at: directory, - includingPropertiesForKeys: [.isRegularFileKey] - ) else { return [] } - var results: [URL] = [] - for case let url as URL in enumerator { - guard url.pathExtension == "swift" else { continue } - guard let content = try? String(contentsOf: url, encoding: .utf8), - content.contains("Generated by SwiftGtkGen") else { continue } - results.append(url) - } - return results - } -} diff --git a/Tests/IntegrationTests/RealGIRParsingTests.swift b/Tests/IntegrationTests/RealGIRParsingTests.swift new file mode 100644 index 0000000..bc72167 --- /dev/null +++ b/Tests/IntegrationTests/RealGIRParsingTests.swift @@ -0,0 +1,233 @@ +// RealGIRParsingTests.swift +// Cross-checks the parser against the system's real .gir files. Counts are +// verified against independently-derived ground truth (grep over the same XML) +// so that a parser regression that silently drops constructs is caught here +// rather than surfacing as mysterious missing bindings downstream. + +import Foundation +import Testing + +@testable import SwiftGtkGenCore + +@Suite("Real GIR parsing") +struct RealGIRParsingTests { + /// Directory holding the system's GObject Introspection files. + nonisolated static let girDirectory = "/usr/share/gir-1.0" + + /// Whether a given GIR file is present on this system. + /// + /// Callable from `@Test` availability traits, which run outside the + /// package's default MainActor isolation. + /// + /// - Parameter name: The GIR file name, e.g. `"Gtk-4.0.gir"`. + /// - Returns: `true` when the file exists and tests depending on it can run. + nonisolated static func hasGIR(_ name: String) -> Bool { + FileManager.default.fileExists(atPath: "\(girDirectory)/\(name)") + } + + /// Parses a system GIR file. + /// + /// - Parameter name: The GIR file name, e.g. `"Gtk-4.0.gir"`. + /// - Returns: The parsed repository. + /// - Throws: A `GIRParserError` if parsing fails. + static func parse(_ name: String) throws -> Repository { + try GIRParser().parse(fileURL: URL(fileURLWithPath: "\(girDirectory)/\(name)")) + } + + /// Counts occurrences of a literal substring in a GIR file, as independent + /// ground truth for what the parser should have found. + /// + /// Mirrors `grep -c` semantics for the single-occurrence-per-line markup + /// these attributes appear in. + /// + /// - Parameters: + /// - needle: The literal substring to count, e.g. `"direction=\"out\""`. + /// - file: The GIR file name. + /// - Returns: The number of lines containing the substring. + static func groundTruthCount(of needle: String, in file: String) throws -> Int { + let text = try String(contentsOfFile: "\(girDirectory)/\(file)", encoding: .utf8) + return text.split(separator: "\n").count { $0.contains(needle) } + } + + @Test(.enabled(if: hasGIR("GLib-2.0.gir"))) + func parsesGLib() throws { + let repo = try Self.parse("GLib-2.0.gir") + let ns = try #require(repo.namespaces.first { $0.name == "GLib" }) + #expect(ns.version == "2.0") + #expect(ns.records.count > 50) + #expect(ns.functions.count > 100) + #expect(ns.enumerations.count > 10) + + // Every record field must have a real type. `.void` fields were the + // signature of the old parser's dropped routing. + let voidFields = ns.records.flatMap { record in + record.fields.filter { $0.type == .void }.map { "\(record.name).\($0.name)" } + } + #expect(voidFields.isEmpty, "record fields with no type: \(voidFields.prefix(5))") + } + + @Test(.enabled(if: hasGIR("Gtk-4.0.gir"))) + func parsesGtkMatchingGroundTruth() throws { + let repo = try Self.parse("Gtk-4.0.gir") + let ns = try #require(repo.namespaces.first { $0.name == "Gtk" }) + + #expect(ns.classes.count == (try Self.groundTruthCount(of: " ns.records.count / 2) + } + + @Test(.enabled(if: hasGIR("Gtk-4.0.gir"))) + func capturesOutParametersAndThrows() throws { + let repo = try Self.parse("Gtk-4.0.gir") + let ns = try #require(repo.namespaces.first { $0.name == "Gtk" }) + + /// Every callable reachable from the namespace, reduced to the two + /// facts under test: its parameters and whether it throws. + var parameterLists: [[Parameter]] = [] + var throwsFlags: [Bool] = [] + func record(_ parameters: [Parameter], _ throwsGError: Bool) { + parameterLists.append(parameters) + throwsFlags.append(throwsGError) + } + for cls in ns.classes { + for m in cls.methods { record(m.parameters, m.throwsGError) } + for c in cls.constructors { record(c.parameters, c.throwsGError) } + for f in cls.functions { record(f.parameters, f.throwsGError) } + } + for iface in ns.interfaces { + for m in iface.methods { record(m.parameters, m.throwsGError) } + } + for rec in ns.records { + for m in rec.methods { record(m.parameters, m.throwsGError) } + } + for f in ns.functions { record(f.parameters, f.throwsGError) } + + let outParams = parameterLists.flatMap { $0 }.count { $0.direction == .out } + #expect(outParams > 300, "expected GTK's out-parameters to be parsed, found \(outParams)") + + let throwing = throwsFlags.count { $0 } + #expect(throwing > 30, "expected GTK's throwing callables to be parsed, found \(throwing)") + + // gtk_widget_measure is the canonical multi-out-parameter method. + let widget = try #require(ns.classes.first { $0.name == "Widget" }) + let measure = try #require(widget.methods.first { $0.name == "measure" }) + #expect(measure.parameters.count { $0.direction == .out } == 4) + } + + @Test(.enabled(if: hasGIR("Gtk-4.0.gir"))) + func capturesClassHierarchyAndGTypes() throws { + let repo = try Self.parse("Gtk-4.0.gir") + let ns = try #require(repo.namespaces.first { $0.name == "Gtk" }) + + let widget = try #require(ns.classes.first { $0.name == "Widget" }) + #expect(widget.parent == "GObject.InitiallyUnowned") + #expect(widget.isAbstract) + #expect(widget.getTypeFunction == "gtk_widget_get_type") + #expect(widget.implements.contains("Accessible")) + + // Every class must carry its GType registration: the registry needs it + // to classify types and drive GValue access. + let missingGType = ns.classes.filter { $0.getTypeFunction == nil }.map(\.name) + #expect(missingGType.isEmpty, "classes missing glib:get-type: \(missingGType.prefix(5))") + } + + /// The registry must link the real GTK stack across module boundaries. + /// Under the old generator this chain was severed at every namespace + /// boundary, so `Gtk.Widget` did not inherit from `GObject.Object` at all. + @Test( + .enabled( + if: hasGIR("Gtk-4.0.gir") && hasGIR("Gio-2.0.gir") + && hasGIR("GObject-2.0.gir") && hasGIR("GLib-2.0.gir"))) + func registryLinksRealGtkStackAcrossModules() throws { + // Mirrors the tier configs: Gtk's stack is only coherent with Gio + // present, since Gtk.Application inherits Gio.Application. + let registry = TypeRegistry(repositories: [ + "GLib": try Self.parse("GLib-2.0.gir"), + "GObject": try Self.parse("GObject-2.0.gir"), + "Gio": try Self.parse("Gio-2.0.gir"), + "Gtk": try Self.parse("Gtk-4.0.gir"), + ]) + + let ancestry = registry.ancestry(of: "Gtk.Button").map(\.girName) + #expect(ancestry.contains("Gtk.Widget")) + #expect(ancestry.contains("GObject.InitiallyUnowned")) + #expect(ancestry.last == "GObject.Object") + + // Floating-reference rule: widgets sink, plain GObjects do not. + let buttonFloats = registry.descendsFromInitiallyUnowned("Gtk.Button") + let appFloats = registry.descendsFromInitiallyUnowned("Gtk.Application") + #expect(buttonFloats) + #expect(!appFloats) + #expect(registry.isGObject("Gtk.Application")) + #expect(registry.ancestry(of: "Gtk.Application").map(\.girName).contains("Gio.Application")) + + // Cross-module `open` requirement: GObject.Object is subclassed only + // from other modules, and must still be open. + let subclassed = registry.subclassedTypes() + #expect(subclassed.contains("GObject.Object")) + #expect(subclassed.contains("GObject.InitiallyUnowned")) + + // Gtk includes Gdk and Gsk; with neither loaded, both must resolve as + // foreign so callables touching them skip cleanly rather than emitting + // fabricated type references. + let foreign = registry.foreign + #expect(foreign.contains("Gdk")) + #expect(foreign.contains("Gsk")) + let surface = registry.resolve(.typeRef("Surface", namespace: "Gdk"), from: "Gtk") + #expect(surface?.category == .foreign(namespace: "Gdk")) + } + + /// cairo ships no GIR on this system, but Gdk references it. Loading Gdk + /// must therefore surface cairo as foreign rather than as an unknown type. + @Test(.enabled(if: hasGIR("Gdk-4.0.gir") && hasGIR("GObject-2.0.gir") && hasGIR("GLib-2.0.gir"))) + func cairoResolvesAsForeignWhenGdkIsLoaded() throws { + let registry = TypeRegistry(repositories: [ + "GLib": try Self.parse("GLib-2.0.gir"), + "GObject": try Self.parse("GObject-2.0.gir"), + "Gdk": try Self.parse("Gdk-4.0.gir"), + ]) + let foreign = registry.foreign + #expect(foreign.contains("cairo")) + let context = registry.resolve(.typeRef("Context", namespace: "cairo"), from: "Gdk") + #expect(context?.category == .foreign(namespace: "cairo")) + } + + /// Every class parent named by the real GIRs must resolve. An unresolvable + /// parent means a fabricated superclass reference in generated code. + @Test( + .enabled( + if: hasGIR("Gtk-4.0.gir") && hasGIR("Gio-2.0.gir") + && hasGIR("GObject-2.0.gir") && hasGIR("GLib-2.0.gir"))) + func everyRealGtkClassParentResolves() throws { + let repos: [String: Repository] = [ + "GLib": try Self.parse("GLib-2.0.gir"), + "GObject": try Self.parse("GObject-2.0.gir"), + "Gio": try Self.parse("Gio-2.0.gir"), + "Gtk": try Self.parse("Gtk-4.0.gir"), + ] + let registry = TypeRegistry(repositories: repos) + let ns = try #require(repos["Gtk"]?.namespaces.first { $0.name == "Gtk" }) + + let unresolved = ns.classes.compactMap { cls -> String? in + guard let parent = cls.parent else { return nil } + let qualified = parent.contains(".") ? parent : "Gtk.\(parent)" + return registry.resolve(girName: qualified) == nil ? "\(cls.name) -> \(parent)" : nil + } + #expect(unresolved.isEmpty, "unresolvable class parents: \(unresolved.prefix(5))") + } + + @Test(.enabled(if: hasGIR("Gtk-4.0.gir"))) + func capturesNonIntrospectableSymbols() throws { + let repo = try Self.parse("Gtk-4.0.gir") + let ns = try #require(repo.namespaces.first { $0.name == "Gtk" }) + let nonIntrospectable = ns.classes.flatMap { cls in + cls.methods.filter { !$0.symbolInfo.isIntrospectable } + } + #expect(!nonIntrospectable.isEmpty, "GTK has non-introspectable methods that must be recognized") + } +} diff --git a/Tests/IntegrationTests/Support/IntegrationTestSupport.swift b/Tests/IntegrationTests/Support/IntegrationTestSupport.swift deleted file mode 100644 index 4761322..0000000 --- a/Tests/IntegrationTests/Support/IntegrationTestSupport.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation - -/// Error thrown by integration test helpers when the required environment -/// is missing. Swift Testing marks the test as failed when this is thrown. -enum IntegrationTestEnvironmentError: Error { - /// The required GIR file was not found on disk. - case missingGIRFile(String) - /// The expected namespace was not present in the parsed GIR. - case missingNamespace(String) -} diff --git a/Tests/SwiftGtkGenCLITests/CLITests.swift b/Tests/SwiftGtkGenCLITests/CLITests.swift index 1b91f45..986a62e 100644 --- a/Tests/SwiftGtkGenCLITests/CLITests.swift +++ b/Tests/SwiftGtkGenCLITests/CLITests.swift @@ -9,14 +9,9 @@ func testCLIHelp() throws { process.arguments = ["--help"] let output = try process.runAndCapture() #expect(output.contains("Usage:")) - #expect(output.contains("--gir-file")) + #expect(output.contains("--monorepo-config")) #expect(output.contains("--output")) - #expect(output.contains("--generate-all")) - #expect(output.contains("--config-toml")) - #expect(output.contains("--namespace")) - #expect(output.contains("--list-output-files")) - #expect(!output.contains("--library")) - #expect(!output.contains("--version")) + #expect(output.contains("--skip-report")) } private func findBinary() -> URL? { diff --git a/Tests/SwiftGtkGenCoreTests/CFunctionCallTests.swift b/Tests/SwiftGtkGenCoreTests/CFunctionCallTests.swift deleted file mode 100644 index 216f047..0000000 --- a/Tests/SwiftGtkGenCoreTests/CFunctionCallTests.swift +++ /dev/null @@ -1,116 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("Simple void method calls C function directly") -func testVoidMethodCall() throws { - let method = Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .void) - let callExpr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(callExpr == "gtk_widget_show(pointer)") -} - -@Test("String return wraps with String(cString:)") -func testStringReturnCall() throws { - let method = Method(name: "getLabel", cIdentifier: "gtk_label_get_text", - parameters: [ - Parameter(name: "label", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .string) - let callExpr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(callExpr == "String(cString: gtk_label_get_text(pointer))") -} - -@Test("Bool return uses CInt comparison") -func testBoolReturnCall() throws { - let method = Method(name: "getVisible", cIdentifier: "gtk_widget_get_visible", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .boolean) - let callExpr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(callExpr == "(gtk_widget_get_visible(pointer) != 0)") -} - -@Test("GObject pointer parameter uses .pointer property") -func testGObjectParameterCall() throws { - let method = Method(name: "add", cIdentifier: "gtk_container_add", - parameters: [ - Parameter(name: "container", type: .pointer, - transferOwnership: .none, isInstanceParameter: true), - Parameter(name: "child", type: .typeRef("Widget"), - transferOwnership: .none) - ], returnType: .void) - let callExpr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(callExpr == "gtk_container_add(pointer, child.pointer)") -} - -@Test("TypeRef return wraps in Swift type") -func testTypeRefReturnCall() throws { - let method = Method(name: "getParent", cIdentifier: "gtk_widget_get_parent", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .typeRef("Widget", namespace: "Gtk")) - let callExpr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(callExpr == "Widget(pointer: gtk_widget_get_parent(pointer))") -} - -@Test("Void return type produces bare call") -func testVoidReturn() throws { - let method = Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .void) - let expr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(expr == "gtk_widget_show(pointer)") -} - -@Test("Optional typeRef parameter uses optional chaining") -func testOptionalTypeRefParameter() throws { - let method = Method(name: "setParent", cIdentifier: "gtk_widget_set_parent", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true), - Parameter(name: "parent", type: .optional(.typeRef("Widget")), - transferOwnership: .none) - ], returnType: .void) - let expr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(expr == "gtk_widget_set_parent(pointer, parent?.pointer)") -} - -@Test("Optional typeRef return uses map") -func testOptionalTypeRefReturn() throws { - let method = Method(name: "getChild", cIdentifier: "gtk_widget_get_child", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .optional(.typeRef("Widget"))) - let expr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(expr == "gtk_widget_get_child(pointer).map { Widget(pointer: $0) }") -} - -@Test("Int32 return passes through directly") -func testIntReturn() throws { - let method = Method(name: "getWidth", cIdentifier: "gtk_widget_get_width", - parameters: [ - Parameter(name: "widget", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .int32) - let expr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(expr == "gtk_widget_get_width(pointer)") -} - -@Test("Filename return wraps with String(cString:)") -func testFilenameReturn() throws { - let method = Method(name: "getFilename", cIdentifier: "gtk_file_chooser_get_filename", - parameters: [ - Parameter(name: "chooser", type: .pointer, - transferOwnership: .none, isInstanceParameter: true) - ], returnType: .filename) - let expr = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer") - #expect(expr == "String(cString: gtk_file_chooser_get_filename(pointer))") -} diff --git a/Tests/SwiftGtkGenCoreTests/CodeGenTests.swift b/Tests/SwiftGtkGenCoreTests/CodeGenTests.swift deleted file mode 100644 index 0506f4c..0000000 --- a/Tests/SwiftGtkGenCoreTests/CodeGenTests.swift +++ /dev/null @@ -1,723 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("Generates a simple class wrapper") -func testGenerateClass() throws { - let repo = Repository(namespaces: [ - Namespace(name: "GLib", version: "2.0", classes: [ - Class(name: "String", cType: "GString", parent: nil, - constructors: [ - Constructor(name: "new", cIdentifier: "g_string_new", - parameters: [ - Parameter(name: "init", type: .string, transferOwnership: .none) - ], returnType: .typeRef("String")) - ], - methods: [ - Method(name: "assign", cIdentifier: "g_string_assign", - parameters: [ - Parameter(name: "string", type: .string, isNullable: false, - transferOwnership: .none, isInstanceParameter: true), - Parameter(name: "value", type: .string) - ], returnType: .typeRef("String")) - ], properties: [ - Property(name: "length", type: .int32, isReadable: true, isWritable: false) - ], signals: [ - Signal(name: "changed", parameters: [], returnType: .void) - ]) - ]) - ]) - let config = GenerationConfig(library: "GLib", version: "2.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["GLib.String"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["String.swift"] ?? "" - #expect(output.contains("public final class String")) - #expect(output.contains("convenience init")) - #expect(output.contains("g_string_new(`init`)")) - #expect(output.contains("func assign")) - #expect(output.contains("g_value_get_int")) - #expect(output.contains("connectChanged")) - #expect(output.contains("g_signal_connect_data")) - // Verify real C function call instead of fatalError - #expect(output.contains("g_string_assign(pointer.assumingMemoryBound(to: GString.self), value)")) - #expect(!output.contains("fatalError(\"g_object_get_property")) - #expect(!output.contains("fatalError(\"g_object_set_property")) - #expect(!output.contains("fatalError(\"C function call not yet implemented")) -} - -@Test("Kebab-case property names are converted to camelCase") -func testKebabCaseToCamelCase() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Box", cType: "GtkBox", parent: "Widget", - properties: [ - Property(name: "baseline-child", type: .int32, isReadable: true, isWritable: true), - Property(name: "baseline-position", type: .int32, isReadable: true, isWritable: false), - Property(name: "homogeneous", type: .boolean, isReadable: true, isWritable: true), - Property(name: "spacing", type: .int32, isReadable: true, isWritable: true), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Box"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["Box.swift"] ?? "" - #expect(output.contains("var baselineChild"), "baseline-child should become baselineChild") - #expect(output.contains("var baselinePosition"), "baseline-position should become baselinePosition") - #expect(output.contains("var homogeneous"), "homogeneous should stay as-is (no hyphens)") - #expect(output.contains("var spacing"), "spacing should stay as-is") - // Verify no kebab-case names remain in var declarations - #expect(!output.contains("var baseline-"), "No kebab-case var names should remain") -} - -@Test("Generates enumeration") -func testGenerateEnum() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", enumerations: [ - Enumeration(name: "Align", cType: "GtkAlign", - members: [ - EnumMember(name: "fill", value: "0", cIdentifier: "GTK_ALIGN_FILL"), - EnumMember(name: "start", value: "1", cIdentifier: "GTK_ALIGN_START"), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Align"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["Align.swift"] ?? "" - #expect(output.contains("public enum Align")) - #expect(output.contains("case fill")) - #expect(output.contains("case start")) -} - -@Test("Generates record with fields and methods") -func testGenerateRecord() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", records: [ - Record(name: "Rectangle", cType: "GdkRectangle", - fields: [ - Field(name: "x", type: .int32), - Field(name: "y", type: .int32), - Field(name: "width", type: .int32), - Field(name: "height", type: .int32), - ], methods: [ - Method(name: "contains_point", cIdentifier: "gdk_rectangle_contains_point", - parameters: [ - Parameter(name: "rect", type: .typeRef("Rectangle"), isInstanceParameter: true), - Parameter(name: "x", type: .int32), - Parameter(name: "y", type: .int32), - ], returnType: .boolean), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Rectangle"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["Rectangle.swift"] ?? "" - #expect(output.contains("public struct Rectangle")) - #expect(output.contains("public let x: Int32")) - #expect(output.contains("public let y: Int32")) - #expect(output.contains("public let width: Int32")) - #expect(output.contains("public let height: Int32")) - #expect(output.contains("mutating func containsPoint")) - #expect(output.contains("gdk_rectangle_contains_point(&self, x, y)")) -} - -@Test("Generates constant declaration") -func testGenerateConstant() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", constants: [ - Constant(name: "MAJOR_VERSION", value: "4", type: .int32), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.MAJOR_VERSION"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["MajorVersion.swift"] ?? "" - #expect(output.contains("public let majorVersion: Int32 = 4")) -} - -@Test("Generates typealias declaration") -func testGenerateAlias() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", aliases: [ - Alias(name: "Allocation", cType: "GtkAllocation", target: .typeRef("Rectangle")), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Allocation"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - - let output = files["Allocation.swift"] ?? "" - #expect(output.contains("public typealias Allocation = Rectangle")) -} - -@Test("Parameterized signal generates trampoline with extraction") -func testParameterizedSignalTrampoline() { - let signal = Signal(name: "size-allocate", parameters: [ - Parameter(name: "allocation", type: .typeRef("Rectangle")), - Parameter(name: "width", type: .int32), - ], returnType: .void) - let code = CodeGenerator.generateSignalConnection(signal: signal) - #expect(code.contains("connectSizeAllocate")) - #expect(code.contains("handler as AnyObject")) - #expect(code.contains("Unmanaged.fromOpaque(data!).takeUnretainedValue()")) - #expect(!code.contains("// Manual")) - #expect(!code.contains("nil, nil, nil")) - #expect(code.contains("g_signal_connect_data(pointer, \"size-allocate\"")) -} - -@Test("Class generation applies MainActor override") -func testMainActorOverride() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .object("Gtk.Widget", overrides: ObjectOverrides(concurrency: .mainActor)) - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("@MainActor")) - #expect(output.contains("public final class Widget")) -} - -@Test("Class generation applies Sendable conformance") -func testSendableOverride() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gdk", version: "4.0", classes: [ - Class(name: "Texture", cType: "GdkTexture", parent: nil) - ]) - ]) - let config = GenerationConfig(library: "Gdk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .object("Gdk.Texture", overrides: ObjectOverrides(concurrency: .sendable)) - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("extension Texture: Sendable {}")) -} - -@Test("Class generation applies cfgCondition") -func testCfgConditionOverride() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .object("Gtk.Widget", overrides: ObjectOverrides(cfgCondition: "os(macOS)")) - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("#if os(macOS)")) - #expect(output.contains("#endif")) -} - -@Test("Method override applies visibility and ignore") -func testMethodOverrides() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil, methods: [ - Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [ - Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true) - ], returnType: .void), - Method(name: "hide", cIdentifier: "gtk_widget_hide", - parameters: [ - Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true) - ], returnType: .void), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .function("Gtk.Widget", "show", overrides: FunctionOverrides(ignore: true)), - .function("Gtk.Widget", "hide", overrides: FunctionOverrides(visibility: .internal)), - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(!output.contains("func show")) - #expect(output.contains("internal func hide")) - #expect(!output.contains("public func hide")) -} - -@Test("Signal override ignores signal") -func testSignalOverrideIgnore() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil, signals: [ - Signal(name: "map", parameters: [], returnType: .void), - Signal(name: "unmap", parameters: [], returnType: .void), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .signal("Gtk.Widget", "unmap", overrides: SignalOverrides(ignore: true)), - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("connectMap")) - #expect(!output.contains("connectUnmap")) -} - -@Test("Inhibit signal generates Bool-returning handler") -func testInhibitSignalHandling() { - let signal = Signal(name: "delete-event", parameters: [], returnType: .boolean) - let code = CodeGenerator.generateSignalConnection(signal: signal, inhibit: true) - #expect(code.contains("() -> Bool")) - #expect(code.contains("gboolean")) - #expect(code.contains("result ? 1 : 0")) -} - -@Test("Function pattern override applies glob rename") -func testFunctionPatternOverride() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil, methods: [ - Method(name: "get_parent", cIdentifier: "gtk_widget_get_parent", - parameters: [ - Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true) - ], returnType: .typeRef("Widget")), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .functionPattern("Gtk.Widget", pattern: "get_*", - rename: RenameRule(regex: "^get_", replacement: "")), - ]) - let analyzer = Analyzer(config: config) - let analysis = analyzer.analyze(repository: repo) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: analysis) - #expect(output.contains("func parent")) - #expect(!output.contains("func getParent")) -} - -@Test("Constructor override generates convenience init") -func testConstructorOverride() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Label", cType: "GtkLabel", parent: "Widget", methods: [ - Method(name: "new", cIdentifier: "gtk_label_new", - parameters: [ - Parameter(name: "str", type: .string) - ], returnType: .typeRef("Widget")), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: [ - .function("Gtk.Label", "new", overrides: FunctionOverrides(constructor: true)), - ]) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("convenience init")) - #expect(output.contains("gtk_label_new(str)")) -} - -@Test("Subclass inherits pointer property from parent") -func testSubclassInheritsPointer() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: nil), - Class(name: "Button", cType: "GtkButton", parent: "Widget"), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let widgetOutput = files["Widget.swift"] ?? "" - let buttonOutput = files["Button.swift"] ?? "" - - // Root class has pointer - #expect(widgetOutput.contains("let pointer: UnsafeMutableRawPointer")) - - // Subclass inherits pointer, does not redeclare it - #expect(!buttonOutput.contains("let pointer: UnsafeMutableRawPointer")) -} - -@Test("Cross-namespace parent does not break pointer inheritance") -func testCrossNamespaceParentInheritsPointer() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned"), - Class(name: "Button", cType: "GtkButton", parent: "Widget"), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let widgetOutput = files["Widget.swift"] ?? "" - let buttonOutput = files["Button.swift"] ?? "" - - // Widget's parent is cross-namespace (GObject.InitiallyUnowned), so it gets its own pointer - #expect(widgetOutput.contains("let pointer: UnsafeMutableRawPointer")) - - // Button's parent is same-namespace Widget, so it inherits pointer - #expect(!buttonOutput.contains("let pointer: UnsafeMutableRawPointer")) -} - -@Test("Record generation included in generateFiles output") -func testRecordInGenerateFiles() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gdk", version: "4.0", records: [ - Record(name: "RGBA", cType: "GdkRGBA", - fields: [ - Field(name: "red", type: .double), - Field(name: "green", type: .double), - Field(name: "blue", type: .double), - Field(name: "alpha", type: .double), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gdk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gdk.RGBA"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(files.keys.contains("RGBA.swift")) - let output = files["RGBA.swift"] ?? "" - #expect(output.contains("public struct RGBA")) - #expect(output.contains("public let red: Double")) - #expect(output.contains("public let green: Double")) - #expect(output.contains("public let blue: Double")) - #expect(output.contains("public let alpha: Double")) -} - - @Test("Constant and alias in single-file generate") - func testConstantAndAliasInGenerate() throws { - let repo = Repository(namespaces: [ - Namespace(name: "GLib", version: "2.0", constants: [ - Constant(name: "VERSION", value: "2.0", type: .string), - ], aliases: [ - Alias(name: "Type", cType: "GType", target: .uint64), - ]) - ]) - let config = GenerationConfig(library: "GLib", version: "2.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: [], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let output = try generator.generate(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - #expect(output.contains("public let version: String = \"2.0\"")) - #expect(output.contains("public typealias Type = UInt64")) - } - - @Test("Subclass method that overrides parent gets override keyword") - func testOverrideKeywordOnOverriddenMethod() throws { - let parentMethods = [ - Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true)], - returnType: .void) - ] - let childMethods = [ - Method(name: "show", cIdentifier: "gtk_button_show", - parameters: [Parameter(name: "button", type: .typeRef("Button"), isInstanceParameter: true)], - returnType: .void), - Method(name: "clicked", cIdentifier: "gtk_button_clicked", - parameters: [Parameter(name: "button", type: .typeRef("Button"), isInstanceParameter: true)], - returnType: .void) - ] - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned", methods: parentMethods), - Class(name: "Button", cType: "GtkButton", parent: "Widget", methods: childMethods), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let buttonOutput = files["Button.swift"] ?? "" - - #expect(buttonOutput.contains("override func show")) - #expect(buttonOutput.contains("func clicked")) - #expect(!buttonOutput.contains("override func clicked")) - } - - @Test("Cross-namespace ancestor does not cause override") - func testCrossNamespaceAncestorNoOverride() throws { - // Widget has parent "GObject.InitiallyUnowned" which is in a different - // namespace. So Widget is a Swift root and "show" should NOT be marked override. - let parentMethods = [ - Method(name: "initiallyUnownedShow", cIdentifier: "g_initially_unowned_show", - parameters: [Parameter(name: "obj", type: .typeRef("InitiallyUnowned"), isInstanceParameter: true)], - returnType: .void) - ] - let widgetMethods = [ - Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true)], - returnType: .void) - ] - let repo = Repository(namespaces: [ - Namespace(name: "GObject", version: "2.0", classes: [ - Class(name: "InitiallyUnowned", cType: "GInitiallyUnowned", parent: nil, methods: parentMethods), - ]), - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned", methods: widgetMethods), - ]), - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "GObject.InitiallyUnowned"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let widgetOutput = files["Widget.swift"] ?? "" - - // Widget's "show" is NOT an override because its parent is cross-namespace - #expect(widgetOutput.contains("func show")) - #expect(!widgetOutput.contains("override func show")) - } - - @Test("Static function that overrides parent gets override keyword") - func testStaticFunctionOverrideKeyword() throws { - let parentFunctions = [ - GlobalFunction(name: "show_all", cIdentifier: "gtk_widget_show_all", - parameters: [Parameter(name: "widget", type: .typeRef("Widget"))], - returnType: .void) - ] - let childFunctions = [ - GlobalFunction(name: "show_all", cIdentifier: "gtk_button_show_all", - parameters: [Parameter(name: "button", type: .typeRef("Button"))], - returnType: .void) - ] - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned", functions: parentFunctions), - Class(name: "Button", cType: "GtkButton", parent: "Widget", functions: childFunctions), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let buttonOutput = files["Button.swift"] ?? "" - - #expect(buttonOutput.contains("static override func showAll")) - } - - @Test("Deep inheritance walks full chain") - func testDeepInheritanceChain() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned", - methods: [ - Method(name: "show", cIdentifier: "gtk_widget_show", - parameters: [Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true)], - returnType: .void) - ]), - Class(name: "Container", cType: "GtkContainer", parent: "Widget", - methods: [ - Method(name: "add", cIdentifier: "gtk_container_add", - parameters: [Parameter(name: "container", type: .typeRef("Container"), isInstanceParameter: true), - Parameter(name: "child", type: .typeRef("Widget"))], - returnType: .void) - ]), - Class(name: "Box", cType: "GtkBox", parent: "Container", - methods: [ - Method(name: "show", cIdentifier: "gtk_box_show", - parameters: [Parameter(name: "box", type: .typeRef("Box"), isInstanceParameter: true)], - returnType: .void), - Method(name: "add", cIdentifier: "gtk_box_add", - parameters: [Parameter(name: "box", type: .typeRef("Box"), isInstanceParameter: true), - Parameter(name: "child", type: .typeRef("Widget"))], - returnType: .void) - ]), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Container", "Gtk.Box"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let boxOutput = files["Box.swift"] ?? "" - - // Box inherits show from Widget (grandparent) and add from Container (parent) - #expect(boxOutput.contains("override func show")) - #expect(boxOutput.contains("override func add")) - } - - @Test("Bool parameter is converted to gboolean with ? 1 : 0") - func testBoolParameterConversion() throws { - let method = Method(name: "set_visible", cIdentifier: "gtk_widget_set_visible", - parameters: [ - Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true), - Parameter(name: "visible", type: .boolean) - ], - returnType: .void) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let output = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer", classTypeNames: nil, cType: "GtkWidget") - #expect(output.contains("visible ? 1 : 0")) - #expect(!output.contains(", visible)")) - } - - @Test("Optional Bool parameter is converted to gboolean with nil-check") - func testOptionalBoolParameterConversion() throws { - let method = Method(name: "set_can_focus", cIdentifier: "gtk_widget_set_can_focus", - parameters: [ - Parameter(name: "widget", type: .typeRef("Widget"), isInstanceParameter: true), - Parameter(name: "can_focus", type: .optional(.boolean)) - ], - returnType: .void) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let output = CodeGenerator.generateCFunctionCall(method: method, instancePointer: "pointer", classTypeNames: nil, cType: "GtkWidget") - #expect(output.contains("canFocus.map { $0 ? 1 : 0 } ?? 0")) - #expect(!output.contains(", canFocus)")) - } - -@Test("Optional boolean return is mapped with != 0") -func testOptionalBooleanReturnMapping() { - let result = CodeGenerator.wrapCReturnValue(callExpression: "g_value_get_boolean(&value)", returnType: .optional(.boolean)) - #expect(result == "g_value_get_boolean(&value).map { $0 != 0 }") -} - -@Test("Class with subclasses is not final") -func testClassWithSubclassesIsNotFinal() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned"), - Class(name: "Button", cType: "GtkButton", parent: "Widget"), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let widgetOutput = files["Widget.swift"] ?? "" - let buttonOutput = files["Button.swift"] ?? "" - - // Widget has a subclass (Button), so it should NOT be final - #expect(widgetOutput.contains("open class Widget")) - #expect(!widgetOutput.contains("final class Widget")) - - // Button has no subclasses, so it CAN be final - #expect(buttonOutput.contains("final class Button")) -} - -@Test("Cross-namespace child does not force open class") -func testCrossNamespaceChildDoesNotForceOpen() throws { - // Base is in GObject namespace. Derived is in Gtk namespace (cross-namespace). - // Base should remain `final class` since the child is in a different namespace. - let repo = Repository(namespaces: [ - Namespace(name: "GObject", version: "2.0", classes: [ - Class(name: "Base", cType: "GBase", parent: nil), - ]), - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Derived", cType: "GtkDerived", parent: "GObject.Base"), - ]), - ]) - let config = GenerationConfig(library: "GObject", version: "2.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["GObject.Base"], manual: [], ignore: [], objects: []) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo)) - let baseOutput = files["Base.swift"] ?? "" - - // Base has a child (Derived) but in a different namespace, so it stays final - #expect(baseOutput.contains("final class Base")) -} - -@Test func qualifiedTypeQualifiesCrossNamespaceRef() { - let nsMap = ["Gdk": "Gdk", "Gsk": "Gsk", "GObject": "GObject"] - let rect = GIRType.typeRef("Rectangle", namespace: "Gdk") - let result = CodeGenerator.qualifiedTypeToSwift(rect, currentModule: "Gtk", nsToModule: nsMap) - #expect(result == "Gdk.Rectangle") -} - -@Test func qualifiedTypeKeepsBareNameForSameModule() { - let nsMap = ["Gtk": "Gtk"] - let widget = GIRType.typeRef("Widget", namespace: "Gtk") - let result = CodeGenerator.qualifiedTypeToSwift(widget, currentModule: "Gtk", nsToModule: nsMap) - #expect(result == "Widget") -} - -@Test func qualifiedTypeUnqualifiedRefStaysBare() { - let nsMap = ["Gdk": "Gdk"] - let widget = GIRType.typeRef("Widget", namespace: nil) - let result = CodeGenerator.qualifiedTypeToSwift(widget, currentModule: "Gtk", nsToModule: nsMap) - #expect(result == "Widget") -} - -@Test func qualifiedTypeNestsWithOptional() { - let nsMap = ["Gdk": "Gdk"] - let optRect = GIRType.optional(.typeRef("Rectangle", namespace: "Gdk")) - let result = CodeGenerator.qualifiedTypeToSwift(optRect, currentModule: "Gtk", nsToModule: nsMap) - #expect(result == "Gdk.Rectangle?") -} - -@Test func generateReexportUmbrellasExportsTransitiveDeps() { - var repos: [String: Repository] = [:] - repos["GLib"] = Repository() - repos["GObject"] = Repository() - repos["Gtk"] = Repository() - let analysis = MultiPackageAnalysis( - repositories: repos, - directDependencies: [ - "GLib": [], - "GObject": ["GLib"], - "Gtk": ["GObject"], - ], - transitiveDependencies: [ - "GLib": [], - "GObject": ["GLib"], - "Gtk": ["GLib", "GObject"], - ], - implicitImports: ["GLib": [], "GObject": [], "Gtk": []], - packageConfigs: [:] - ) - - let umbrellas = CodeGenerator.generateReexportUmbrellas(analysis: analysis) - - let glibUmbrella = umbrellas["Sources/GLib/GLib.swift"] - #expect(glibUmbrella != nil) - #expect(!(glibUmbrella?.contains("@_exported import") ?? false), - "GLib is root, no re-exports expected") - - let gobjUmbrella = umbrellas["Sources/GObject/GObject.swift"] - #expect(gobjUmbrella?.contains("@_exported import GLib") == true) - - let gtkUmbrella = umbrellas["Sources/Gtk/Gtk.swift"] - #expect(gtkUmbrella?.contains("@_exported import GObject") == true) - #expect(gtkUmbrella?.contains("@_exported import GLib") == true) -} diff --git a/Tests/SwiftGtkGenCoreTests/ConstructorTests.swift b/Tests/SwiftGtkGenCoreTests/ConstructorTests.swift deleted file mode 100644 index a1e76e7..0000000 --- a/Tests/SwiftGtkGenCoreTests/ConstructorTests.swift +++ /dev/null @@ -1,35 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("Constructor with no parameters generates convenience init") -func testConstructorNoParams() { - let ctor = Constructor(name: "new", cIdentifier: "gtk_button_new", - parameters: [], returnType: .typeRef("Widget")) - let initMethod = CodeGenerator.generateConstructor(constructor: ctor, className: "Button") - #expect(initMethod.contains("convenience init")) - #expect(initMethod.contains("gtk_button_new()")) - #expect(!initMethod.contains("g_object_ref_sink")) - #expect(initMethod.contains("self.init(pointer:")) -} - -@Test("Constructor with string parameter") -func testConstructorWithStringParam() { - let ctor = Constructor(name: "newWithLabel", cIdentifier: "gtk_button_new_with_label", - parameters: [ - Parameter(name: "label", type: .string, transferOwnership: .none) - ], returnType: .typeRef("Widget")) - let initMethod = CodeGenerator.generateConstructor(constructor: ctor, className: "Button") - #expect(initMethod.contains("label: String")) - #expect(initMethod.contains("gtk_button_new_with_label(label)")) -} - -@Test("Constructor with GObject parameter uses .pointer") -func testConstructorWithGObjectParam() { - let ctor = Constructor(name: "newFromModel", cIdentifier: "gtk_combo_box_new_from_model", - parameters: [ - Parameter(name: "model", type: .typeRef("TreeModel"), transferOwnership: .none) - ], returnType: .typeRef("Widget")) - let initMethod = CodeGenerator.generateConstructor(constructor: ctor, className: "ComboBox") - #expect(initMethod.contains("model: TreeModel")) - #expect(initMethod.contains("gtk_combo_box_new_from_model(model.pointer)")) -} diff --git a/Tests/SwiftGtkGenCoreTests/FileOutputTests.swift b/Tests/SwiftGtkGenCoreTests/FileOutputTests.swift deleted file mode 100644 index 221568e..0000000 --- a/Tests/SwiftGtkGenCoreTests/FileOutputTests.swift +++ /dev/null @@ -1,66 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("generateFiles returns one file per type") -func testGenerateFilesReturnsMultipleFiles() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.Object"), - Class(name: "Window", cType: "GtkWindow", parent: "Widget"), - ], enumerations: [ - Enumeration(name: "Align", cType: "GtkAlign", members: [ - EnumMember(name: "fill", value: "0", cIdentifier: "GTK_ALIGN_FILL"), - ]) - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget", "Gtk.Window", "Gtk.Align"], manual: [], ignore: [], objects: []) - let analysis = Analyzer(config: config).analyze(repository: repo) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - #expect(files.keys.contains("Widget.swift")) - #expect(files.keys.contains("Window.swift")) - #expect(files.keys.contains("Align.swift")) - #expect(files["Widget.swift"]?.contains("class Widget") == true) - #expect(files["Widget.swift"]?.contains("class Window") == false) - #expect(files["Align.swift"]?.contains("enum Align") == true) -} - -@Test("generateFiles includes import CGtk in header") -func testGenerateFilesIncludesCGtkImport() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.Object"), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget"], manual: [], ignore: [], objects: []) - let analysis = Analyzer(config: config).analyze(repository: repo) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - #expect(files["Widget.swift"]?.contains("import Foundation") == true) - #expect(files["Widget.swift"]?.contains("import CGtk") == true) -} - -@Test("generateFiles skips types not in analysis") -func testGenerateFilesSkipsNonGeneratedTypes() throws { - let repo = Repository(namespaces: [ - Namespace(name: "Gtk", version: "4.0", classes: [ - Class(name: "Widget", cType: "GtkWidget", parent: "GObject.Object"), - Class(name: "Button", cType: "GtkButton", parent: "Widget"), - ]) - ]) - let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [], - targetDirectory: "", externalLibraries: [], - generate: ["Gtk.Widget"], manual: [], ignore: [], objects: []) - let analysis = Analyzer(config: config).analyze(repository: repo) - let generator = CodeGenerator(config: config) - let files = try generator.generateFiles(repository: repo, analysis: analysis) - - #expect(files.keys.contains("Widget.swift")) - #expect(files.keys.contains("Button.swift") == false) -} diff --git a/Tests/SwiftGtkGenCoreTests/FunctionGenerationTests.swift b/Tests/SwiftGtkGenCoreTests/FunctionGenerationTests.swift new file mode 100644 index 0000000..7c98717 --- /dev/null +++ b/Tests/SwiftGtkGenCoreTests/FunctionGenerationTests.swift @@ -0,0 +1,170 @@ +// FunctionGenerationTests.swift +// Covers Phase C1: namespace-level function planning and rendering — the +// C-type bridging that lets primitive, enum, bitfield, and const-string +// callables generate compilable Swift. These lock in the boundary decisions +// (numericCast for width-ambiguous integers, withCString for input strings, +// and the skips for varargs / mutable buffers / string vectors) so a +// regression surfaces here rather than as a mysterious drop in gate coverage. + +import Testing + +@testable import SwiftGtkGenCore + +@Suite("Function generation") +struct FunctionGenerationTests { + /// A registry-backed context in the GLib module. No named types are needed: + /// these tests exercise primitives, strings, and bitfields only. + func makeContext() -> MapContext { + let glib = Repository(namespaces: [ + Namespace( + name: "GLib", version: "2.0", + bitfields: [ + Bitfield(name: "LogLevelFlags", cType: "GLogLevelFlags", + getTypeFunction: "g_log_level_flags_get_type") + ] + ) + ]) + let registry = TypeRegistry(repositories: ["GLib": glib]) + return MapContext(registry: registry, currentModule: "GLib", currentNamespace: "GLib") + } + + /// Renders a single planned callable to Swift source via the public module + /// renderer, returning the callable's file body. + func render(_ plan: CallablePlan) -> String { + let module = ModulePlan( + module: "GLib", + types: [.callable(plan)], + skips: [], + coverage: CoverageStats() + ) + let files = renderModule(module) + return files["\(plan.name).swift"] ?? "" + } + + // MARK: - Plannable callables + + @Test("Width-ambiguous integer parameters bridge through numericCast") + func integerParameterBridging() throws { + let fn = GlobalFunction( + name: "free_sized", cIdentifier: "g_free_sized", + parameters: [ + Parameter(name: "mem", type: .pointer, cType: "gpointer"), + Parameter(name: "size", type: .size, cType: "gsize"), + ] + ) + guard case .success(let plan) = planFunction(fn, context: makeContext()) else { + Issue.record("expected g_free_sized to plan successfully"); return + } + #expect(plan.parameters.count == 2) + #expect(plan.parameters[1].mapping.marshalIn == .numericCast(targetType: "UInt")) + + let body = render(plan) + #expect(body.contains("g_free_sized(mem, numericCast(size))")) + } + + @Test("Const string parameters are bridged with withCString") + func stringParameterBridging() throws { + let fn = GlobalFunction( + name: "set_application_name", cIdentifier: "g_set_application_name", + parameters: [ + Parameter(name: "application_name", type: .string, cType: "const char*") + ] + ) + guard case .success(let plan) = planFunction(fn, context: makeContext()) else { + Issue.record("expected const-string function to plan successfully"); return + } + #expect(plan.parameters[0].mapping.marshalIn == .stringToC) + + let body = render(plan) + #expect(body.contains("application_name.withCString { cString0 in")) + #expect(body.contains("g_set_application_name(cString0)")) + } + + @Test("Bitfield parameters and returns round-trip through the C flags type") + func bitfieldRoundTrip() throws { + let fn = GlobalFunction( + name: "log_set_always_fatal", cIdentifier: "g_log_set_always_fatal", + parameters: [ + Parameter(name: "fatal_mask", type: .typeRef("LogLevelFlags"), cType: "GLogLevelFlags") + ], + returnValue: ReturnValue(type: .typeRef("LogLevelFlags")) + ) + guard case .success(let plan) = planFunction(fn, context: makeContext()) else { + Issue.record("expected bitfield function to plan successfully"); return + } + let body = render(plan) + #expect(body.contains("GLogLevelFlags(rawValue: numericCast(fatal_mask.rawValue))")) + #expect(body.contains("LogLevelFlags(rawValue: numericCast(")) + } + + // MARK: - Skips + + @Test("Variadic functions are skipped with the varargs reason") + func variadicSkip() throws { + let fn = GlobalFunction( + name: "build_filename", cIdentifier: "g_build_filename", + parameters: [ + Parameter(name: "first_element", type: .string, cType: "const char*"), + Parameter(name: "...", type: .void), + ] + ) + guard case .skip(let entry) = planFunction(fn, context: makeContext()) else { + Issue.record("expected variadic function to be skipped"); return + } + #expect(entry.reason == .varargs) + } + + @Test("Mutable string buffers and string vectors are skipped") + func mutableAndVectorStringSkips() throws { + let mutableBuffer = GlobalFunction( + name: "utf8_strncpy", cIdentifier: "g_utf8_strncpy", + parameters: [Parameter(name: "dest", type: .string, cType: "char*")] + ) + guard case .skip = planFunction(mutableBuffer, context: makeContext()) else { + Issue.record("expected mutable string buffer to be skipped"); return + } + + let stringVector = GlobalFunction( + name: "cmp_strv", cIdentifier: "g_cmp_strv", + parameters: [Parameter(name: "arg1", type: .string, cType: "const char* const*")] + ) + guard case .skip = planFunction(stringVector, context: makeContext()) else { + Issue.record("expected string vector to be skipped"); return + } + } + + @Test("Unexported C symbols never reach a plan") + func missingSymbolSkip() throws { + // g_open is a `#define g_open open` macro on non-Windows: not a real + // symbol. The planner must skip it before rendering an uncompilable call. + var skips: [SkipEntry] = [] + var types: [TypePlan] = [] + let fn = GlobalFunction(name: "open", cIdentifier: "g_open") + let bound = planOrSkipFunctionForTest(&skips, &types, fn) + #expect(bound == 0) + #expect(types.isEmpty) + #expect(skips.count == 1) + } + + /// Test shim over the private `planOrSkipFunction`, exercised through the + /// public planner so the missing-symbol gate is covered end to end. + private func planOrSkipFunctionForTest( + _ skips: inout [SkipEntry], _ types: inout [TypePlan], _ fn: GlobalFunction + ) -> Int { + let ns = Namespace(name: "GLib", version: "2.0", functions: [fn]) + let repo = Repository(namespaces: [ns]) + let analysis = MultiPackageAnalysis( + repositories: ["GLib": repo], + directDependencies: ["GLib": []], + transitiveDependencies: ["GLib": []], + implicitImports: ["GLib": []], + packageConfigs: [:] + ) + let registry = TypeRegistry(repositories: ["GLib": repo]) + let plans = planModules(analysis: analysis, registry: registry) + let module = plans["GLib"] + skips = module?.skips ?? [] + types = module?.types ?? [] + return module?.coverage.boundCallables ?? 0 + } +} diff --git a/Tests/SwiftGtkGenCoreTests/IRModelTests.swift b/Tests/SwiftGtkGenCoreTests/IRModelTests.swift index e50a6c4..eac3a66 100644 --- a/Tests/SwiftGtkGenCoreTests/IRModelTests.swift +++ b/Tests/SwiftGtkGenCoreTests/IRModelTests.swift @@ -24,10 +24,46 @@ func testClassHasProperties() { @Test("Method stores parameters and return type") func testMethodStoresParameters() { let param = Parameter(name: "label", type: .string, isNullable: false, transferOwnership: .none) - let method = Method(name: "set_label", cIdentifier: "gtk_label_set_text", parameters: [param], returnType: .void) + let method = Method(name: "set_label", cIdentifier: "gtk_label_set_text", parameters: [param]) #expect(method.name == "set_label") #expect(method.parameters.count == 1) - #expect(method.returnType == .void) + #expect(method.returnValue.type == .void) +} + +@Test("Method carries return ownership and nullability") +func testMethodCarriesReturnSemantics() { + let method = Method( + name: "get_name", cIdentifier: "gtk_widget_get_name", + returnValue: ReturnValue(type: .string, isNullable: true, transferOwnership: .full) + ) + #expect(method.returnValue.type == .string) + #expect(method.returnValue.isNullable) + #expect(method.returnValue.transferOwnership == .full) + #expect(!method.throwsGError) +} + +@Test("Parameter defaults to in-direction with no callback scope") +func testParameterDirectionDefaults() { + let param = Parameter(name: "value", type: .int32) + #expect(param.direction == .in) + #expect(param.scope == nil) + #expect(param.closureIndex == nil) + #expect(!param.callerAllocates) +} + +@Test("Parameter records out-direction and callback metadata") +func testParameterRecordsOutAndCallbackMetadata() { + let out = Parameter(name: "natural", type: .int32, direction: .out, callerAllocates: true) + #expect(out.direction == .out) + #expect(out.callerAllocates) + + let callback = Parameter( + name: "callback", type: .typeRef("Callback"), + scope: .notified, closureIndex: 1, destroyIndex: 2 + ) + #expect(callback.scope == .notified) + #expect(callback.closureIndex == 1) + #expect(callback.destroyIndex == 2) } @Test("Enumeration stores members") @@ -41,9 +77,9 @@ func testEnumerationStoresMembers() { @Test("Signal stores parameters and return type") func testSignalStoresParameters() { - let signal = Signal(name: "clicked", parameters: [], returnType: .void, isDetailed: false) + let signal = Signal(name: "clicked", parameters: [], isDetailed: false) #expect(signal.name == "clicked") - #expect(signal.returnType == .void) + #expect(signal.returnValue.type == .void) #expect(signal.isDetailed == false) } @@ -72,10 +108,46 @@ func testGIRTypeEquality() { #expect(GIRType.string == GIRType.string) #expect(GIRType.typeRef("GtkWidget") == GIRType.typeRef("GtkWidget")) #expect(GIRType.typeRef("GtkWidget") != GIRType.typeRef("GtkLabel")) - #expect(GIRType.array(.string) == GIRType.array(.string)) - #expect(GIRType.array(.string) != GIRType.array(.int32)) + #expect(GIRType.cArray(.string) == GIRType.cArray(.string)) + #expect(GIRType.cArray(.string) != GIRType.cArray(.int32)) #expect(GIRType.optional(.string) == GIRType.optional(.string)) #expect(GIRType.optional(.string) != GIRType.string) + #expect(GIRType.container(.list, elements: [.string]) == GIRType.container(.list, elements: [.string])) + #expect(GIRType.container(.list, elements: [.string]) != GIRType.container(.slist, elements: [.string])) +} + +@Test("Array length metadata distinguishes bridgeable arrays") +func testArrayInfoKnownLength() { + #expect(!ArrayInfo().hasKnownLength) + #expect(ArrayInfo(lengthParameterIndex: 1).hasKnownLength) + #expect(ArrayInfo(fixedSize: 4).hasKnownLength) + #expect(ArrayInfo(isZeroTerminated: true).hasKnownLength) + // Length metadata participates in type identity: two arrays of the same + // element type but different lengths are not interchangeable. + #expect(GIRType.cArray(.string, ArrayInfo(lengthParameterIndex: 1)) + != GIRType.cArray(.string, ArrayInfo(isZeroTerminated: true))) +} + +@Test("SymbolInfo gates binding on introspectability and shadowing") +func testSymbolInfoBindability() { + #expect(SymbolInfo().isBindable) + #expect(!SymbolInfo(isIntrospectable: false).isBindable) + #expect(!SymbolInfo(shadowedBy: "g_object_set_valist").isBindable) + #expect(!SymbolInfo(movedTo: "Gtk.Widget.newer").isBindable) + // Deprecation alone does not make a symbol unbindable. + #expect(SymbolInfo(isDeprecated: true).isBindable) +} + +@Test("Record boxedness follows GType registration") +func testRecordBoxedness() { + let boxed = Record(name: "RGBA", cType: "GdkRGBA", getTypeFunction: "gdk_rgba_get_type") + #expect(boxed.isBoxed) + + let plain = Record(name: "Bogus", cType: "GBogus") + #expect(!plain.isBoxed) + + let typeStruct = Record(name: "WidgetClass", cType: "GtkWidgetClass", isGTypeStructFor: "Widget") + #expect(typeStruct.isGTypeStructFor == "Widget") } @Test("Interface stores methods, properties, signals, and prereqs") diff --git a/Tests/SwiftGtkGenCoreTests/ParserSemanticsTests.swift b/Tests/SwiftGtkGenCoreTests/ParserSemanticsTests.swift new file mode 100644 index 0000000..f89da45 --- /dev/null +++ b/Tests/SwiftGtkGenCoreTests/ParserSemanticsTests.swift @@ -0,0 +1,421 @@ +// ParserSemanticsTests.swift +// Covers the GIR attributes the binding planner depends on: parameter +// direction, GError throwing, introspectability, GType registration, record +// type-structs, array length metadata, container element types, and record +// field types. Each of these was previously dropped on the floor by the parser. + +import Foundation +import Testing + +@testable import SwiftGtkGenCore + +/// Wraps GIR element markup in a minimal well-formed repository document. +/// +/// - Parameter body: The XML to place inside the `` element. +/// - Returns: A complete GIR document string ready to parse. +private func girDocument(_ body: String) -> String { + """ + + + + \(body) + + + """ +} + +@Suite("Parser semantics") +struct ParserSemanticsTests { + /// Record fields previously always parsed as `.void` because the `` + /// handler never routed to the enclosing field. + @Test("Record field types are populated") + func fieldTypesArePopulated() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + """)) + let record = try #require(repo.namespaces.first?.records.first) + #expect(record.fields.count == 2) + #expect(record.fields.allSatisfy { $0.type == .float }) + #expect(record.isBoxed) + } + + /// C vtable structs hold function-pointer members, spelled as a `` + /// child rather than a ``. Such a field is an opaque function pointer + /// at the ABI level, and must not be left as `.void`. + @Test("Function-pointer fields are typed as pointers") + func callbackFieldsAreTypedAsPointers() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + """)) + let ns = try #require(repo.namespaces.first) + let record = try #require(ns.records.first) + #expect(record.fields.count == 2) + #expect(record.fields[0].type == .pointer) + #expect(record.fields[1].type == .int32) + // A callback nested in a field is not a namespace-level declaration. + #expect(ns.callbacks.isEmpty) + } + + @Test("Parameter direction and caller-allocates are captured") + func parameterDirectionIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + + + + """)) + let method = try #require(repo.namespaces.first?.classes.first?.methods.first) + #expect(method.parameters.count == 3) + #expect(method.parameters[0].isInstanceParameter) + #expect(method.parameters[1].direction == .out) + #expect(!method.parameters[1].callerAllocates) + #expect(method.parameters[2].direction == .in) + } + + @Test("GError-throwing callables are flagged") + func throwingCallablesAreFlagged() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + """)) + let methods = try #require(repo.namespaces.first?.classes.first?.methods) + #expect(methods[0].throwsGError) + #expect(!methods[1].throwsGError) + } + + @Test("Return value ownership and nullability are captured") + func returnValueSemanticsAreCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + """)) + let method = try #require(repo.namespaces.first?.classes.first?.methods.first) + #expect(method.returnValue.type == .string) + #expect(method.returnValue.transferOwnership == .full) + #expect(method.returnValue.isNullable) + } + + @Test("Non-introspectable and shadowed symbols are marked unbindable") + func symbolInfoIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + """)) + let methods = try #require(repo.namespaces.first?.classes.first?.methods) + #expect(!methods[0].symbolInfo.isIntrospectable) + #expect(!methods[0].symbolInfo.isBindable) + #expect(methods[1].symbolInfo.shadowedBy == "set_property") + #expect(!methods[1].symbolInfo.isBindable) + // Deprecation is recorded but does not by itself prevent binding. + #expect(methods[2].symbolInfo.isDeprecated) + #expect(methods[2].symbolInfo.deprecatedVersion == "2.4") + #expect(methods[2].symbolInfo.isBindable) + } + + @Test("Class GType registration, finality, and interfaces are captured") + func classMetadataIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + """)) + let classes = try #require(repo.namespaces.first?.classes) + #expect(classes[0].isAbstract) + #expect(!classes[0].isFinal) + #expect(classes[0].parent == "GObject.InitiallyUnowned") + #expect(classes[0].getTypeFunction == "gtk_widget_get_type") + #expect(classes[0].typeName == "GtkWidget") + #expect(classes[0].implements == ["Accessible", "Buildable"]) + #expect(classes[1].isFinal) + } + + @Test("GObject type-struct records are identified") + func gtypeStructRecordsAreIdentified() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + """)) + let records = try #require(repo.namespaces.first?.records) + #expect(records[0].isGTypeStructFor == "Widget") + #expect(!records[0].isBoxed) + #expect(records[1].isGTypeStructFor == nil) + #expect(records[1].isBoxed) + } + + @Test("Array length metadata is captured") + func arrayLengthMetadataIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + + + + + + + + + + + + + """)) + let params = try #require(repo.namespaces.first?.classes.first?.methods.first?.parameters) + + guard case .cArray(let element, let info) = params[0].type else { + Issue.record("expected a C array for 'names', got \(params[0].type)") + return + } + #expect(element == .string) + #expect(info.lengthParameterIndex == 1) + #expect(!info.isZeroTerminated) + #expect(info.hasKnownLength) + + guard case .cArray(_, let zeroInfo) = params[2].type else { + Issue.record("expected a C array for 'tags'") + return + } + #expect(zeroInfo.isZeroTerminated) + #expect(zeroInfo.hasKnownLength) + + guard case .cArray(_, let fixedInfo) = params[3].type else { + Issue.record("expected a C array for 'quad'") + return + } + #expect(fixedInfo.fixedSize == 4) + } + + @Test("Container element types are captured") + func containerElementTypesAreCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + """)) + let method = try #require(repo.namespaces.first?.classes.first?.methods.first) + guard case .container(let kind, let elements) = method.returnValue.type else { + Issue.record("expected a container type, got \(method.returnValue.type)") + return + } + #expect(kind == .list) + #expect(elements == [.typeRef("Widget")]) + #expect(method.returnValue.transferOwnership == .container) + } + + @Test("Callback scope, closure, and destroy indices are captured") + func callbackScopeIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + + """)) + let param = try #require(repo.namespaces.first?.classes.first?.methods.first?.parameters.first) + #expect(param.scope == .notified) + #expect(param.closureIndex == 1) + #expect(param.destroyIndex == 2) + } + + @Test("Property getter, setter, and transfer are captured") + func propertyAccessorsAreCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + """)) + let prop = try #require(repo.namespaces.first?.classes.first?.properties.first) + #expect(prop.type == .string) + #expect(prop.getter == "get_label") + #expect(prop.setter == "set_label") + #expect(prop.isWritable) + } + + @Test("Interface prerequisites parse from child elements") + func interfacePrerequisitesParse() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + """)) + let iface = try #require(repo.namespaces.first?.interfaces.first) + #expect(iface.prereqs == ["GObject.Object"]) + #expect(iface.getTypeFunction == "gtk_buildable_get_type") + } + + @Test("Virtual method bodies do not leak into class members") + func virtualMethodsDoNotLeak() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + + + + + """)) + let cls = try #require(repo.namespaces.first?.classes.first) + // The virtual method contributes no method, and — critically — its + // parameters do not attach to the sibling . + #expect(cls.methods.count == 1) + #expect(cls.methods[0].name == "show") + #expect(cls.methods[0].parameters.isEmpty) + } + + @Test("Enum GType, error domain, and aliased values are captured") + func enumMetadataIsCaptured() throws { + let repo = try GIRParser().parse( + xmlString: girDocument( + """ + + + + + + + + + """)) + let enums = try #require(repo.namespaces.first?.enumerations) + #expect(enums[0].getTypeFunction == "gtk_align_get_type") + // Aliased raw values survive parsing intact; de-duplicating them into + // Swift `static var` aliases is the renderer's job. + #expect(enums[0].members.count == 3) + #expect(enums[0].members[1].value == "4") + #expect(enums[0].members[2].value == "4") + #expect(enums[1].errorDomain == "g-file-error-quark") + } + + @Test("Full primitive type table maps without fabricating type refs") + func primitiveTypeTableIsComplete() { + let expected: [String: GIRType] = [ + "none": .void, "gboolean": .boolean, + "gint8": .int8, "gint16": .int16, "gint": .int32, "gint32": .int32, "gint64": .int64, + "guint8": .uint8, "guint16": .uint16, "guint": .uint32, "guint32": .uint32, "guint64": .uint64, + "glong": .long, "gulong": .ulong, "gsize": .size, "gssize": .ssize, + "gchar": .char, "guchar": .uchar, "gunichar": .unichar, "GType": .gtype, + "gfloat": .float, "gdouble": .double, + "utf8": .string, "filename": .filename, + "gpointer": .pointer, "gconstpointer": .pointer, "va_list": .vaList, + ] + for (name, type) in expected { + #expect(GIRXMLDelegate.girType(forName: name) == type, "\(name) should map to \(type)") + } + // Namespace-qualified references keep their namespace for the registry. + #expect(GIRXMLDelegate.girType(forName: "Gtk.Widget") == .typeRef("Widget", namespace: "Gtk")) + #expect(GIRXMLDelegate.girType(forName: "Widget") == .typeRef("Widget", namespace: nil)) + } +} diff --git a/Tests/SwiftGtkGenCoreTests/PropertyAccessorTests.swift b/Tests/SwiftGtkGenCoreTests/PropertyAccessorTests.swift deleted file mode 100644 index 0415f7a..0000000 --- a/Tests/SwiftGtkGenCoreTests/PropertyAccessorTests.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("Readable Int32 property generates correct accessor") -func testReadableInt32Property() throws { - let prop = Property(name: "length", type: .int32, isReadable: true, isWritable: false) - let accessor = CodeGenerator.generatePropertyAccessor(property: prop) - #expect(accessor.contains("g_value_init")) - #expect(accessor.contains("g_value_get_int")) - #expect(accessor.contains("public var length: Int32")) - #expect(!accessor.contains("get {")) - #expect(!accessor.contains("set {")) -} - -@Test("Writable string property generates read-write accessor") -func testWritableStringProperty() throws { - let prop = Property(name: "label", type: .string, isReadable: true, isWritable: true) - let accessor = CodeGenerator.generatePropertyAccessor(property: prop) - #expect(accessor.contains("g_value_set_string")) - #expect(accessor.contains("set {")) - #expect(accessor.contains("get {")) - #expect(accessor.contains("g_value_get_string")) -} - -@Test("Read-only boolean property generates getter only") -func testReadOnlyBooleanProperty() throws { - let prop = Property(name: "visible", type: .boolean, isReadable: true, isWritable: false) - let accessor = CodeGenerator.generatePropertyAccessor(property: prop) - #expect(!accessor.contains("get {")) - #expect(!accessor.contains("set {")) - #expect(accessor.contains("g_value_get_boolean")) -} - -@Test("Write-only property has setter only") -func testWriteOnlyProperty() throws { - let prop = Property(name: "opacity", type: .double, isReadable: false, isWritable: true) - let accessor = CodeGenerator.generatePropertyAccessor(property: prop) - #expect(!accessor.contains("get {")) - #expect(accessor.contains("set {")) - #expect(accessor.contains("g_value_set_double")) -} - -@Test("Construct-only property has no accessor") -func testConstructOnlyProperty() throws { - let prop = Property(name: "type", type: .typeRef("Type"), isReadable: false, isWritable: true, isConstructOnly: true) - let accessor = CodeGenerator.generatePropertyAccessor(property: prop) - #expect(accessor.isEmpty) -} diff --git a/Tests/SwiftGtkGenCoreTests/SignalConnectionTests.swift b/Tests/SwiftGtkGenCoreTests/SignalConnectionTests.swift deleted file mode 100644 index 0dcc0b5..0000000 --- a/Tests/SwiftGtkGenCoreTests/SignalConnectionTests.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Testing -@testable import SwiftGtkGenCore - -@Test("Signal with no parameters generates connection") -func testSignalNoParams() { - let signal = Signal(name: "activate", parameters: [], returnType: .void) - let connection = CodeGenerator.generateSignalConnection(signal: signal) - #expect(connection.contains("g_signal_connect_data")) - #expect(connection.contains("connectActivate")) - #expect(connection.contains("() -> Void")) -} - -@Test("Signal with parameters includes them in handler") -func testSignalWithParams() { - let signal = Signal(name: "value-changed", parameters: [ - Parameter(name: "value", type: .int32, transferOwnership: .none) - ], returnType: .void) - let connection = CodeGenerator.generateSignalConnection(signal: signal) - #expect(connection.contains("connectValueChanged")) - #expect(connection.contains("_: Int32")) - #expect(connection.contains("g_signal_connect_data")) -} - -@Test("Non-inhibit signal generates correct @convention(c) with -> Void") -func testNonInhibitSignalConnection() { - let signal = Signal(name: "clicked", parameters: [], returnType: .void) - let code = CodeGenerator.generateSignalConnection(signal: signal, inhibit: false) - #expect(code.contains("-> Void")) - #expect(code.contains("@convention(c) (UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Void")) -} - -@Test("Parameterized non-inhibit signal generates correct @convention(c)") -func testParameterizedNonInhibitSignalConnection() { - let signal = Signal(name: "size-allocate", parameters: [ - Parameter(name: "width", type: .int32), - Parameter(name: "height", type: .int32), - ], returnType: .void) - let code = CodeGenerator.generateSignalConnection(signal: signal, inhibit: false) - #expect(code.contains("-> Void")) - #expect(code.contains("@convention(c) (UnsafeMutableRawPointer?, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Void")) -} diff --git a/Tests/SwiftGtkGenCoreTests/TypeMapperTests.swift b/Tests/SwiftGtkGenCoreTests/TypeMapperTests.swift new file mode 100644 index 0000000..6323987 --- /dev/null +++ b/Tests/SwiftGtkGenCoreTests/TypeMapperTests.swift @@ -0,0 +1,467 @@ +// TypeMapperTests.swift +// Table-driven tests covering every GIRType the TypeMapper supports and +// every SkipReason it can throw. This is the verification that the single +// GIRType switch produces correct Mapping values — the foundation for +// Rules 2 and 3 of the rearchitecture. + +import Testing + +@testable import SwiftGtkGenCore + +@Suite("TypeMapper") +struct TypeMapperTests { + + // MARK: - Registry helpers + + /// Builds a minimal registry containing representative types of every + /// category the mapper distinguishes: object, interface, enum, bitfield, + /// boxed record, gtype-struct record, plain record, and alias. + func makeContext() -> MapContext { + let glib = Repository(namespaces: [ + Namespace( + name: "GLib", version: "2.0", + records: [ + Record(name: "Bytes", cType: "GBytes", getTypeFunction: "g_bytes_get_type"), + Record(name: "StringChunk", cType: "GStringChunk"), + Record(name: "ObjectClass", cType: "GObjectClass", isGTypeStructFor: "Object"), + ], + aliases: [ + Alias(name: "Strv", cType: "GStrv", target: .cArray(.string, ArrayInfo(isZeroTerminated: true))) + ] + ) + ]) + let gobject = Repository(namespaces: [ + Namespace( + name: "GObject", version: "2.0", + classes: [ + Class(name: "Object", cType: "GObject", parent: nil, + getTypeFunction: "g_object_get_type"), + Class(name: "InitiallyUnowned", cType: "GInitiallyUnowned", parent: "Object", + getTypeFunction: "g_initially_unowned_get_type"), + ], + interfaces: [ + Interface(name: "TypePlugin", cType: "GTypePlugin", + getTypeFunction: "g_type_plugin_get_type") + ], + records: [ + Record(name: "Value", cType: "GValue", getTypeFunction: "g_value_get_type"), + ], + enumerations: [ + Enumeration(name: "ParamFlags", cType: "GParamFlags", + getTypeFunction: "g_param_flags_get_type") + ], + bitfields: [ + Bitfield(name: "SignalFlags", cType: "GSignalFlags", + getTypeFunction: "g_signal_flags_get_type") + ] + ) + ]) + // Include GObject so cross-module references resolve; mark "cairo" as + // an included-but-unloaded namespace so foreign resolution is tested. + let gtkRepo = Repository( + namespaces: [ + Namespace(name: "Gtk", version: "4.0") + ], + includedPackages: [ + IncludeEntry(name: "GObject", version: "2.0"), + IncludeEntry(name: "GLib", version: "2.0"), + IncludeEntry(name: "cairo", version: "1.0"), + ] + ) + let registry = TypeRegistry( + repositories: ["GLib": glib, "GObject": gobject, "Gtk": gtkRepo] + ) + return MapContext(registry: registry, currentModule: "Gtk", currentNamespace: "Gtk") + } + + /// A context where the current module IS the module the type lives in, + /// so `swiftTypeName` returns bare names (no module prefix). + func makeLocalContext() -> MapContext { + let gobject = Repository(namespaces: [ + Namespace( + name: "GObject", version: "2.0", + classes: [ + Class(name: "Object", cType: "GObject", parent: nil, + getTypeFunction: "g_object_get_type"), + ], + enumerations: [ + Enumeration(name: "ParamFlags", cType: "GParamFlags", + getTypeFunction: "g_param_flags_get_type") + ], + bitfields: [ + Bitfield(name: "SignalFlags", cType: "GSignalFlags", + getTypeFunction: "g_signal_flags_get_type") + ] + ) + ]) + let registry = TypeRegistry(repositories: ["GObject": gobject]) + return MapContext(registry: registry, currentModule: "GObject", currentNamespace: "GObject") + } + + // MARK: - Void + + @Test("Void maps correctly") + func voidMapping() throws { + let ctx = makeContext() + let mapping = try map(.void, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "Void") + #expect(mapping.cSwiftType == "Void") + #expect(mapping.marshalIn == .direct) + #expect(mapping.marshalOut == .direct) + #expect(mapping.gvalue == nil) + } + + // MARK: - Boolean + + @Test("Boolean maps with gboolean conversion") + func booleanMapping() throws { + let ctx = makeContext() + let mapping = try map(.boolean, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "Bool") + #expect(mapping.cSwiftType == "Int32") + #expect(mapping.marshalIn == .boolToGboolean) + #expect(mapping.marshalOut == .gbooleanToBool) + #expect(mapping.gvalue?.typeMacro == "G_TYPE_BOOLEAN") + #expect(mapping.gvalue?.getterSuffix == "boolean") + #expect(mapping.gvalue?.setterSuffix == "boolean") + } + + // MARK: - Integer primitives (table-driven) + + struct PrimitiveCase { + let type: GIRType + let swiftType: String + let cSwiftType: String + let gvalueTypeMacro: String? + let gvalueGetter: String? + /// Expected marshalling. Fixed-width types pass through directly; + /// platform-ambiguous widths (`gint64`, `gsize`, `GType`, …) route + /// through `numericCast` so the compiler bridges the C boundary type. + var marshalIn: MarshalIn = .direct + var marshalOut: MarshalOut = .direct + } + + @Test("Signed integers map correctly", arguments: [ + PrimitiveCase(type: .int8, swiftType: "Int8", cSwiftType: "Int8", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .int16, swiftType: "Int16", cSwiftType: "Int16", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .int32, swiftType: "Int32", cSwiftType: "Int32", gvalueTypeMacro: "G_TYPE_INT", gvalueGetter: "int"), + PrimitiveCase(type: .int64, swiftType: "Int", cSwiftType: "Int", gvalueTypeMacro: "G_TYPE_INT64", gvalueGetter: "int64", + marshalIn: .numericCast(targetType: "Int"), marshalOut: .numericCast(fromType: "Int")), + ]) + func signedIntegers(_ tc: PrimitiveCase) throws { + let ctx = makeContext() + let mapping = try map(tc.type, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == tc.swiftType) + #expect(mapping.cSwiftType == tc.cSwiftType) + #expect(mapping.marshalIn == tc.marshalIn) + #expect(mapping.marshalOut == tc.marshalOut) + if let macro = tc.gvalueTypeMacro { + #expect(mapping.gvalue?.typeMacro == macro) + } else { + #expect(mapping.gvalue == nil) + } + } + + @Test("Unsigned integers map correctly", arguments: [ + PrimitiveCase(type: .uint8, swiftType: "UInt8", cSwiftType: "UInt8", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .uint16, swiftType: "UInt16", cSwiftType: "UInt16", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .uint32, swiftType: "UInt32", cSwiftType: "UInt32", gvalueTypeMacro: "G_TYPE_UINT", gvalueGetter: "uint"), + PrimitiveCase(type: .uint64, swiftType: "UInt", cSwiftType: "UInt", gvalueTypeMacro: "G_TYPE_UINT64", gvalueGetter: "uint64", + marshalIn: .numericCast(targetType: "UInt"), marshalOut: .numericCast(fromType: "UInt")), + ]) + func unsignedIntegers(_ tc: PrimitiveCase) throws { + let ctx = makeContext() + let mapping = try map(tc.type, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == tc.swiftType) + #expect(mapping.cSwiftType == tc.cSwiftType) + #expect(mapping.marshalIn == tc.marshalIn) + #expect(mapping.marshalOut == tc.marshalOut) + } + + @Test("Platform-width integers map correctly", arguments: [ + PrimitiveCase(type: .long, swiftType: "Int", cSwiftType: "Int", gvalueTypeMacro: "G_TYPE_LONG", gvalueGetter: "long"), + PrimitiveCase(type: .ulong, swiftType: "UInt", cSwiftType: "UInt", gvalueTypeMacro: "G_TYPE_ULONG", gvalueGetter: "ulong"), + PrimitiveCase(type: .size, swiftType: "UInt", cSwiftType: "UInt", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .ssize, swiftType: "Int", cSwiftType: "Int", gvalueTypeMacro: nil, gvalueGetter: nil), + ]) + func platformWidthIntegers(_ tc: PrimitiveCase) throws { + let ctx = makeContext() + let mapping = try map(tc.type, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == tc.swiftType) + #expect(mapping.cSwiftType == tc.cSwiftType) + } + + @Test("Character types map correctly", arguments: [ + PrimitiveCase(type: .char, swiftType: "Int8", cSwiftType: "Int8", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .uchar, swiftType: "UInt8", cSwiftType: "UInt8", gvalueTypeMacro: nil, gvalueGetter: nil), + PrimitiveCase(type: .unichar, swiftType: "UInt32", cSwiftType: "UInt32", gvalueTypeMacro: nil, gvalueGetter: nil), + ]) + func characterTypes(_ tc: PrimitiveCase) throws { + let ctx = makeContext() + let mapping = try map(tc.type, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == tc.swiftType) + } + + @Test("Floating-point types map correctly", arguments: [ + PrimitiveCase(type: .float, swiftType: "Float", cSwiftType: "Float", gvalueTypeMacro: "G_TYPE_FLOAT", gvalueGetter: "float"), + PrimitiveCase(type: .double, swiftType: "Double", cSwiftType: "Double", gvalueTypeMacro: "G_TYPE_DOUBLE", gvalueGetter: "double"), + ]) + func floatingPointTypes(_ tc: PrimitiveCase) throws { + let ctx = makeContext() + let mapping = try map(tc.type, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == tc.swiftType) + } + + // MARK: - GType + + @Test("GType maps with gtype GValue ops") + func gtypeMapping() throws { + let ctx = makeContext() + let mapping = try map(.gtype, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "UInt") + #expect(mapping.cSwiftType == "UInt") + #expect(mapping.marshalIn == .numericCast(targetType: "UInt")) + #expect(mapping.marshalOut == .numericCast(fromType: "UInt")) + #expect(mapping.gvalue?.typeMacro == "G_TYPE_GTYPE") + } + + // MARK: - Pointer + + @Test("Pointer maps to UnsafeMutableRawPointer?") + func pointerMapping() throws { + let ctx = makeContext() + let mapping = try map(.pointer, nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "UnsafeMutableRawPointer?") + #expect(mapping.cSwiftType == "UnsafeMutableRawPointer?") + #expect(mapping.marshalIn == .direct) + #expect(mapping.marshalOut == .direct) + #expect(mapping.gvalue?.typeMacro == "G_TYPE_POINTER") + } + + // MARK: - String with transfer ownership + + @Test("String copy-free tracks transfer=full") + func stringTransferFull() throws { + let ctx = makeContext() + let mapping = try map(.string, nullable: false, transfer: .full, context: ctx) + #expect(mapping.marshalOut == .stringCopy(free: true)) + } + + @Test("String copy-free tracks transfer=none") + func stringTransferNone() throws { + let ctx = makeContext() + let mapping = try map(.string, nullable: false, transfer: .none, context: ctx) + #expect(mapping.marshalOut == .stringCopy(free: false)) + } + + // MARK: - Nullable wrapping + + @Test("Nullable string becomes Optional") + func nullableString() throws { + let ctx = makeContext() + let mapping = try map(.string, nullable: true, transfer: .none, context: ctx) + #expect(mapping.swiftType == "String?") + #expect(mapping.cSwiftType == "UnsafePointer?") + } + + @Test("Nullable int stays non-optional (value type)") + func nullableInt() throws { + let ctx = makeContext() + let mapping = try map(.int32, nullable: true, transfer: .none, context: ctx) + // Value types don't carry nullable semantics — the optionalised + // wrapper is applied mechanically, but GIR shouldn't annotate ints + // as nullable in practice. + #expect(mapping.swiftType == "Int32?") + } + + // MARK: - Type references + + @Test("Object typeRef maps to pointer wrapper") + func objectTypeRef() throws { + let ctx = makeContext() + let mapping = try map(.typeRef("Object", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "GObject.Object") + #expect(mapping.cSwiftType == "UnsafeMutableRawPointer?") + #expect(mapping.marshalIn == .objectPointer) + #expect(mapping.marshalOut == .objectWrap(sink: false)) + } + + @Test("Object typeRef is bare in local module") + func objectTypeRefLocal() throws { + let ctx = makeLocalContext() + let mapping = try map(.typeRef("Object", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "Object") + } + + @Test("Interface typeRef maps to pointer wrapper") + func interfaceTypeRef() throws { + let ctx = makeContext() + let mapping = try map(.typeRef("TypePlugin", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "GObject.TypePlugin") + #expect(mapping.marshalIn == .objectPointer) + } + + @Test("Enum typeRef maps to enum raw-value wrapping") + func enumTypeRef() throws { + let ctx = makeContext() + let mapping = try map(.typeRef("ParamFlags", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "GObject.ParamFlags") + #expect(mapping.cSwiftType == "GParamFlags") + #expect(mapping.marshalIn == .enumRaw) + #expect(mapping.marshalOut == .enumFromRaw(swiftType: "GObject.ParamFlags")) + #expect(mapping.gvalue?.typeMacro == "G_TYPE_ENUM") + } + + @Test("Bitfield typeRef maps to OptionSet raw-value wrapping") + func bitfieldTypeRef() throws { + let ctx = makeContext() + let mapping = try map(.typeRef("SignalFlags", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "GObject.SignalFlags") + #expect(mapping.cSwiftType == "GSignalFlags") + #expect(mapping.marshalIn == .bitfieldRaw) + #expect(mapping.marshalOut == .bitfieldFromRaw(swiftType: "GObject.SignalFlags")) + #expect(mapping.gvalue?.typeMacro == "G_TYPE_FLAGS") + } + + @Test("Boxed record typeRef maps to pointer wrapper with copy semantics") + func boxedRecordTypeRef() throws { + let ctx = makeContext() + let mapping = try map(.typeRef("Value", namespace: "GObject"), + nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "GObject.Value") + #expect(mapping.cSwiftType == "UnsafeMutableRawPointer?") + #expect(mapping.marshalIn == .boxedPointer) + #expect(mapping.marshalOut == .boxedWrap(copy: true)) // transfer != .full → copy + #expect(mapping.gvalue?.typeMacro == "G_TYPE_BOXED") + } + + // MARK: - Alias following + + @Test("Alias follows to underlying type") + func aliasFollowsToUnderlying() throws { + let ctx = makeContext() + // GLib.Strv is an alias for a zero-terminated string array. + // Without array bridging, this throws .arrayWithoutLength — but the + // alias is *followed*, which is what this test asserts. + do { + _ = try map(.typeRef("Strv", namespace: "GLib"), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected arrayWithoutLength error") + } catch { + #expect(error.reason == .arrayWithoutLength) + } + } + + // MARK: - Error cases: every SkipReason the mapper can throw + + @Test("vaList throws varargs") + func vaListThrowsVarargs() { + let ctx = makeContext() + do { + _ = try map(.vaList, nullable: false, transfer: .none, context: ctx) + Issue.record("Expected varargs error") + } catch { + #expect(error.reason == .varargs) + } + } + + @Test("Container throws containerType") + func containerThrowsContainerType() { + let ctx = makeContext() + do { + _ = try map(.container(.list, elements: [.int32]), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected containerType error") + } catch { + #expect(error.reason == .containerType) + } + } + + @Test("cArray without length throws arrayWithoutLength") + func cArrayWithoutLength() { + let ctx = makeContext() + do { + _ = try map(.cArray(.int32, ArrayInfo()), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected arrayWithoutLength error") + } catch { + #expect(error.reason == .arrayWithoutLength) + } + } + + @Test("cArray with length throws arrayWithoutLength (not yet bridged)") + func cArrayWithLengthNotYetBridged() { + let ctx = makeContext() + do { + _ = try map(.cArray(.int32, ArrayInfo(lengthParameterIndex: 0)), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected arrayWithoutLength error") + } catch { + #expect(error.reason == .arrayWithoutLength) + } + } + + @Test("Foreign namespace typeRef throws foreignNamespace") + func foreignNamespace() { + let ctx = makeContext() + do { + _ = try map(.typeRef("Context", namespace: "cairo"), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected foreignNamespace error") + } catch { + #expect(error.reason == .foreignNamespace) + } + } + + @Test("Unknown typeRef throws unknownType") + func unknownTypeRef() { + let ctx = makeContext() + // Gtk namespace is loaded but names no "FluxCapacitor" + do { + _ = try map(.typeRef("FluxCapacitor", namespace: "Gtk"), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected unknownType error") + } catch { + #expect(error.reason == .unknownType) + } + } + + @Test("GType struct throws gtypeStruct") + func gtypeStructThrows() { + let ctx = makeContext() + do { + _ = try map(.typeRef("ObjectClass", namespace: "GLib"), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected gtypeStruct error") + } catch { + #expect(error.reason == .gtypeStruct) + } + } + + @Test("Plain record throws plainRecord") + func plainRecordThrows() { + let ctx = makeContext() + // GLib.StringChunk has no getTypeFunction → plainRecord + do { + _ = try map(.typeRef("StringChunk", namespace: "GLib"), + nullable: false, transfer: .none, context: ctx) + Issue.record("Expected plainRecord error") + } catch { + #expect(error.reason == .plainRecord) + } + } + + // MARK: - Optional unwrapping + + @Test("Optional unwraps and nullableises") + func optionalUnwrapping() throws { + let ctx = makeContext() + let mapping = try map(.optional(.string), nullable: false, transfer: .none, context: ctx) + #expect(mapping.swiftType == "String?") + } +} diff --git a/Tests/SwiftGtkGenCoreTests/TypeRegistryTests.swift b/Tests/SwiftGtkGenCoreTests/TypeRegistryTests.swift new file mode 100644 index 0000000..3b4194d --- /dev/null +++ b/Tests/SwiftGtkGenCoreTests/TypeRegistryTests.swift @@ -0,0 +1,196 @@ +// TypeRegistryTests.swift +// The registry is what makes cross-namespace inheritance and precise type +// classification possible. These tests pin the behaviours the planner relies +// on: namespace-crossing ancestry, InitiallyUnowned detection (which drives +// floating-reference sinking), foreign-namespace resolution, and category +// classification driven by GIR metadata rather than names. + +import Testing + +@testable import SwiftGtkGenCore + +@Suite("TypeRegistry") +struct TypeRegistryTests { + /// Builds a two-module registry mirroring the real GObject/Gtk split: + /// `Gtk.Widget` inherits `GObject.InitiallyUnowned` across a module + /// boundary, which is exactly the case the old generator severed. + private func makeRegistry() -> TypeRegistry { + let gobject = Repository(namespaces: [ + Namespace( + name: "GObject", version: "2.0", + classes: [ + Class( + name: "Object", cType: "GObject", parent: nil, + getTypeFunction: "g_object_get_type"), + Class( + name: "InitiallyUnowned", cType: "GInitiallyUnowned", parent: "Object", + getTypeFunction: "g_initially_unowned_get_type"), + ], + records: [ + Record(name: "Value", cType: "GValue", getTypeFunction: "g_value_get_type"), + Record(name: "ObjectClass", cType: "GObjectClass", isGTypeStructFor: "Object"), + ] + ) + ]) + let gtk = Repository( + namespaces: [ + Namespace( + name: "Gtk", version: "4.0", + classes: [ + Class( + name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned", + isAbstract: true, getTypeFunction: "gtk_widget_get_type", + implements: ["Buildable"]), + Class( + name: "Label", cType: "GtkLabel", parent: "Widget", + getTypeFunction: "gtk_label_get_type"), + ], + interfaces: [ + Interface( + name: "Buildable", cType: "GtkBuildable", + getTypeFunction: "gtk_buildable_get_type") + ], + enumerations: [ + Enumeration(name: "Align", cType: "GtkAlign", getTypeFunction: "gtk_align_get_type") + ], + bitfields: [ + Bitfield( + name: "StateFlags", cType: "GtkStateFlags", + getTypeFunction: "gtk_state_flags_get_type") + ] + ) + ], + // Gdk and cairo are included but never loaded: both are foreign. + includedPackages: [ + IncludeEntry(name: "GObject", version: "2.0"), + IncludeEntry(name: "cairo", version: "1.0"), + ] + ) + return TypeRegistry(repositories: ["GObject": gobject, "Gtk": gtk]) + } + + @Test("Unqualified references resolve against their declaring namespace") + func resolvesUnqualifiedReferences() { + let registry = makeRegistry() + let widget = registry.resolve(.typeRef("Widget"), from: "Gtk") + #expect(widget?.girName == "Gtk.Widget") + #expect(widget?.swiftModule == "Gtk") + // The same bare name written from another namespace does not resolve. + #expect(registry.resolve(.typeRef("Widget"), from: "GObject") == nil) + } + + @Test("Qualified references resolve across namespaces") + func resolvesQualifiedReferences() { + let registry = makeRegistry() + let object = registry.resolve(.typeRef("Object", namespace: "GObject"), from: "Gtk") + #expect(object?.girName == "GObject.Object") + #expect(object?.swiftModule == "GObject") + } + + @Test("Ancestry crosses namespace boundaries") + func ancestryCrossesNamespaces() { + let registry = makeRegistry() + #expect( + registry.ancestry(of: "Gtk.Label").map(\.girName) + == ["Gtk.Widget", "GObject.InitiallyUnowned", "GObject.Object"]) + #expect(registry.ancestry(of: "GObject.Object").isEmpty) + } + + @Test("InitiallyUnowned ancestry drives floating-reference sinking") + func detectsInitiallyUnownedAncestry() { + let registry = makeRegistry() + #expect(registry.descendsFromInitiallyUnowned("Gtk.Widget")) + #expect(registry.descendsFromInitiallyUnowned("Gtk.Label")) + #expect(registry.descendsFromInitiallyUnowned("GObject.InitiallyUnowned")) + // A plain GObject is not floating: its constructors must not sink. + #expect(!registry.descendsFromInitiallyUnowned("GObject.Object")) + #expect(registry.isGObject("Gtk.Label")) + } + + @Test("Types from unloaded namespaces resolve as foreign") + func resolvesForeignNamespaces() { + let registry = makeRegistry() + #expect(registry.foreign.contains("cairo")) + let context = registry.resolve(.typeRef("Context", namespace: "cairo"), from: "Gtk") + #expect(context?.category == .foreign(namespace: "cairo")) + // An unknown name in a *loaded* namespace is not foreign — it is + // genuinely unknown, and must be reported as such, not guessed at. + #expect(registry.resolve(.typeRef("Nonexistent", namespace: "Gtk"), from: "Gtk") == nil) + } + + @Test("Categories follow GIR metadata") + func classifiesCategories() { + let registry = makeRegistry() + #expect( + registry.resolve(girName: "Gtk.Widget")?.category + == .object( + parentGIRName: "GObject.InitiallyUnowned", isAbstract: true, + isFinal: false, interfaces: ["Gtk.Buildable"])) + #expect(registry.resolve(girName: "Gtk.Buildable")?.category == .interface(prereqs: [])) + #expect(registry.resolve(girName: "Gtk.Align")?.category == .enumeration(hasGType: true)) + #expect(registry.resolve(girName: "Gtk.StateFlags")?.category == .bitfield(hasGType: true)) + #expect( + registry.resolve(girName: "GObject.Value")?.category + == .boxedRecord(copyFunction: nil, freeFunction: nil)) + #expect( + registry.resolve(girName: "GObject.ObjectClass")?.category + == .gtypeStruct(forType: "GObject.Object")) + } + + @Test("Pointer-backing distinguishes wrapper types from value types") + func identifiesPointerBackedTypes() { + let registry = makeRegistry() + #expect(registry.resolve(girName: "Gtk.Widget")?.isPointerBacked == true) + #expect(registry.resolve(girName: "Gtk.Buildable")?.isPointerBacked == true) + #expect(registry.resolve(girName: "GObject.Value")?.isPointerBacked == true) + #expect(registry.resolve(girName: "Gtk.Align")?.isPointerBacked == false) + #expect(registry.resolve(girName: "Gtk.StateFlags")?.isPointerBacked == false) + } + + @Test("Subclassed types are computed registry-wide, across modules") + func computesSubclassedTypesAcrossModules() { + let registry = makeRegistry() + let subclassed = registry.subclassedTypes() + // GObject.InitiallyUnowned is subclassed only from *another* module. + // It must still be `open`, or Gtk.Widget cannot inherit from it. + #expect(subclassed.contains("GObject.InitiallyUnowned")) + #expect(subclassed.contains("GObject.Object")) + #expect(subclassed.contains("Gtk.Widget")) + #expect(!subclassed.contains("Gtk.Label")) + } + + @Test("Swift spelling qualifies only cross-module references") + func spellsSwiftTypeNames() throws { + let registry = makeRegistry() + let object = try #require(registry.resolve(girName: "GObject.Object")) + let widget = try #require(registry.resolve(girName: "Gtk.Widget")) + #expect(registry.swiftTypeName(for: object, in: "Gtk") == "GObject.Object") + #expect(registry.swiftTypeName(for: object, in: "GObject") == "Object") + #expect(registry.swiftTypeName(for: widget, in: "Gtk") == "Widget") + } + + @Test("Manually excluded namespaces are treated as foreign") + func manualNamespacesAreForeign() { + let repo = Repository(namespaces: [ + Namespace( + name: "Gtk", version: "4.0", + classes: [Class(name: "Widget", cType: "GtkWidget", parent: nil)]) + ]) + let registry = TypeRegistry(repositories: ["Gtk": repo], manualNamespaces: ["Gtk"]) + #expect(registry.resolve(girName: "Gtk.Widget")?.category == .foreign(namespace: "Gtk")) + } + + @Test("Malformed parent cycles terminate ancestry instead of hanging") + func ancestryTerminatesOnCycles() { + let repo = Repository(namespaces: [ + Namespace( + name: "Bad", version: "1.0", + classes: [ + Class(name: "A", cType: "BadA", parent: "B"), + Class(name: "B", cType: "BadB", parent: "A"), + ]) + ]) + let registry = TypeRegistry(repositories: ["Bad": repo]) + #expect(registry.ancestry(of: "Bad.A").map(\.girName) == ["Bad.B"]) + } +} diff --git a/configs/tier1.toml b/configs/tier1.toml new file mode 100644 index 0000000..4f900ae --- /dev/null +++ b/configs/tier1.toml @@ -0,0 +1,8 @@ +# Compile-gate tier 1: the foundation libraries. +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" diff --git a/configs/tier2.toml b/configs/tier2.toml new file mode 100644 index 0000000..02683e5 --- /dev/null +++ b/configs/tier2.toml @@ -0,0 +1,14 @@ +# Compile-gate tier 2: tier 1 + GIO (and GModule, which Gio's GIR includes). +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" + +[packages.GModule] +gir = "/usr/share/gir-1.0/GModule-2.0.gir" + +[packages.Gio] +gir = "/usr/share/gir-1.0/Gio-2.0.gir" diff --git a/configs/tier3.toml b/configs/tier3.toml new file mode 100644 index 0000000..a77eeee --- /dev/null +++ b/configs/tier3.toml @@ -0,0 +1,25 @@ +# Compile-gate tier 3: tier 2 + text/image foundations. +# cairo, HarfBuzz, freetype2, and fontconfig have no GIR on this system and +# resolve as foreign namespaces (skipped with reasons). +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" + +[packages.GModule] +gir = "/usr/share/gir-1.0/GModule-2.0.gir" + +[packages.Gio] +gir = "/usr/share/gir-1.0/Gio-2.0.gir" + +[packages.Pango] +gir = "/usr/share/gir-1.0/Pango-1.0.gir" + +[packages.GdkPixbuf] +gir = "/usr/share/gir-1.0/GdkPixbuf-2.0.gir" + +[packages.Graphene] +gir = "/usr/share/gir-1.0/Graphene-1.0.gir" diff --git a/configs/tier4.toml b/configs/tier4.toml new file mode 100644 index 0000000..802e7a9 --- /dev/null +++ b/configs/tier4.toml @@ -0,0 +1,29 @@ +# Compile-gate tier 4: tier 3 + GDK and GSK. +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" + +[packages.GModule] +gir = "/usr/share/gir-1.0/GModule-2.0.gir" + +[packages.Gio] +gir = "/usr/share/gir-1.0/Gio-2.0.gir" + +[packages.Pango] +gir = "/usr/share/gir-1.0/Pango-1.0.gir" + +[packages.GdkPixbuf] +gir = "/usr/share/gir-1.0/GdkPixbuf-2.0.gir" + +[packages.Graphene] +gir = "/usr/share/gir-1.0/Graphene-1.0.gir" + +[packages.Gdk] +gir = "/usr/share/gir-1.0/Gdk-4.0.gir" + +[packages.Gsk] +gir = "/usr/share/gir-1.0/Gsk-4.0.gir" diff --git a/configs/tier5.toml b/configs/tier5.toml new file mode 100644 index 0000000..7e13e84 --- /dev/null +++ b/configs/tier5.toml @@ -0,0 +1,32 @@ +# Compile-gate tier 5: tier 4 + GTK 4. +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" + +[packages.GModule] +gir = "/usr/share/gir-1.0/GModule-2.0.gir" + +[packages.Gio] +gir = "/usr/share/gir-1.0/Gio-2.0.gir" + +[packages.Pango] +gir = "/usr/share/gir-1.0/Pango-1.0.gir" + +[packages.GdkPixbuf] +gir = "/usr/share/gir-1.0/GdkPixbuf-2.0.gir" + +[packages.Graphene] +gir = "/usr/share/gir-1.0/Graphene-1.0.gir" + +[packages.Gdk] +gir = "/usr/share/gir-1.0/Gdk-4.0.gir" + +[packages.Gsk] +gir = "/usr/share/gir-1.0/Gsk-4.0.gir" + +[packages.Gtk] +gir = "/usr/share/gir-1.0/Gtk-4.0.gir" diff --git a/configs/tier6.toml b/configs/tier6.toml new file mode 100644 index 0000000..fa86a3b --- /dev/null +++ b/configs/tier6.toml @@ -0,0 +1,41 @@ +# Compile-gate tier 6: tier 5 + libadwaita, Soup, and GStreamer core. +# Output directory is supplied by scripts/compile-gate.sh via --output. + +[packages.GLib] +gir = "/usr/share/gir-1.0/GLib-2.0.gir" + +[packages.GObject] +gir = "/usr/share/gir-1.0/GObject-2.0.gir" + +[packages.GModule] +gir = "/usr/share/gir-1.0/GModule-2.0.gir" + +[packages.Gio] +gir = "/usr/share/gir-1.0/Gio-2.0.gir" + +[packages.Pango] +gir = "/usr/share/gir-1.0/Pango-1.0.gir" + +[packages.GdkPixbuf] +gir = "/usr/share/gir-1.0/GdkPixbuf-2.0.gir" + +[packages.Graphene] +gir = "/usr/share/gir-1.0/Graphene-1.0.gir" + +[packages.Gdk] +gir = "/usr/share/gir-1.0/Gdk-4.0.gir" + +[packages.Gsk] +gir = "/usr/share/gir-1.0/Gsk-4.0.gir" + +[packages.Gtk] +gir = "/usr/share/gir-1.0/Gtk-4.0.gir" + +[packages.Adw] +gir = "/usr/share/gir-1.0/Adw-1.gir" + +[packages.Soup] +gir = "/usr/share/gir-1.0/Soup-3.0.gir" + +[packages.Gst] +gir = "/usr/share/gir-1.0/Gst-1.0.gir" diff --git a/docs/regression-baseline.txt b/docs/regression-baseline.txt deleted file mode 100644 index d81c631..0000000 --- a/docs/regression-baseline.txt +++ /dev/null @@ -1,11 +0,0 @@ -Generated file count: 932 -Total build errors: 676,162 -Cannot find errors (dependency, ignored): 268,626 -Fixable build errors: 407,536 -Lint errors: 0 - -Captured after fix: `open class` (no `public` prefix) for non-final classes. - -Remaining fixable errors are in categories that have not been addressed yet -(signal closure type mismatches, Int32 vs UInt32, missing arguments, etc.). -These are not regressions — they are the planned next phase of work. diff --git a/docs/skip-baseline/tier1/GLib.json b/docs/skip-baseline/tier1/GLib.json index 47c71ca..e80fb92 100644 --- a/docs/skip-baseline/tier1/GLib.json +++ b/docs/skip-baseline/tier1/GLib.json @@ -8,7 +8,7 @@ }, { "cIdentifier" : "GArray", - "detail" : "boxed record planned for Phase C4", + "detail" : "record name 'Array' shadows Swift stdlib type", "reason" : "unknownType", "symbol" : "GLib.Array" }, @@ -18,24 +18,6 @@ "reason" : "plainRecord", "symbol" : "GLib.AsyncQueue" }, - { - "cIdentifier" : "GBookmarkFile", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.BookmarkFile" - }, - { - "cIdentifier" : "GByteArray", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.ByteArray" - }, - { - "cIdentifier" : "GBytes", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Bytes" - }, { "cIdentifier" : "GCache", "detail" : "no GType registration", @@ -60,12 +42,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.CacheNewFunc" }, - { - "cIdentifier" : "GChecksum", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Checksum" - }, { "cIdentifier" : "GChildWatchFunc", "detail" : "callback planned for Phase D2", @@ -134,16 +110,10 @@ }, { "cIdentifier" : "GDate", - "detail" : "boxed record planned for Phase C4", + "detail" : "record name 'Date' shadows Swift stdlib type", "reason" : "unknownType", "symbol" : "GLib.Date" }, - { - "cIdentifier" : "GDateTime", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.DateTime" - }, { "cIdentifier" : "GDebugKey", "detail" : "no GType registration", @@ -156,12 +126,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.DestroyNotify" }, - { - "cIdentifier" : "GDir", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Dir" - }, { "cIdentifier" : "GDuplicateFunc", "detail" : "callback planned for Phase D2", @@ -182,7 +146,7 @@ }, { "cIdentifier" : "GError", - "detail" : "boxed record planned for Phase C4", + "detail" : "record name 'Error' shadows Swift stdlib type", "reason" : "unknownType", "symbol" : "GLib.Error" }, @@ -234,24 +198,12 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.HashFunc" }, - { - "cIdentifier" : "GHashTable", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.HashTable" - }, { "cIdentifier" : "GHashTableIter", "detail" : "no GType registration", "reason" : "plainRecord", "symbol" : "GLib.HashTableIter" }, - { - "cIdentifier" : "GHmac", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Hmac" - }, { "cIdentifier" : "GHook", "detail" : "no GType registration", @@ -312,12 +264,6 @@ "reason" : "plainRecord", "symbol" : "GLib.IConv" }, - { - "cIdentifier" : "GIOChannel", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.IOChannel" - }, { "cIdentifier" : "GIOFunc", "detail" : "callback planned for Phase D2", @@ -330,12 +276,6 @@ "reason" : "plainRecord", "symbol" : "GLib.IOFuncs" }, - { - "cIdentifier" : "GKeyFile", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.KeyFile" - }, { "cIdentifier" : "GList", "detail" : "no GType registration", @@ -360,42 +300,12 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.LogWriterFunc" }, - { - "cIdentifier" : "GMainContext", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.MainContext" - }, - { - "cIdentifier" : "GMainLoop", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.MainLoop" - }, - { - "cIdentifier" : "GMappedFile", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.MappedFile" - }, - { - "cIdentifier" : "GMarkupParseContext", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.MarkupParseContext" - }, { "cIdentifier" : "GMarkupParser", "detail" : "no GType registration", "reason" : "plainRecord", "symbol" : "GLib.MarkupParser" }, - { - "cIdentifier" : "GMatchInfo", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.MatchInfo" - }, { "cIdentifier" : "GMemChunk", "detail" : "no GType registration", @@ -456,12 +366,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.OptionErrorFunc" }, - { - "cIdentifier" : "GOptionGroup", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.OptionGroup" - }, { "cIdentifier" : "GOptionParseFunc", "detail" : "callback planned for Phase D2", @@ -474,18 +378,6 @@ "reason" : "plainRecord", "symbol" : "GLib.PathBuf" }, - { - "cIdentifier" : "GPatternSpec", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.PatternSpec" - }, - { - "cIdentifier" : "GPollFD", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.PollFD" - }, { "cIdentifier" : "GPollFunc", "detail" : "callback planned for Phase D2", @@ -504,12 +396,6 @@ "reason" : "plainRecord", "symbol" : "GLib.Private" }, - { - "cIdentifier" : "GPtrArray", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.PtrArray" - }, { "cIdentifier" : "GQueue", "detail" : "no GType registration", @@ -522,24 +408,12 @@ "reason" : "plainRecord", "symbol" : "GLib.RWLock" }, - { - "cIdentifier" : "GRand", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Rand" - }, { "cIdentifier" : "GRecMutex", "detail" : "no GType registration", "reason" : "plainRecord", "symbol" : "GLib.RecMutex" }, - { - "cIdentifier" : "GRegex", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Regex" - }, { "cIdentifier" : "GRegexEvalCallback", "detail" : "callback planned for Phase D2", @@ -594,12 +468,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.SequenceIterCompareFunc" }, - { - "cIdentifier" : "GSource", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Source" - }, { "cIdentifier" : "GSourceCallbackFuncs", "detail" : "no GType registration", @@ -704,7 +572,7 @@ }, { "cIdentifier" : "GString", - "detail" : "boxed record planned for Phase C4", + "detail" : "record name 'String' shadows Swift stdlib type", "reason" : "unknownType", "symbol" : "GLib.String" }, @@ -714,12 +582,6 @@ "reason" : "plainRecord", "symbol" : "GLib.StringChunk" }, - { - "cIdentifier" : "GStrvBuilder", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.StrvBuilder" - }, { "cIdentifier" : "GTestCase", "detail" : "no GType registration", @@ -774,12 +636,6 @@ "reason" : "plainRecord", "symbol" : "GLib.TestSuite" }, - { - "cIdentifier" : "GThread", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Thread" - }, { "cIdentifier" : "GThreadFunc", "detail" : "callback planned for Phase D2", @@ -810,12 +666,6 @@ "reason" : "plainRecord", "symbol" : "GLib.TimeVal" }, - { - "cIdentifier" : "GTimeZone", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.TimeZone" - }, { "cIdentifier" : "GTimer", "detail" : "no GType registration", @@ -846,12 +696,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GLib.TraverseNodeFunc" }, - { - "cIdentifier" : "GTree", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Tree" - }, { "cIdentifier" : "GTreeNode", "detail" : "no GType registration", @@ -864,48 +708,18 @@ "reason" : "plainRecord", "symbol" : "GLib.Tuples" }, - { - "cIdentifier" : "GUri", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Uri" - }, { "cIdentifier" : "GUriParamsIter", "detail" : "no GType registration", "reason" : "plainRecord", "symbol" : "GLib.UriParamsIter" }, - { - "cIdentifier" : "GVariant", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.Variant" - }, - { - "cIdentifier" : "GVariantBuilder", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.VariantBuilder" - }, - { - "cIdentifier" : "GVariantDict", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.VariantDict" - }, { "cIdentifier" : "GVariantIter", "detail" : "no GType registration", "reason" : "plainRecord", "symbol" : "GLib.VariantIter" }, - { - "cIdentifier" : "GVariantType", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GLib.VariantType" - }, { "cIdentifier" : "GVoidFunc", "detail" : "callback planned for Phase D2", @@ -914,4354 +728,2596 @@ }, { "cIdentifier" : "g_access", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_access' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.access" }, - { - "cIdentifier" : "g_aligned_alloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.aligned_alloc" - }, - { - "cIdentifier" : "g_aligned_alloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.aligned_alloc0" - }, - { - "cIdentifier" : "g_aligned_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.aligned_free" - }, - { - "cIdentifier" : "g_aligned_free_sized", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.aligned_free_sized" - }, { "cIdentifier" : "g_array_new_take", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.array_new_take" }, { "cIdentifier" : "g_array_new_take_zero_terminated", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.array_new_take_zero_terminated" }, - { - "cIdentifier" : "g_ascii_digit_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_digit_value" - }, { "cIdentifier" : "g_ascii_dtostr", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'buffer' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.ascii_dtostr" }, { "cIdentifier" : "g_ascii_formatd", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'buffer' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.ascii_formatd" }, - { - "cIdentifier" : "g_ascii_strcasecmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_strcasecmp" - }, - { - "cIdentifier" : "g_ascii_strdown", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_strdown" - }, { "cIdentifier" : "g_ascii_string_to_signed", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.ascii_string_to_signed" }, { "cIdentifier" : "g_ascii_string_to_unsigned", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.ascii_string_to_unsigned" }, - { - "cIdentifier" : "g_ascii_strncasecmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_strncasecmp" - }, { "cIdentifier" : "g_ascii_strtod", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'endptr' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.ascii_strtod" }, { "cIdentifier" : "g_ascii_strtoll", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'endptr' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.ascii_strtoll" }, { "cIdentifier" : "g_ascii_strtoull", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'endptr' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.ascii_strtoull" }, - { - "cIdentifier" : "g_ascii_strup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_strup" - }, - { - "cIdentifier" : "g_ascii_tolower", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_tolower" - }, - { - "cIdentifier" : "g_ascii_toupper", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_toupper" - }, - { - "cIdentifier" : "g_ascii_xdigit_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ascii_xdigit_value" - }, - { - "cIdentifier" : "g_assert_warning", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.assert_warning" - }, - { - "cIdentifier" : "g_assertion_message", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.assertion_message" - }, - { - "cIdentifier" : "g_assertion_message_cmpint", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.assertion_message_cmpint" - }, { "cIdentifier" : "g_assertion_message_cmpnum", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'arg1': unresolved type 'GLib.long double'", "reason" : "unknownType", "symbol" : "GLib.assertion_message_cmpnum" }, - { - "cIdentifier" : "g_assertion_message_cmpstr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.assertion_message_cmpstr" - }, { "cIdentifier" : "g_assertion_message_cmpstrv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'arg1' is not a single const input string ('const char* const*')", "reason" : "unknownType", "symbol" : "GLib.assertion_message_cmpstrv" }, { "cIdentifier" : "g_assertion_message_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'error' type 'Error' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.assertion_message_error" }, { "cIdentifier" : "g_assertion_message_expr", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.assertion_message_expr" }, { "cIdentifier" : "g_async_queue_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GLib.AsyncQueue' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.async_queue_new" }, { "cIdentifier" : "g_async_queue_new_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'item_free_func': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.async_queue_new_full" }, { "cIdentifier" : "g_atexit", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'func': callback 'GLib.VoidFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.atexit" }, { "cIdentifier" : "g_atomic_int_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_add" }, { "cIdentifier" : "g_atomic_int_and", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile guint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_and" }, { "cIdentifier" : "g_atomic_int_compare_and_exchange", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_compare_and_exchange" }, { "cIdentifier" : "g_atomic_int_compare_and_exchange_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_compare_and_exchange_full" }, { "cIdentifier" : "g_atomic_int_dec_and_test", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_dec_and_test" }, { "cIdentifier" : "g_atomic_int_exchange", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_exchange" }, { "cIdentifier" : "g_atomic_int_exchange_and_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_exchange_and_add" }, { "cIdentifier" : "g_atomic_int_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile const gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_get" }, { "cIdentifier" : "g_atomic_int_inc", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_inc" }, { "cIdentifier" : "g_atomic_int_or", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile guint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_or" }, { "cIdentifier" : "g_atomic_int_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_set" }, { "cIdentifier" : "g_atomic_int_xor", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'volatile guint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_int_xor" }, { "cIdentifier" : "g_atomic_pointer_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_add" }, { "cIdentifier" : "g_atomic_pointer_and", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_and" }, { "cIdentifier" : "g_atomic_pointer_compare_and_exchange", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_compare_and_exchange" }, { "cIdentifier" : "g_atomic_pointer_compare_and_exchange_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_compare_and_exchange_full" }, { "cIdentifier" : "g_atomic_pointer_exchange", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_exchange" }, { "cIdentifier" : "g_atomic_pointer_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_get" }, { "cIdentifier" : "g_atomic_pointer_or", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_or" }, { "cIdentifier" : "g_atomic_pointer_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_set" }, { "cIdentifier" : "g_atomic_pointer_xor", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'atomic' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_pointer_xor" }, - { - "cIdentifier" : "g_atomic_rc_box_acquire", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_acquire" - }, - { - "cIdentifier" : "g_atomic_rc_box_alloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_alloc" - }, - { - "cIdentifier" : "g_atomic_rc_box_alloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_alloc0" - }, - { - "cIdentifier" : "g_atomic_rc_box_dup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_dup" - }, - { - "cIdentifier" : "g_atomic_rc_box_get_size", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_get_size" - }, - { - "cIdentifier" : "g_atomic_rc_box_release", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.atomic_rc_box_release" - }, { "cIdentifier" : "g_atomic_rc_box_release_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'clear_func': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.atomic_rc_box_release_full" }, { "cIdentifier" : "g_atomic_ref_count_compare", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'arc' C type 'gatomicrefcount*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_ref_count_compare" }, { "cIdentifier" : "g_atomic_ref_count_dec", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'arc' C type 'gatomicrefcount*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_ref_count_dec" }, { "cIdentifier" : "g_atomic_ref_count_inc", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'arc' C type 'gatomicrefcount*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.atomic_ref_count_inc" }, { "cIdentifier" : "g_atomic_ref_count_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'arc' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.atomic_ref_count_init" }, { "cIdentifier" : "g_base64_decode", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'out_len' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.base64_decode" }, { "cIdentifier" : "g_base64_decode_inplace", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'text' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.base64_decode_inplace" }, { "cIdentifier" : "g_base64_decode_step", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'in': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.base64_decode_step" }, { "cIdentifier" : "g_base64_encode", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.base64_encode" }, { "cIdentifier" : "g_base64_encode_close", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'out' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.base64_encode_close" }, { "cIdentifier" : "g_base64_encode_step", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'in': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.base64_encode_step" }, - { - "cIdentifier" : "g_basename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.basename" - }, { "cIdentifier" : "g_bit_lock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.bit_lock" }, { "cIdentifier" : "g_bit_lock_and_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.bit_lock_and_get" }, - { - "cIdentifier" : "g_bit_nth_lsf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.bit_nth_lsf" - }, - { - "cIdentifier" : "g_bit_nth_msf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.bit_nth_msf" - }, - { - "cIdentifier" : "g_bit_storage", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.bit_storage" - }, { "cIdentifier" : "g_bit_trylock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.bit_trylock" }, { "cIdentifier" : "g_bit_unlock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'volatile gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.bit_unlock" }, { "cIdentifier" : "g_bit_unlock_and_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'gint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.bit_unlock_and_set" }, - { - "cIdentifier" : "g_blow_chunks", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.blow_chunks" - }, - { - "cIdentifier" : "g_bookmark_file_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.bookmark_file_error_quark" - }, { "cIdentifier" : "g_build_filename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.build_filename" }, { "cIdentifier" : "g_build_filename_valist", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': va_list parameters are permanently unbridgeable", + "reason" : "varargs", "symbol" : "GLib.build_filename_valist" }, { "cIdentifier" : "g_build_filenamev", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.build_filenamev" }, { "cIdentifier" : "g_build_path", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.build_path" }, { "cIdentifier" : "g_build_pathv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.build_pathv" }, { "cIdentifier" : "g_byte_array_append", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_append" }, { "cIdentifier" : "g_byte_array_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_free" }, { "cIdentifier" : "g_byte_array_free_to_bytes", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_free_to_bytes" }, { "cIdentifier" : "g_byte_array_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_new" }, { "cIdentifier" : "g_byte_array_new_take", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.byte_array_new_take" }, { "cIdentifier" : "g_byte_array_prepend", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_prepend" }, { "cIdentifier" : "g_byte_array_ref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_ref" }, { "cIdentifier" : "g_byte_array_remove_index", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_remove_index" }, { "cIdentifier" : "g_byte_array_remove_index_fast", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_remove_index_fast" }, { "cIdentifier" : "g_byte_array_remove_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_remove_range" }, { "cIdentifier" : "g_byte_array_set_size", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_set_size" }, { "cIdentifier" : "g_byte_array_sized_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_sized_new" }, { "cIdentifier" : "g_byte_array_sort", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_sort" }, { "cIdentifier" : "g_byte_array_sort_with_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_sort_with_data" }, { "cIdentifier" : "g_byte_array_steal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_steal" }, { "cIdentifier" : "g_byte_array_unref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': byteArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.byte_array_unref" }, { "cIdentifier" : "g_canonicalize_filename", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'relative_to' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.canonicalize_filename" }, { "cIdentifier" : "g_chdir", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_chdir' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.chdir" }, - { - "cIdentifier" : "glib_check_version", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.check_version" - }, - { - "cIdentifier" : "g_checksum_type_get_length", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.checksum_type_get_length" - }, { "cIdentifier" : "g_child_watch_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.ChildWatchFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.child_watch_add" }, { "cIdentifier" : "g_child_watch_add_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.ChildWatchFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.child_watch_add_full" }, { "cIdentifier" : "g_child_watch_source_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Source' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.child_watch_source_new" }, { "cIdentifier" : "g_chmod", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_chmod' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.chmod" }, { "cIdentifier" : "g_clear_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.clear_error" }, { "cIdentifier" : "g_clear_handle_id", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'tag_ptr' C type 'guint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.clear_handle_id" }, { "cIdentifier" : "g_clear_list", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'list_ptr': list container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.clear_list" }, { "cIdentifier" : "g_clear_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'pp' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.clear_pointer" }, { "cIdentifier" : "g_clear_slist", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'slist_ptr': slist container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.clear_slist" }, { "cIdentifier" : "g_close", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.close" }, { "cIdentifier" : "g_compute_checksum_for_bytes", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'data' type 'Bytes' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.compute_checksum_for_bytes" }, { "cIdentifier" : "g_compute_checksum_for_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.compute_checksum_for_data" }, - { - "cIdentifier" : "g_compute_checksum_for_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.compute_checksum_for_string" - }, { "cIdentifier" : "g_compute_hmac_for_bytes", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'key' type 'Bytes' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.compute_hmac_for_bytes" }, { "cIdentifier" : "g_compute_hmac_for_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'key': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.compute_hmac_for_data" }, { "cIdentifier" : "g_compute_hmac_for_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'key': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.compute_hmac_for_string" }, { "cIdentifier" : "g_cond_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GLib.Cond' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.cond_new" }, { "cIdentifier" : "g_convert", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.convert" }, - { - "cIdentifier" : "g_convert_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.convert_error_quark" - }, { "cIdentifier" : "g_convert_with_fallback", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.convert_with_fallback" }, { "cIdentifier" : "g_convert_with_iconv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.convert_with_iconv" }, { "cIdentifier" : "g_creat", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_creat' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.creat" }, { "cIdentifier" : "g_datalist_clear", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_clear" }, { "cIdentifier" : "g_datalist_foreach", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_foreach" }, { "cIdentifier" : "g_datalist_get_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_get_data" }, { "cIdentifier" : "g_datalist_get_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_get_flags" }, { "cIdentifier" : "g_datalist_id_dup_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_dup_data" }, { "cIdentifier" : "g_datalist_id_get_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_get_data" }, { "cIdentifier" : "g_datalist_id_remove_multiple", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_remove_multiple" }, { "cIdentifier" : "g_datalist_id_remove_no_notify", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_remove_no_notify" }, { "cIdentifier" : "g_datalist_id_replace_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_replace_data" }, { "cIdentifier" : "g_datalist_id_set_data_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_id_set_data_full" }, { "cIdentifier" : "g_datalist_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_init" }, { "cIdentifier" : "g_datalist_set_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_set_flags" }, { "cIdentifier" : "g_datalist_unset_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'datalist': 'GLib.Data' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.datalist_unset_flags" }, - { - "cIdentifier" : "g_dataset_destroy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.dataset_destroy" - }, { "cIdentifier" : "g_dataset_foreach", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'func': callback 'GLib.DataForeachFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.dataset_foreach" }, - { - "cIdentifier" : "g_dataset_id_get_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.dataset_id_get_data" - }, - { - "cIdentifier" : "g_dataset_id_remove_no_notify", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.dataset_id_remove_no_notify" - }, { "cIdentifier" : "g_dataset_id_set_data_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'destroy_func': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.dataset_id_set_data_full" }, - { - "cIdentifier" : "g_date_get_days_in_month", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_get_days_in_month" - }, - { - "cIdentifier" : "g_date_get_monday_weeks_in_year", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_get_monday_weeks_in_year" - }, - { - "cIdentifier" : "g_date_get_sunday_weeks_in_year", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_get_sunday_weeks_in_year" - }, - { - "cIdentifier" : "g_date_get_weeks_in_year", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_get_weeks_in_year" - }, - { - "cIdentifier" : "g_date_is_leap_year", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_is_leap_year" - }, { "cIdentifier" : "g_date_strftime", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 's' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.date_strftime" }, - { - "cIdentifier" : "g_date_valid_day", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_day" - }, - { - "cIdentifier" : "g_date_valid_dmy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_dmy" - }, - { - "cIdentifier" : "g_date_valid_julian", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_julian" - }, - { - "cIdentifier" : "g_date_valid_month", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_month" - }, - { - "cIdentifier" : "g_date_valid_weekday", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_weekday" - }, - { - "cIdentifier" : "g_date_valid_year", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.date_valid_year" - }, { "cIdentifier" : "g_dcgettext", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.dcgettext" }, { "cIdentifier" : "g_dgettext", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.dgettext" }, { "cIdentifier" : "g_dir_make_tmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.dir_make_tmp" }, - { - "cIdentifier" : "g_direct_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.direct_equal" - }, - { - "cIdentifier" : "g_direct_hash", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.direct_hash" - }, { "cIdentifier" : "g_dngettext", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.dngettext" }, - { - "cIdentifier" : "g_double_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.double_equal" - }, - { - "cIdentifier" : "g_double_hash", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.double_hash" - }, { "cIdentifier" : "g_dpgettext", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.dpgettext" }, { "cIdentifier" : "g_dpgettext2", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.dpgettext2" }, { "cIdentifier" : "g_environ_getenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'envp': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.environ_getenv" }, { "cIdentifier" : "g_environ_setenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'envp': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.environ_setenv" }, { "cIdentifier" : "g_environ_unsetenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'envp': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.environ_unsetenv" }, { "cIdentifier" : "g_error_domain_register", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'error_type_init': callback 'GLib.ErrorInitFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.error_domain_register" }, { "cIdentifier" : "g_error_domain_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'error_type_init': callback 'GLib.ErrorInitFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.error_domain_register_static" }, - { - "cIdentifier" : "g_file_error_from_errno", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.file_error_from_errno" - }, - { - "cIdentifier" : "g_file_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.file_error_quark" - }, { "cIdentifier" : "g_file_get_contents", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.file_get_contents" }, { "cIdentifier" : "g_file_open_tmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.file_open_tmp" }, { "cIdentifier" : "g_file_read_link", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.file_read_link" }, { "cIdentifier" : "g_file_set_contents", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.file_set_contents" }, { "cIdentifier" : "g_file_set_contents_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.file_set_contents_full" }, - { - "cIdentifier" : "g_file_test", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.file_test" - }, - { - "cIdentifier" : "g_filename_display_basename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.filename_display_basename" - }, - { - "cIdentifier" : "g_filename_display_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.filename_display_name" - }, { "cIdentifier" : "g_filename_from_uri", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.filename_from_uri" }, { "cIdentifier" : "g_filename_from_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.filename_from_utf8" }, { "cIdentifier" : "g_filename_to_uri", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.filename_to_uri" }, { "cIdentifier" : "g_filename_to_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.filename_to_utf8" }, - { - "cIdentifier" : "g_find_program_in_path", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.find_program_in_path" - }, { "cIdentifier" : "g_fopen", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_fopen' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.fopen" }, - { - "cIdentifier" : "g_format_size", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.format_size" - }, - { - "cIdentifier" : "g_format_size_for_display", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.format_size_for_display" - }, - { - "cIdentifier" : "g_format_size_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.format_size_full" - }, { "cIdentifier" : "g_fprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'file' C type 'FILE*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.fprintf" }, - { - "cIdentifier" : "g_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.free" - }, - { - "cIdentifier" : "g_free_sized", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.free_sized" - }, { "cIdentifier" : "g_freopen", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_freopen' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.freopen" }, { "cIdentifier" : "g_fsync", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_fsync' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.fsync" }, - { - "cIdentifier" : "g_get_application_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_application_name" - }, { "cIdentifier" : "g_get_charset", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'charset' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.get_charset" }, - { - "cIdentifier" : "g_get_codeset", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_codeset" - }, { "cIdentifier" : "g_get_console_charset", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'charset' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.get_console_charset" }, - { - "cIdentifier" : "g_get_current_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_current_dir" - }, { "cIdentifier" : "g_get_current_time", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'result': 'GLib.TimeVal' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.get_current_time" }, { "cIdentifier" : "g_get_environ", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_environ" }, { "cIdentifier" : "g_get_filename_charsets", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'filename_charsets' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.get_filename_charsets" }, - { - "cIdentifier" : "g_get_home_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_home_dir" - }, - { - "cIdentifier" : "g_get_host_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_host_name" - }, { "cIdentifier" : "g_get_language_names", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_language_names" }, { "cIdentifier" : "g_get_language_names_with_category", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_language_names_with_category" }, { "cIdentifier" : "g_get_locale_variants", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_locale_variants" }, - { - "cIdentifier" : "g_get_monotonic_time", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_monotonic_time" - }, { "cIdentifier" : "g_get_monotonic_time_ns", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_get_monotonic_time_ns' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.get_monotonic_time_ns" }, - { - "cIdentifier" : "g_get_num_processors", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_num_processors" - }, - { - "cIdentifier" : "g_get_os_info", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_os_info" - }, - { - "cIdentifier" : "g_get_prgname", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_prgname" - }, - { - "cIdentifier" : "g_get_real_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_real_name" - }, - { - "cIdentifier" : "g_get_real_time", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_real_time" - }, { "cIdentifier" : "g_get_system_config_dirs", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_system_config_dirs" }, { "cIdentifier" : "g_get_system_data_dirs", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.get_system_data_dirs" }, - { - "cIdentifier" : "g_get_tmp_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_tmp_dir" - }, - { - "cIdentifier" : "g_get_user_cache_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_cache_dir" - }, - { - "cIdentifier" : "g_get_user_config_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_config_dir" - }, - { - "cIdentifier" : "g_get_user_data_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_data_dir" - }, - { - "cIdentifier" : "g_get_user_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_name" - }, - { - "cIdentifier" : "g_get_user_runtime_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_runtime_dir" - }, - { - "cIdentifier" : "g_get_user_special_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_special_dir" - }, - { - "cIdentifier" : "g_get_user_state_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.get_user_state_dir" - }, - { - "cIdentifier" : "g_getenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.getenv" - }, { "cIdentifier" : "g_hash_table_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_add" }, { "cIdentifier" : "g_hash_table_contains", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_contains" }, { "cIdentifier" : "g_hash_table_destroy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_destroy" }, { "cIdentifier" : "g_hash_table_find", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_find" }, { "cIdentifier" : "g_hash_table_foreach", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_foreach" }, { "cIdentifier" : "g_hash_table_foreach_remove", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_foreach_remove" }, { "cIdentifier" : "g_hash_table_foreach_steal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_foreach_steal" }, { "cIdentifier" : "g_hash_table_get_keys_as_ptr_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_get_keys_as_ptr_array" }, { "cIdentifier" : "g_hash_table_get_values_as_ptr_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_get_values_as_ptr_array" }, { "cIdentifier" : "g_hash_table_insert", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_insert" }, { "cIdentifier" : "g_hash_table_lookup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_lookup" }, { "cIdentifier" : "g_hash_table_lookup_extended", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_lookup_extended" }, { "cIdentifier" : "g_hash_table_new_similar", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'other_hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_new_similar" }, { "cIdentifier" : "g_hash_table_ref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_ref" }, { "cIdentifier" : "g_hash_table_remove", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_remove" }, { "cIdentifier" : "g_hash_table_remove_all", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_remove_all" }, { "cIdentifier" : "g_hash_table_replace", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_replace" }, { "cIdentifier" : "g_hash_table_size", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_size" }, { "cIdentifier" : "g_hash_table_steal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_steal" }, { "cIdentifier" : "g_hash_table_steal_all", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_steal_all" }, { "cIdentifier" : "g_hash_table_steal_all_keys", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_steal_all_keys" }, { "cIdentifier" : "g_hash_table_steal_all_values", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_steal_all_values" }, { "cIdentifier" : "g_hash_table_steal_extended", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_steal_extended" }, { "cIdentifier" : "g_hash_table_unref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hash_table': hashTable container with 2 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.hash_table_unref" }, { "cIdentifier" : "g_hook_destroy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_destroy" }, { "cIdentifier" : "g_hook_destroy_link", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_destroy_link" }, { "cIdentifier" : "g_hook_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_free" }, { "cIdentifier" : "g_hook_insert_before", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_insert_before" }, { "cIdentifier" : "g_hook_insert_sorted", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_insert_sorted" }, { "cIdentifier" : "g_hook_prepend", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_prepend" }, { "cIdentifier" : "g_hook_unref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_list': 'GLib.HookList' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.hook_unref" }, - { - "cIdentifier" : "g_hostname_is_ascii_encoded", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.hostname_is_ascii_encoded" - }, - { - "cIdentifier" : "g_hostname_is_ip_address", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.hostname_is_ip_address" - }, - { - "cIdentifier" : "g_hostname_is_non_ascii", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.hostname_is_non_ascii" - }, - { - "cIdentifier" : "g_hostname_to_ascii", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.hostname_to_ascii" - }, - { - "cIdentifier" : "g_hostname_to_unicode", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.hostname_to_unicode" - }, { "cIdentifier" : "g_iconv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'converter': 'GLib.IConv' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.iconv" }, { "cIdentifier" : "g_iconv_open", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GLib.IConv' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.iconv_open" }, { "cIdentifier" : "g_idle_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.idle_add" }, { "cIdentifier" : "g_idle_add_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.idle_add_full" }, { "cIdentifier" : "g_idle_add_once", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceOnceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.idle_add_once" }, - { - "cIdentifier" : "g_idle_remove_by_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.idle_remove_by_data" - }, { "cIdentifier" : "g_idle_source_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Source' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.idle_source_new" }, - { - "cIdentifier" : "g_int64_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.int64_equal" - }, - { - "cIdentifier" : "g_int64_hash", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.int64_hash" - }, - { - "cIdentifier" : "g_int_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.int_equal" - }, - { - "cIdentifier" : "g_int_hash", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.int_hash" - }, { "cIdentifier" : "g_intern_static_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.intern_static_string" }, { "cIdentifier" : "g_intern_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.intern_string" }, { "cIdentifier" : "g_io_add_watch", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'channel' type 'IOChannel' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.io_add_watch" }, { "cIdentifier" : "g_io_add_watch_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'channel' type 'IOChannel' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.io_add_watch_full" }, - { - "cIdentifier" : "g_io_channel_error_from_errno", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.io_channel_error_from_errno" - }, - { - "cIdentifier" : "g_io_channel_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.io_channel_error_quark" - }, { "cIdentifier" : "g_io_create_watch", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'channel' type 'IOChannel' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.io_create_watch" }, - { - "cIdentifier" : "g_key_file_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.key_file_error_quark" - }, - { - "cIdentifier" : "g_list_pop_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.list_pop_allocator" - }, { "cIdentifier" : "g_list_push_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'allocator': 'GLib.Allocator' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.list_push_allocator" }, { "cIdentifier" : "g_listenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.listenv" }, { "cIdentifier" : "g_locale_from_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.locale_from_utf8" }, { "cIdentifier" : "g_locale_to_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.locale_to_utf8" }, { "cIdentifier" : "g_log", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log" }, { "cIdentifier" : "g_log_default_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_default_handler" }, - { - "cIdentifier" : "g_log_get_always_fatal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_get_always_fatal" - }, - { - "cIdentifier" : "g_log_get_debug_enabled", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_get_debug_enabled" - }, - { - "cIdentifier" : "g_log_remove_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_remove_handler" - }, - { - "cIdentifier" : "g_log_set_always_fatal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_set_always_fatal" - }, - { - "cIdentifier" : "g_log_set_debug_enabled", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_set_debug_enabled" - }, { "cIdentifier" : "g_log_set_default_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'log_func': callback 'GLib.LogFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.log_set_default_handler" }, - { - "cIdentifier" : "g_log_set_fatal_mask", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_set_fatal_mask" - }, { "cIdentifier" : "g_log_set_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_set_handler" }, { "cIdentifier" : "g_log_set_handler_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_set_handler_full" }, { "cIdentifier" : "g_log_set_writer_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'func': callback 'GLib.LogWriterFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.log_set_writer_func" }, { "cIdentifier" : "g_log_structured", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.log_structured" }, { "cIdentifier" : "g_log_structured_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_structured_array" }, { "cIdentifier" : "g_log_structured_standard", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.log_structured_standard" }, { "cIdentifier" : "g_log_variant", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_variant" }, { "cIdentifier" : "g_log_writer_default", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_writer_default" }, { "cIdentifier" : "g_log_writer_default_set_debug_domains", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domains' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_writer_default_set_debug_domains" }, - { - "cIdentifier" : "g_log_writer_default_set_use_stderr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_writer_default_set_use_stderr" - }, { "cIdentifier" : "g_log_writer_default_would_drop", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.log_writer_default_would_drop" }, { "cIdentifier" : "g_log_writer_format_fields", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_writer_format_fields" }, - { - "cIdentifier" : "g_log_writer_is_journald", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_writer_is_journald" - }, { "cIdentifier" : "g_log_writer_journald", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_writer_journald" }, { "cIdentifier" : "g_log_writer_standard_streams", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_writer_standard_streams" }, - { - "cIdentifier" : "g_log_writer_supports_color", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.log_writer_supports_color" - }, { "cIdentifier" : "g_log_writer_syslog", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'fields': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.log_writer_syslog" }, { "cIdentifier" : "g_logv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.logv" }, { "cIdentifier" : "g_lstat", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_lstat' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.lstat" }, { "cIdentifier" : "g_main_context_default", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'MainContext' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.main_context_default" }, { "cIdentifier" : "g_main_context_get_thread_default", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'MainContext?' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.main_context_get_thread_default" }, { "cIdentifier" : "g_main_context_ref_thread_default", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'MainContext' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.main_context_ref_thread_default" }, { "cIdentifier" : "g_main_current_source", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Source?' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.main_current_source" }, - { - "cIdentifier" : "g_main_depth", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.main_depth" - }, - { - "cIdentifier" : "g_malloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.malloc" - }, - { - "cIdentifier" : "g_malloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.malloc0" - }, - { - "cIdentifier" : "g_malloc0_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.malloc0_n" - }, - { - "cIdentifier" : "g_malloc_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.malloc_n" - }, { "cIdentifier" : "g_markup_collect_attributes", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'attribute_names' is not a single const input string ('const gchar**')", "reason" : "unknownType", "symbol" : "GLib.markup_collect_attributes" }, - { - "cIdentifier" : "g_markup_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.markup_error_quark" - }, - { - "cIdentifier" : "g_markup_escape_text", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.markup_escape_text" - }, { "cIdentifier" : "g_markup_printf_escaped", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.markup_printf_escaped" }, { "cIdentifier" : "g_markup_vprintf_escaped", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': va_list parameters are permanently unbridgeable", + "reason" : "varargs", "symbol" : "GLib.markup_vprintf_escaped" }, - { - "cIdentifier" : "g_mem_chunk_info", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.mem_chunk_info" - }, - { - "cIdentifier" : "g_mem_is_system_malloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.mem_is_system_malloc" - }, - { - "cIdentifier" : "g_mem_profile", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.mem_profile" - }, { "cIdentifier" : "g_mem_set_vtable", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'vtable': 'GLib.MemVTable' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.mem_set_vtable" }, - { - "cIdentifier" : "g_memdup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.memdup" - }, - { - "cIdentifier" : "g_memdup2", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.memdup2" - }, { "cIdentifier" : "g_mkdir", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_mkdir' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.mkdir" }, - { - "cIdentifier" : "g_mkdir_with_parents", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.mkdir_with_parents" - }, { "cIdentifier" : "g_mkdtemp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'tmpl' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.mkdtemp" }, { "cIdentifier" : "g_mkdtemp_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'tmpl' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.mkdtemp_full" }, { "cIdentifier" : "g_mkstemp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'tmpl' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.mkstemp" }, { "cIdentifier" : "g_mkstemp_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'tmpl' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.mkstemp_full" }, { "cIdentifier" : "g_mutex_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "unresolved type 'GLib.Mutex'", "reason" : "unknownType", "symbol" : "GLib.mutex_new" }, - { - "cIdentifier" : "g_node_pop_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.node_pop_allocator" - }, { "cIdentifier" : "g_node_push_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'allocator': 'GLib.Allocator' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.node_push_allocator" }, { "cIdentifier" : "g_nullify_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nullify_location' C type 'gpointer*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.nullify_pointer" }, - { - "cIdentifier" : "g_number_parser_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.number_parser_error_quark" - }, - { - "cIdentifier" : "g_on_error_query", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.on_error_query" - }, { "cIdentifier" : "g_on_error_stack_trace", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'prg_name' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.on_error_stack_trace" }, { "cIdentifier" : "g_once_init_enter", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'location' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.once_init_enter" }, { "cIdentifier" : "g_once_init_enter_impl", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'location' C type 'volatile gsize*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.once_init_enter_impl" }, { "cIdentifier" : "g_once_init_enter_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'location' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.once_init_enter_pointer" }, { "cIdentifier" : "g_once_init_leave", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'location' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.once_init_leave" }, { "cIdentifier" : "g_once_init_leave_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'location' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.once_init_leave_pointer" }, { "cIdentifier" : "g_open", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_open' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.open" }, - { - "cIdentifier" : "g_option_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.option_error_quark" - }, { "cIdentifier" : "g_parse_debug_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.parse_debug_string" }, - { - "cIdentifier" : "g_path_buf_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.path_buf_equal" - }, - { - "cIdentifier" : "g_path_get_basename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.path_get_basename" - }, - { - "cIdentifier" : "g_path_get_dirname", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.path_get_dirname" - }, - { - "cIdentifier" : "g_path_is_absolute", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.path_is_absolute" - }, - { - "cIdentifier" : "g_path_skip_root", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.path_skip_root" - }, { "cIdentifier" : "g_pattern_match", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'PatternSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.pattern_match" }, - { - "cIdentifier" : "g_pattern_match_simple", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.pattern_match_simple" - }, { "cIdentifier" : "g_pattern_match_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'PatternSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.pattern_match_string" }, { "cIdentifier" : "g_pointer_bit_lock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.pointer_bit_lock" }, { "cIdentifier" : "g_pointer_bit_lock_and_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'out_ptr' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.pointer_bit_lock_and_get" }, - { - "cIdentifier" : "g_pointer_bit_lock_mask_ptr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.pointer_bit_lock_mask_ptr" - }, { "cIdentifier" : "g_pointer_bit_trylock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.pointer_bit_trylock" }, { "cIdentifier" : "g_pointer_bit_unlock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.pointer_bit_unlock" }, { "cIdentifier" : "g_pointer_bit_unlock_and_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'address' C type 'void*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.pointer_bit_unlock_and_set" }, { "cIdentifier" : "g_poll", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'fds' type 'PollFD' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.poll" }, { "cIdentifier" : "g_prefix_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'err' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.prefix_error" }, { "cIdentifier" : "g_prefix_error_literal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'err' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.prefix_error_literal" }, { "cIdentifier" : "g_print", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.print" }, { "cIdentifier" : "g_printerr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.printerr" }, { "cIdentifier" : "g_printf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.printf" }, { "cIdentifier" : "g_printf_string_upper_bound", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': va_list parameters are permanently unbridgeable", + "reason" : "varargs", "symbol" : "GLib.printf_string_upper_bound" }, { "cIdentifier" : "g_private_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'notify': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.private_new" }, { "cIdentifier" : "g_propagate_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'dest' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.propagate_error" }, { "cIdentifier" : "g_propagate_prefixed_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'dest' type 'Error' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.propagate_prefixed_error" }, { "cIdentifier" : "g_ptr_array_find", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'haystack': ptrArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.ptr_array_find" }, { "cIdentifier" : "g_ptr_array_find_with_equal_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'haystack': ptrArray container with 1 element(s) not yet bridged", + "reason" : "containerType", "symbol" : "GLib.ptr_array_find_with_equal_func" }, { "cIdentifier" : "g_ptr_array_new_from_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.ptr_array_new_from_array" }, { "cIdentifier" : "g_ptr_array_new_from_null_terminated_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.ptr_array_new_from_null_terminated_array" }, { "cIdentifier" : "g_ptr_array_new_take", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.ptr_array_new_take" }, { "cIdentifier" : "g_ptr_array_new_take_null_terminated", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.ptr_array_new_take_null_terminated" }, { "cIdentifier" : "g_qsort_with_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'compare_func': callback 'GLib.CompareDataFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.qsort_with_data" }, { "cIdentifier" : "g_quark_from_static_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.quark_from_static_string" }, { "cIdentifier" : "g_quark_from_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.quark_from_string" }, - { - "cIdentifier" : "g_quark_to_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.quark_to_string" - }, { "cIdentifier" : "g_quark_try_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.quark_try_string" }, - { - "cIdentifier" : "g_random_double", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.random_double" - }, - { - "cIdentifier" : "g_random_double_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.random_double_range" - }, - { - "cIdentifier" : "g_random_int", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.random_int" - }, - { - "cIdentifier" : "g_random_int_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.random_int_range" - }, - { - "cIdentifier" : "g_random_set_seed", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.random_set_seed" - }, - { - "cIdentifier" : "g_rc_box_acquire", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_acquire" - }, - { - "cIdentifier" : "g_rc_box_alloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_alloc" - }, - { - "cIdentifier" : "g_rc_box_alloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_alloc0" - }, - { - "cIdentifier" : "g_rc_box_dup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_dup" - }, - { - "cIdentifier" : "g_rc_box_get_size", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_get_size" - }, - { - "cIdentifier" : "g_rc_box_release", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.rc_box_release" - }, { "cIdentifier" : "g_rc_box_release_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'clear_func': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.rc_box_release_full" }, - { - "cIdentifier" : "g_realloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.realloc" - }, - { - "cIdentifier" : "g_realloc_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.realloc_n" - }, { "cIdentifier" : "g_ref_count_compare", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'rc' C type 'grefcount*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.ref_count_compare" }, { "cIdentifier" : "g_ref_count_dec", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'rc' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.ref_count_dec" }, { "cIdentifier" : "g_ref_count_inc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'rc' has direction=inout", + "reason" : "inoutParameter", "symbol" : "GLib.ref_count_inc" }, { "cIdentifier" : "g_ref_count_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'rc' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.ref_count_init" }, { "cIdentifier" : "g_ref_string_acquire", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str' is not a single const input string ('char*')", "reason" : "unknownType", "symbol" : "GLib.ref_string_acquire" }, - { - "cIdentifier" : "g_ref_string_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ref_string_equal" - }, { "cIdentifier" : "g_ref_string_length", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str' is not a single const input string ('char*')", "reason" : "unknownType", "symbol" : "GLib.ref_string_length" }, - { - "cIdentifier" : "g_ref_string_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ref_string_new" - }, - { - "cIdentifier" : "g_ref_string_new_intern", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ref_string_new_intern" - }, - { - "cIdentifier" : "g_ref_string_new_len", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.ref_string_new_len" - }, { "cIdentifier" : "g_ref_string_release", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str' is not a single const input string ('char*')", "reason" : "unknownType", "symbol" : "GLib.ref_string_release" }, { "cIdentifier" : "g_regex_check_replacement", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.regex_check_replacement" }, - { - "cIdentifier" : "g_regex_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.regex_error_quark" - }, - { - "cIdentifier" : "g_regex_escape_nul", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.regex_escape_nul" - }, - { - "cIdentifier" : "g_regex_escape_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.regex_escape_string" - }, - { - "cIdentifier" : "g_regex_match_simple", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.regex_match_simple" - }, { "cIdentifier" : "g_regex_split_simple", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.regex_split_simple" }, - { - "cIdentifier" : "g_reload_user_special_dirs_cache", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.reload_user_special_dirs_cache" - }, { "cIdentifier" : "g_remove", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_remove' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.remove" }, { "cIdentifier" : "g_rename", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_rename' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.rename" }, { "cIdentifier" : "g_return_if_fail_warning", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.return_if_fail_warning" }, { "cIdentifier" : "g_rmdir", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_rmdir' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.rmdir" }, { "cIdentifier" : "g_sequence_foreach_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'begin': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_foreach_range" }, { "cIdentifier" : "g_sequence_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_get" }, { "cIdentifier" : "g_sequence_insert_before", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_insert_before" }, { "cIdentifier" : "g_sequence_move", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'src': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_move" }, { "cIdentifier" : "g_sequence_move_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'dest': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_move_range" }, { "cIdentifier" : "g_sequence_range_get_midpoint", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'begin': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_range_get_midpoint" }, { "cIdentifier" : "g_sequence_remove", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_remove" }, { "cIdentifier" : "g_sequence_remove_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'begin': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_remove_range" }, { "cIdentifier" : "g_sequence_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_set" }, { "cIdentifier" : "g_sequence_sort_changed", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_sort_changed" }, { "cIdentifier" : "g_sequence_sort_changed_iter", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'iter': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_sort_changed_iter" }, { "cIdentifier" : "g_sequence_swap", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'a': 'GLib.SequenceIter' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.sequence_swap" }, - { - "cIdentifier" : "g_set_application_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.set_application_name" - }, { "cIdentifier" : "g_set_error", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'err' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.set_error" }, { "cIdentifier" : "g_set_error_literal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'err' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.set_error_literal" }, - { - "cIdentifier" : "g_set_prgname", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.set_prgname" - }, { "cIdentifier" : "g_set_print_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'func': callback 'GLib.PrintFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.set_print_handler" }, { "cIdentifier" : "g_set_printerr_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'func': callback 'GLib.PrintFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.set_printerr_handler" }, - { - "cIdentifier" : "g_setenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.setenv" - }, - { - "cIdentifier" : "g_shell_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.shell_error_quark" - }, { "cIdentifier" : "g_shell_parse_argv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.shell_parse_argv" }, - { - "cIdentifier" : "g_shell_quote", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.shell_quote" - }, { "cIdentifier" : "g_shell_unquote", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.shell_unquote" }, - { - "cIdentifier" : "g_slice_alloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_alloc" - }, - { - "cIdentifier" : "g_slice_alloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_alloc0" - }, - { - "cIdentifier" : "g_slice_copy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_copy" - }, - { - "cIdentifier" : "g_slice_free1", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_free1" - }, - { - "cIdentifier" : "g_slice_free_chain_with_offset", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_free_chain_with_offset" - }, - { - "cIdentifier" : "g_slice_get_config", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_get_config" - }, { "cIdentifier" : "g_slice_get_config_state", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'n_values' C type 'guint*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.slice_get_config_state" }, - { - "cIdentifier" : "g_slice_set_config", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slice_set_config" - }, - { - "cIdentifier" : "g_slist_pop_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.slist_pop_allocator" - }, { "cIdentifier" : "g_slist_push_allocator", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'allocator': 'GLib.Allocator' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.slist_push_allocator" }, { "cIdentifier" : "g_snprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.snprintf" }, { "cIdentifier" : "g_sort_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'array': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.sort_array" }, - { - "cIdentifier" : "g_source_remove", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.source_remove" - }, { "cIdentifier" : "g_source_remove_by_funcs_user_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'funcs': 'GLib.SourceFuncs' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.source_remove_by_funcs_user_data" }, - { - "cIdentifier" : "g_source_remove_by_user_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.source_remove_by_user_data" - }, - { - "cIdentifier" : "g_source_set_name_by_id", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.source_set_name_by_id" - }, - { - "cIdentifier" : "g_spaced_primes_closest", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.spaced_primes_closest" - }, { "cIdentifier" : "g_spawn_async", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_async" }, { "cIdentifier" : "g_spawn_async_with_fds", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_async_with_fds" }, { "cIdentifier" : "g_spawn_async_with_pipes", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_async_with_pipes" }, { "cIdentifier" : "g_spawn_async_with_pipes_and_fds", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_async_with_pipes_and_fds" }, { "cIdentifier" : "g_spawn_check_exit_status", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_check_exit_status" }, { "cIdentifier" : "g_spawn_check_wait_status", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_check_wait_status" }, - { - "cIdentifier" : "g_spawn_close_pid", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.spawn_close_pid" - }, { "cIdentifier" : "g_spawn_command_line_async", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_command_line_async" }, { "cIdentifier" : "g_spawn_command_line_sync", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_command_line_sync" }, - { - "cIdentifier" : "g_spawn_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.spawn_error_quark" - }, - { - "cIdentifier" : "g_spawn_exit_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.spawn_exit_error_quark" - }, { "cIdentifier" : "g_spawn_sync", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.spawn_sync" }, { "cIdentifier" : "g_sprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.sprintf" }, { "cIdentifier" : "g_stat", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_stat' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.stat" }, { "cIdentifier" : "g_stpcpy", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'dest' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.stpcpy" }, - { - "cIdentifier" : "g_str_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_equal" - }, - { - "cIdentifier" : "g_str_has_prefix", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_has_prefix" - }, - { - "cIdentifier" : "g_str_has_suffix", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_has_suffix" - }, - { - "cIdentifier" : "g_str_hash", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_hash" - }, - { - "cIdentifier" : "g_str_is_ascii", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_is_ascii" - }, - { - "cIdentifier" : "g_str_match_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.str_match_string" - }, { "cIdentifier" : "g_str_to_ascii", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'from_locale' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.str_to_ascii" }, { "cIdentifier" : "g_str_tokenize_and_fold", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'translit_locale' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.str_tokenize_and_fold" }, { "cIdentifier" : "g_strcanon", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strcanon" }, - { - "cIdentifier" : "g_strcasecmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strcasecmp" - }, { "cIdentifier" : "g_strchomp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strchomp" }, { "cIdentifier" : "g_strchug", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strchug" }, { "cIdentifier" : "g_strcmp0", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str1' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strcmp0" }, - { - "cIdentifier" : "g_strcompress", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strcompress" - }, { "cIdentifier" : "g_strconcat", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.strconcat" }, { "cIdentifier" : "g_strdelimit", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strdelimit" }, { "cIdentifier" : "g_strdown", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strdown" }, { "cIdentifier" : "g_strdup", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strdup" }, { "cIdentifier" : "g_strdup_printf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.strdup_printf" }, { "cIdentifier" : "g_strdup_vprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': va_list parameters are permanently unbridgeable", + "reason" : "varargs", "symbol" : "GLib.strdup_vprintf" }, { "cIdentifier" : "g_strdupv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'str_array': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strdupv" }, - { - "cIdentifier" : "g_strerror", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strerror" - }, { "cIdentifier" : "g_strescape", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'exceptions' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strescape" }, { "cIdentifier" : "g_strfreev", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'str_array': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strfreev" }, - { - "cIdentifier" : "g_strip_context", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strip_context" - }, { "cIdentifier" : "g_strjoin", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'separator' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strjoin" }, { "cIdentifier" : "g_strjoinv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'separator' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strjoinv" }, { "cIdentifier" : "g_strlcat", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'dest' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strlcat" }, { "cIdentifier" : "g_strlcpy", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'dest' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strlcpy" }, - { - "cIdentifier" : "g_strncasecmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strncasecmp" - }, { "cIdentifier" : "g_strndup", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'str' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.strndup" }, - { - "cIdentifier" : "g_strnfill", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strnfill" - }, { "cIdentifier" : "g_strreverse", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strreverse" }, - { - "cIdentifier" : "g_strrstr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strrstr" - }, - { - "cIdentifier" : "g_strrstr_len", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strrstr_len" - }, - { - "cIdentifier" : "g_strsignal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strsignal" - }, { "cIdentifier" : "g_strsplit", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strsplit" }, { "cIdentifier" : "g_strsplit_set", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'delimiters': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strsplit_set" }, - { - "cIdentifier" : "g_strstr_len", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.strstr_len" - }, { "cIdentifier" : "g_strtod", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'endptr' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.strtod" }, { "cIdentifier" : "g_strup", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.strup" }, { "cIdentifier" : "g_strv_contains", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'strv': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strv_contains" }, { "cIdentifier" : "g_strv_equal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'strv1': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strv_equal" }, { "cIdentifier" : "g_strv_get_type", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_strv_get_type' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.strv_get_type" }, { "cIdentifier" : "g_strv_length", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'str_array': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.strv_length" }, { "cIdentifier" : "g_test_add_data_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'test_func': callback 'GLib.TestDataFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_add_data_func" }, { "cIdentifier" : "g_test_add_data_func_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'test_func': callback 'GLib.TestDataFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_add_data_func_full" }, { "cIdentifier" : "g_test_add_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'test_func': callback 'GLib.TestFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_add_func" }, { "cIdentifier" : "g_test_add_vtable", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data_setup': callback 'GLib.TestFixtureFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_add_vtable" }, - { - "cIdentifier" : "g_test_assert_expected_messages_internal", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_assert_expected_messages_internal" - }, - { - "cIdentifier" : "g_test_bug", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_bug" - }, - { - "cIdentifier" : "g_test_bug_base", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_bug_base" - }, { "cIdentifier" : "g_test_build_filename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_build_filename" }, { "cIdentifier" : "g_test_create_case", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'data_setup': callback 'GLib.TestFixtureFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_create_case" }, { "cIdentifier" : "g_test_create_suite", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GLib.TestSuite' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.test_create_suite" }, - { - "cIdentifier" : "g_test_disable_crash_reporting", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_disable_crash_reporting" - }, { "cIdentifier" : "g_test_expect_message", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'log_domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.test_expect_message" }, - { - "cIdentifier" : "g_test_fail", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_fail" - }, { "cIdentifier" : "g_test_fail_printf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_fail_printf" }, - { - "cIdentifier" : "g_test_failed", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_failed" - }, - { - "cIdentifier" : "g_test_get_dir", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_get_dir" - }, { "cIdentifier" : "g_test_get_filename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_get_filename" }, - { - "cIdentifier" : "g_test_get_path", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_get_path" - }, { "cIdentifier" : "g_test_get_root", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GLib.TestSuite' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.test_get_root" }, { "cIdentifier" : "g_test_incomplete", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'msg' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.test_incomplete" }, { "cIdentifier" : "g_test_incomplete_printf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_incomplete_printf" }, { "cIdentifier" : "g_test_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'argc' C type 'int*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.test_init" }, { "cIdentifier" : "g_test_log_set_fatal_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'log_func': callback 'GLib.TestLogFatalFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_log_set_fatal_handler" }, - { - "cIdentifier" : "g_test_log_type_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_log_type_name" - }, { "cIdentifier" : "g_test_maximized_result", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_maximized_result" }, { "cIdentifier" : "g_test_message", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_message" }, { "cIdentifier" : "g_test_minimized_result", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_minimized_result" }, { "cIdentifier" : "g_test_queue_destroy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'destroy_func': callback 'GLib.DestroyNotify' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.test_queue_destroy" }, - { - "cIdentifier" : "g_test_queue_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_queue_free" - }, - { - "cIdentifier" : "g_test_rand_double", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_rand_double" - }, - { - "cIdentifier" : "g_test_rand_double_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_rand_double_range" - }, - { - "cIdentifier" : "g_test_rand_int", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_rand_int" - }, - { - "cIdentifier" : "g_test_rand_int_range", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_rand_int_range" - }, - { - "cIdentifier" : "g_test_run", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_run" - }, { "cIdentifier" : "g_test_run_suite", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'suite': 'GLib.TestSuite' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.test_run_suite" }, - { - "cIdentifier" : "g_test_set_nonfatal_assertions", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_set_nonfatal_assertions" - }, { "cIdentifier" : "g_test_skip", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'msg' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.test_skip" }, { "cIdentifier" : "g_test_skip_printf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "variadic ('...') parameter", + "reason" : "varargs", "symbol" : "GLib.test_skip_printf" }, - { - "cIdentifier" : "g_test_subprocess", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_subprocess" - }, - { - "cIdentifier" : "g_test_summary", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_summary" - }, - { - "cIdentifier" : "g_test_timer_elapsed", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_timer_elapsed" - }, - { - "cIdentifier" : "g_test_timer_last", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_timer_last" - }, - { - "cIdentifier" : "g_test_timer_start", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_timer_start" - }, - { - "cIdentifier" : "g_test_trap_assertions", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_trap_assertions" - }, - { - "cIdentifier" : "g_test_trap_fork", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_trap_fork" - }, - { - "cIdentifier" : "g_test_trap_has_passed", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_trap_has_passed" - }, - { - "cIdentifier" : "g_test_trap_has_skipped", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_trap_has_skipped" - }, - { - "cIdentifier" : "g_test_trap_reached_timeout", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.test_trap_reached_timeout" - }, { "cIdentifier" : "g_test_trap_subprocess", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'test_path' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.test_trap_subprocess" }, { "cIdentifier" : "g_test_trap_subprocess_with_envp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'test_path' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.test_trap_subprocess_with_envp" }, { "cIdentifier" : "g_thread_create", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.thread_create" }, { "cIdentifier" : "g_thread_create_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.thread_create_full" }, - { - "cIdentifier" : "g_thread_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_error_quark" - }, - { - "cIdentifier" : "g_thread_exit", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_exit" - }, { "cIdentifier" : "g_thread_foreach", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'thread_func': callback 'GLib.Func' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.thread_foreach" }, - { - "cIdentifier" : "g_thread_get_initialized", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_get_initialized" - }, - { - "cIdentifier" : "g_thread_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_init" - }, - { - "cIdentifier" : "g_thread_init_with_errorcheck_mutexes", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_init_with_errorcheck_mutexes" - }, - { - "cIdentifier" : "g_thread_pool_get_max_idle_time", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_get_max_idle_time" - }, - { - "cIdentifier" : "g_thread_pool_get_max_unused_threads", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_get_max_unused_threads" - }, - { - "cIdentifier" : "g_thread_pool_get_num_unused_threads", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_get_num_unused_threads" - }, - { - "cIdentifier" : "g_thread_pool_set_max_idle_time", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_set_max_idle_time" - }, - { - "cIdentifier" : "g_thread_pool_set_max_unused_threads", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_set_max_unused_threads" - }, - { - "cIdentifier" : "g_thread_pool_stop_unused_threads", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_pool_stop_unused_threads" - }, { "cIdentifier" : "g_thread_self", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Thread' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.thread_self" }, - { - "cIdentifier" : "g_thread_yield", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.thread_yield" - }, { "cIdentifier" : "g_time_val_from_iso8601", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'time_' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.time_val_from_iso8601" }, { "cIdentifier" : "g_timeout_add", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add" }, { "cIdentifier" : "g_timeout_add_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add_full" }, { "cIdentifier" : "g_timeout_add_once", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceOnceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add_once" }, { "cIdentifier" : "g_timeout_add_seconds", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add_seconds" }, { "cIdentifier" : "g_timeout_add_seconds_full", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add_seconds_full" }, { "cIdentifier" : "g_timeout_add_seconds_once", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'function': callback 'GLib.SourceOnceFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GLib.timeout_add_seconds_once" }, { "cIdentifier" : "g_timeout_source_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Source' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.timeout_source_new" }, { "cIdentifier" : "g_timeout_source_new_seconds", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Source' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.timeout_source_new_seconds" }, { "cIdentifier" : "g_trash_stack_height", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'stack_p': 'GLib.TrashStack' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.trash_stack_height" }, { "cIdentifier" : "g_trash_stack_peek", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'stack_p': 'GLib.TrashStack' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.trash_stack_peek" }, { "cIdentifier" : "g_trash_stack_pop", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'stack_p': 'GLib.TrashStack' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.trash_stack_pop" }, { "cIdentifier" : "g_trash_stack_push", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'stack_p': 'GLib.TrashStack' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GLib.trash_stack_push" }, - { - "cIdentifier" : "g_try_malloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_malloc" - }, - { - "cIdentifier" : "g_try_malloc0", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_malloc0" - }, - { - "cIdentifier" : "g_try_malloc0_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_malloc0_n" - }, - { - "cIdentifier" : "g_try_malloc_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_malloc_n" - }, - { - "cIdentifier" : "g_try_realloc", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_realloc" - }, - { - "cIdentifier" : "g_try_realloc_n", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.try_realloc_n" - }, { "cIdentifier" : "g_ucs4_to_utf16", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.ucs4_to_utf16" }, { "cIdentifier" : "g_ucs4_to_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.ucs4_to_utf8" }, - { - "cIdentifier" : "g_unichar_break_type", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_break_type" - }, - { - "cIdentifier" : "g_unichar_combining_class", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_combining_class" - }, { "cIdentifier" : "g_unichar_compose", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'ch' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.unichar_compose" }, { "cIdentifier" : "g_unichar_decompose", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'a' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.unichar_decompose" }, - { - "cIdentifier" : "g_unichar_digit_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_digit_value" - }, { "cIdentifier" : "g_unichar_fully_decompose", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'result' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.unichar_fully_decompose" }, { "cIdentifier" : "g_unichar_get_mirror_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'mirrored_ch' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.unichar_get_mirror_char" }, - { - "cIdentifier" : "g_unichar_get_script", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_get_script" - }, - { - "cIdentifier" : "g_unichar_isalnum", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isalnum" - }, - { - "cIdentifier" : "g_unichar_isalpha", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isalpha" - }, - { - "cIdentifier" : "g_unichar_iscntrl", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_iscntrl" - }, - { - "cIdentifier" : "g_unichar_isdefined", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isdefined" - }, - { - "cIdentifier" : "g_unichar_isdigit", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isdigit" - }, - { - "cIdentifier" : "g_unichar_isgraph", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isgraph" - }, - { - "cIdentifier" : "g_unichar_islower", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_islower" - }, - { - "cIdentifier" : "g_unichar_ismark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_ismark" - }, - { - "cIdentifier" : "g_unichar_isprint", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isprint" - }, - { - "cIdentifier" : "g_unichar_ispunct", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_ispunct" - }, - { - "cIdentifier" : "g_unichar_isspace", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isspace" - }, - { - "cIdentifier" : "g_unichar_istitle", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_istitle" - }, - { - "cIdentifier" : "g_unichar_isupper", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isupper" - }, - { - "cIdentifier" : "g_unichar_iswide", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_iswide" - }, - { - "cIdentifier" : "g_unichar_iswide_cjk", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_iswide_cjk" - }, - { - "cIdentifier" : "g_unichar_isxdigit", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_isxdigit" - }, - { - "cIdentifier" : "g_unichar_iszerowidth", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_iszerowidth" - }, { "cIdentifier" : "g_unichar_to_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'outbuf' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.unichar_to_utf8" }, - { - "cIdentifier" : "g_unichar_tolower", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_tolower" - }, - { - "cIdentifier" : "g_unichar_totitle", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_totitle" - }, - { - "cIdentifier" : "g_unichar_toupper", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_toupper" - }, - { - "cIdentifier" : "g_unichar_type", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_type" - }, - { - "cIdentifier" : "g_unichar_validate", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_validate" - }, - { - "cIdentifier" : "g_unichar_xdigit_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unichar_xdigit_value" - }, { "cIdentifier" : "g_unicode_canonical_decomposition", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'result_len' C type 'gsize*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.unicode_canonical_decomposition" }, { "cIdentifier" : "g_unicode_canonical_ordering", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'string': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.unicode_canonical_ordering" }, - { - "cIdentifier" : "g_unicode_script_from_iso15924", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unicode_script_from_iso15924" - }, - { - "cIdentifier" : "g_unicode_script_to_iso15924", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unicode_script_to_iso15924" - }, { "cIdentifier" : "g_unlink", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_unlink' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.unlink" }, - { - "cIdentifier" : "g_unsetenv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.unsetenv" - }, { "cIdentifier" : "g_uri_build", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'userinfo' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_build" }, { "cIdentifier" : "g_uri_build_with_user", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'user' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_build_with_user" }, - { - "cIdentifier" : "g_uri_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.uri_error_quark" - }, { "cIdentifier" : "g_uri_escape_bytes", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'unescaped': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.uri_escape_bytes" }, { "cIdentifier" : "g_uri_escape_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'reserved_chars_allowed' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_escape_string" }, { "cIdentifier" : "g_uri_is_valid", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_is_valid" }, { "cIdentifier" : "g_uri_join", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'scheme' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_join" }, { "cIdentifier" : "g_uri_join_with_user", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'scheme' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_join_with_user" }, { "cIdentifier" : "g_uri_list_extract_uris", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GLib.uri_list_extract_uris" }, { "cIdentifier" : "g_uri_parse", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_parse" }, { "cIdentifier" : "g_uri_parse_params", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_parse_params" }, - { - "cIdentifier" : "g_uri_parse_scheme", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.uri_parse_scheme" - }, - { - "cIdentifier" : "g_uri_peek_scheme", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.uri_peek_scheme" - }, { "cIdentifier" : "g_uri_resolve_relative", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_resolve_relative" }, { "cIdentifier" : "g_uri_split", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_split" }, { "cIdentifier" : "g_uri_split_network", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_split_network" }, { "cIdentifier" : "g_uri_split_with_user", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_split_with_user" }, { "cIdentifier" : "g_uri_unescape_bytes", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.uri_unescape_bytes" }, { "cIdentifier" : "g_uri_unescape_segment", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'escaped_string' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_unescape_segment" }, { "cIdentifier" : "g_uri_unescape_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'illegal_characters' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.uri_unescape_string" }, - { - "cIdentifier" : "g_usleep", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.usleep" - }, { "cIdentifier" : "g_utf16_to_ucs4", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.utf16_to_ucs4" }, { "cIdentifier" : "g_utf16_to_utf8", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.utf16_to_utf8" }, - { - "cIdentifier" : "g_utf8_casefold", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_casefold" - }, - { - "cIdentifier" : "g_utf8_collate", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_collate" - }, - { - "cIdentifier" : "g_utf8_collate_key", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_collate_key" - }, - { - "cIdentifier" : "g_utf8_collate_key_for_filename", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_collate_key_for_filename" - }, { "cIdentifier" : "g_utf8_find_next_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'end' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.utf8_find_next_char" }, - { - "cIdentifier" : "g_utf8_find_prev_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_find_prev_char" - }, - { - "cIdentifier" : "g_utf8_get_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_get_char" - }, - { - "cIdentifier" : "g_utf8_get_char_validated", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_get_char_validated" - }, - { - "cIdentifier" : "g_utf8_make_valid", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_make_valid" - }, - { - "cIdentifier" : "g_utf8_normalize", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_normalize" - }, - { - "cIdentifier" : "g_utf8_offset_to_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_offset_to_pointer" - }, - { - "cIdentifier" : "g_utf8_pointer_to_offset", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_pointer_to_offset" - }, - { - "cIdentifier" : "g_utf8_prev_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_prev_char" - }, - { - "cIdentifier" : "g_utf8_strchr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strchr" - }, - { - "cIdentifier" : "g_utf8_strdown", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strdown" - }, - { - "cIdentifier" : "g_utf8_strlen", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strlen" - }, { "cIdentifier" : "g_utf8_strncpy", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'dest' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.utf8_strncpy" }, - { - "cIdentifier" : "g_utf8_strrchr", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strrchr" - }, - { - "cIdentifier" : "g_utf8_strreverse", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strreverse" - }, - { - "cIdentifier" : "g_utf8_strup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_strup" - }, - { - "cIdentifier" : "g_utf8_substring", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_substring" - }, { "cIdentifier" : "g_utf8_to_ucs4", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.utf8_to_ucs4" }, { "cIdentifier" : "g_utf8_to_ucs4_fast", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'items_written' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.utf8_to_ucs4_fast" }, { "cIdentifier" : "g_utf8_to_utf16", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.utf8_to_utf16" }, - { - "cIdentifier" : "g_utf8_truncate_middle", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.utf8_truncate_middle" - }, { "cIdentifier" : "g_utf8_validate", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'str': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.utf8_validate" }, { "cIdentifier" : "g_utf8_validate_len", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'str': C array bridging not yet implemented", + "reason" : "arrayWithoutLength", "symbol" : "GLib.utf8_validate_len" }, { "cIdentifier" : "g_utime", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_utime' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.utime" }, - { - "cIdentifier" : "g_uuid_string_is_valid", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.uuid_string_is_valid" - }, - { - "cIdentifier" : "g_uuid_string_random", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.uuid_string_random" - }, { "cIdentifier" : "g_variant_get_gtype", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_variant_get_gtype' is not exported by the system library", "reason" : "unknownType", "symbol" : "GLib.variant_get_gtype" }, - { - "cIdentifier" : "g_variant_is_object_path", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_is_object_path" - }, - { - "cIdentifier" : "g_variant_is_signature", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_is_signature" - }, { "cIdentifier" : "g_variant_parse", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "GError throws planned for Phase C2", "reason" : "unknownType", "symbol" : "GLib.variant_parse" }, { "cIdentifier" : "g_variant_parse_error_print_context", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'error' type 'Error' is not yet generated", "reason" : "unknownType", "symbol" : "GLib.variant_parse_error_print_context" }, - { - "cIdentifier" : "g_variant_parse_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_parse_error_quark" - }, - { - "cIdentifier" : "g_variant_parser_get_error_quark", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_parser_get_error_quark" - }, { "cIdentifier" : "g_variant_type_checked_", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'VariantType' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GLib.variant_type_checked_" }, - { - "cIdentifier" : "g_variant_type_string_get_depth_", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_type_string_get_depth_" - }, - { - "cIdentifier" : "g_variant_type_string_is_valid", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GLib.variant_type_string_is_valid" - }, { "cIdentifier" : "g_variant_type_string_scan", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'limit' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.variant_type_string_scan" }, { "cIdentifier" : "g_vasprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'string' has direction=out", + "reason" : "outParameter", "symbol" : "GLib.vasprintf" }, { "cIdentifier" : "g_vfprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'file' C type 'FILE*' is a pointer", "reason" : "unknownType", "symbol" : "GLib.vfprintf" }, { "cIdentifier" : "g_vprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'args': va_list parameters are permanently unbridgeable", + "reason" : "varargs", "symbol" : "GLib.vprintf" }, { "cIdentifier" : "g_vsnprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.vsnprintf" }, { "cIdentifier" : "g_vsprintf", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'string' is not a single const input string ('gchar*')", "reason" : "unknownType", "symbol" : "GLib.vsprintf" }, { "cIdentifier" : "g_warn_message", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'domain' is a nullable string", "reason" : "unknownType", "symbol" : "GLib.warn_message" } ], "module" : "GLib", "stats" : { - "boundCallables" : 0, - "boundTypes" : 215, - "totalCallables" : 0, - "totalTypes" : 1091 + "boundCallables" : 293, + "boundTypes" : 246, + "totalCallables" : 724, + "totalTypes" : 367 } } diff --git a/docs/skip-baseline/tier1/GObject.json b/docs/skip-baseline/tier1/GObject.json index ab5a994..bef664c 100644 --- a/docs/skip-baseline/tier1/GObject.json +++ b/docs/skip-baseline/tier1/GObject.json @@ -54,12 +54,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GObject.ClassInitFunc" }, - { - "cIdentifier" : "GClosure", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GObject.Closure" - }, { "cIdentifier" : "GClosureMarshal", "detail" : "callback planned for Phase D2", @@ -276,12 +270,6 @@ "reason" : "gtypeStruct", "symbol" : "GObject.TypeModuleClass" }, - { - "cIdentifier" : "GTypePlugin", - "detail" : "interface binding planned for Phase C", - "reason" : "unknownType", - "symbol" : "GObject.TypePlugin" - }, { "cIdentifier" : "GTypePluginClass", "detail" : "no GType registration", @@ -366,18 +354,6 @@ "reason" : "callbackWithoutUserData", "symbol" : "GObject.VaClosureMarshal" }, - { - "cIdentifier" : "GValue", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GObject.Value" - }, - { - "cIdentifier" : "GValueArray", - "detail" : "boxed record planned for Phase C4", - "reason" : "unknownType", - "symbol" : "GObject.ValueArray" - }, { "cIdentifier" : "GValueTransform", "detail" : "callback planned for Phase D2", @@ -396,1122 +372,918 @@ "reason" : "plainRecord", "symbol" : "GObject.WeakRef" }, - { - "cIdentifier" : "g_boxed_copy", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.boxed_copy" - }, - { - "cIdentifier" : "g_boxed_free", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.boxed_free" - }, { "cIdentifier" : "g_boxed_type_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'boxed_copy': callback 'GObject.BoxedCopyFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.boxed_type_register_static" }, { "cIdentifier" : "g_cclosure_marshal_BOOLEAN__BOXED_BOXED", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_BOOLEAN__BOXED_BOXED" }, { "cIdentifier" : "g_cclosure_marshal_BOOLEAN__FLAGS", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_BOOLEAN__FLAGS" }, { "cIdentifier" : "g_cclosure_marshal_STRING__OBJECT_POINTER", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_STRING__OBJECT_POINTER" }, { "cIdentifier" : "g_cclosure_marshal_VOID__BOOLEAN", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__BOOLEAN" }, { "cIdentifier" : "g_cclosure_marshal_VOID__BOXED", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__BOXED" }, { "cIdentifier" : "g_cclosure_marshal_VOID__CHAR", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__CHAR" }, { "cIdentifier" : "g_cclosure_marshal_VOID__DOUBLE", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__DOUBLE" }, { "cIdentifier" : "g_cclosure_marshal_VOID__ENUM", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__ENUM" }, { "cIdentifier" : "g_cclosure_marshal_VOID__FLAGS", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__FLAGS" }, { "cIdentifier" : "g_cclosure_marshal_VOID__FLOAT", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__FLOAT" }, { "cIdentifier" : "g_cclosure_marshal_VOID__INT", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__INT" }, { "cIdentifier" : "g_cclosure_marshal_VOID__LONG", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__LONG" }, { "cIdentifier" : "g_cclosure_marshal_VOID__OBJECT", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__OBJECT" }, { "cIdentifier" : "g_cclosure_marshal_VOID__PARAM", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__PARAM" }, { "cIdentifier" : "g_cclosure_marshal_VOID__POINTER", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__POINTER" }, { "cIdentifier" : "g_cclosure_marshal_VOID__STRING", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__STRING" }, { "cIdentifier" : "g_cclosure_marshal_VOID__UCHAR", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__UCHAR" }, { "cIdentifier" : "g_cclosure_marshal_VOID__UINT", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__UINT" }, { "cIdentifier" : "g_cclosure_marshal_VOID__UINT_POINTER", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__UINT_POINTER" }, { "cIdentifier" : "g_cclosure_marshal_VOID__ULONG", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__ULONG" }, { "cIdentifier" : "g_cclosure_marshal_VOID__VARIANT", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__VARIANT" }, { "cIdentifier" : "g_cclosure_marshal_VOID__VOID", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_VOID__VOID" }, { "cIdentifier" : "g_cclosure_marshal_generic", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.cclosure_marshal_generic" }, { "cIdentifier" : "g_cclosure_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'callback_func': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.cclosure_new" }, { "cIdentifier" : "g_cclosure_new_object", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'callback_func': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.cclosure_new_object" }, { "cIdentifier" : "g_cclosure_new_object_swap", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'callback_func': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.cclosure_new_object_swap" }, { "cIdentifier" : "g_cclosure_new_swap", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'callback_func': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.cclosure_new_swap" }, { "cIdentifier" : "g_clear_object", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'object_ptr' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.clear_object" }, { "cIdentifier" : "g_clear_signal_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'handler_id_ptr' C type 'gulong*' is a pointer", "reason" : "unknownType", "symbol" : "GObject.clear_signal_handler" }, { "cIdentifier" : "g_enum_complete_type_info", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'info' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.enum_complete_type_info" }, { "cIdentifier" : "g_enum_get_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'enum_class': 'GObject.EnumClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.enum_get_value" }, { "cIdentifier" : "g_enum_get_value_by_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'enum_class': 'GObject.EnumClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.enum_get_value_by_name" }, { "cIdentifier" : "g_enum_get_value_by_nick", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'enum_class': 'GObject.EnumClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.enum_get_value_by_nick" }, { "cIdentifier" : "g_enum_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'const_static_values': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GObject.enum_register_static" }, - { - "cIdentifier" : "g_enum_to_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.enum_to_string" - }, { "cIdentifier" : "g_flags_complete_type_info", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'info' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.flags_complete_type_info" }, { "cIdentifier" : "g_flags_get_first_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'flags_class': 'GObject.FlagsClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.flags_get_first_value" }, { "cIdentifier" : "g_flags_get_value_by_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'flags_class': 'GObject.FlagsClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.flags_get_value_by_name" }, { "cIdentifier" : "g_flags_get_value_by_nick", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'flags_class': 'GObject.FlagsClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.flags_get_value_by_nick" }, { "cIdentifier" : "g_flags_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'const_static_values': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GObject.flags_register_static" }, - { - "cIdentifier" : "g_flags_to_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.flags_to_string" - }, - { - "cIdentifier" : "g_gtype_get_type", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.gtype_get_type" - }, { "cIdentifier" : "g_param_spec_boolean", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_boolean" }, { "cIdentifier" : "g_param_spec_boxed", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_boxed" }, { "cIdentifier" : "g_param_spec_char", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_char" }, { "cIdentifier" : "g_param_spec_double", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_double" }, { "cIdentifier" : "g_param_spec_enum", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_enum" }, { "cIdentifier" : "g_param_spec_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_flags" }, { "cIdentifier" : "g_param_spec_float", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_float" }, { "cIdentifier" : "g_param_spec_gtype", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_gtype" }, { "cIdentifier" : "g_param_spec_int", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_int" }, { "cIdentifier" : "g_param_spec_int64", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_int64" }, { "cIdentifier" : "g_param_spec_long", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_long" }, { "cIdentifier" : "g_param_spec_object", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_object" }, { "cIdentifier" : "g_param_spec_override", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'overridden' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_spec_override" }, { "cIdentifier" : "g_param_spec_param", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_param" }, { "cIdentifier" : "g_param_spec_pointer", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_pointer" }, { "cIdentifier" : "g_param_spec_string", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_string" }, { "cIdentifier" : "g_param_spec_uchar", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_uchar" }, { "cIdentifier" : "g_param_spec_uint", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_uint" }, { "cIdentifier" : "g_param_spec_uint64", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_uint64" }, { "cIdentifier" : "g_param_spec_ulong", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_ulong" }, { "cIdentifier" : "g_param_spec_unichar", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_unichar" }, { "cIdentifier" : "g_param_spec_value_array", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_value_array" }, { "cIdentifier" : "g_param_spec_variant", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'nick' is a nullable string", "reason" : "unknownType", "symbol" : "GObject.param_spec_variant" }, { "cIdentifier" : "g_param_type_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'pspec_info': 'GObject.ParamSpecTypeInfo' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.param_type_register_static" }, { "cIdentifier" : "g_param_value_convert", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_value_convert" }, { "cIdentifier" : "g_param_value_defaults", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_value_defaults" }, { "cIdentifier" : "g_param_value_is_valid", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_value_is_valid" }, { "cIdentifier" : "g_param_value_set_default", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_value_set_default" }, { "cIdentifier" : "g_param_value_validate", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_value_validate" }, { "cIdentifier" : "g_param_values_cmp", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'pspec' type 'ParamSpec' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.param_values_cmp" }, - { - "cIdentifier" : "g_pointer_type_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.pointer_type_register_static" - }, { "cIdentifier" : "g_signal_accumulator_first_wins", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'ihint': 'GObject.SignalInvocationHint' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.signal_accumulator_first_wins" }, { "cIdentifier" : "g_signal_accumulator_true_handled", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'ihint': 'GObject.SignalInvocationHint' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.signal_accumulator_true_handled" }, { "cIdentifier" : "g_signal_add_emission_hook", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'hook_func': callback 'GObject.SignalEmissionHook' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.signal_add_emission_hook" }, { "cIdentifier" : "g_signal_chain_from_overridden", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance_and_params': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GObject.signal_chain_from_overridden" }, { "cIdentifier" : "g_signal_chain_from_overridden_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.signal_chain_from_overridden_handler" }, { "cIdentifier" : "g_signal_connect_closure", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_connect_closure" }, { "cIdentifier" : "g_signal_connect_closure_by_id", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_connect_closure_by_id" }, { "cIdentifier" : "g_signal_connect_data", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_connect_data" }, { "cIdentifier" : "g_signal_connect_object", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.signal_connect_object" }, { "cIdentifier" : "g_signal_emit", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_emit" }, { "cIdentifier" : "g_signal_emit_by_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_emit_by_name" }, { "cIdentifier" : "g_signal_emit_valist", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.signal_emit_valist" }, { "cIdentifier" : "g_signal_emitv", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance_and_params': C array has no length annotation", + "reason" : "arrayWithoutLength", "symbol" : "GObject.signal_emitv" }, { "cIdentifier" : "g_signal_get_invocation_hint", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_get_invocation_hint" }, { "cIdentifier" : "g_signal_handler_block", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handler_block" }, { "cIdentifier" : "g_signal_handler_disconnect", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handler_disconnect" }, { "cIdentifier" : "g_signal_handler_find", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handler_find" }, { "cIdentifier" : "g_signal_handler_is_connected", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handler_is_connected" }, { "cIdentifier" : "g_signal_handler_unblock", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handler_unblock" }, { "cIdentifier" : "g_signal_handlers_block_matched", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handlers_block_matched" }, { "cIdentifier" : "g_signal_handlers_destroy", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handlers_destroy" }, { "cIdentifier" : "g_signal_handlers_disconnect_matched", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handlers_disconnect_matched" }, { "cIdentifier" : "g_signal_handlers_unblock_matched", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_handlers_unblock_matched" }, { "cIdentifier" : "g_signal_has_handler_pending", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_has_handler_pending" }, - { - "cIdentifier" : "g_signal_is_valid_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.signal_is_valid_name" - }, { "cIdentifier" : "g_signal_list_ids", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'n_ids' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.signal_list_ids" }, - { - "cIdentifier" : "g_signal_lookup", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.signal_lookup" - }, - { - "cIdentifier" : "g_signal_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.signal_name" - }, { "cIdentifier" : "g_signal_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'accumulator': callback 'GObject.SignalAccumulator' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.signal_new" }, { "cIdentifier" : "g_signal_new_class_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'class_handler': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.signal_new_class_handler" }, { "cIdentifier" : "g_signal_new_valist", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'class_closure' type 'Closure?' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_new_valist" }, { "cIdentifier" : "g_signal_newv", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'class_closure' type 'Closure?' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_newv" }, { "cIdentifier" : "g_signal_override_class_closure", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'class_closure' type 'Closure' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_override_class_closure" }, { "cIdentifier" : "g_signal_override_class_handler", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'class_handler': callback 'GObject.Callback' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.signal_override_class_handler" }, { "cIdentifier" : "g_signal_parse_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'signal_id_p' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.signal_parse_name" }, { "cIdentifier" : "g_signal_query", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'query' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.signal_query" }, - { - "cIdentifier" : "g_signal_remove_emission_hook", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.signal_remove_emission_hook" - }, { "cIdentifier" : "g_signal_set_va_marshaller", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'va_marshaller': callback 'GObject.VaClosureMarshal' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.signal_set_va_marshaller" }, { "cIdentifier" : "g_signal_stop_emission", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_stop_emission" }, { "cIdentifier" : "g_signal_stop_emission_by_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'instance' type 'Object' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.signal_stop_emission_by_name" }, { "cIdentifier" : "g_signal_type_cclosure_new", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'Closure' is not yet generated (category: needsRecord)", "reason" : "unknownType", "symbol" : "GObject.signal_type_cclosure_new" }, { "cIdentifier" : "g_source_set_closure", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'source' type 'GLib.Source' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.source_set_closure" }, { "cIdentifier" : "g_source_set_dummy_callback", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'source' type 'GLib.Source' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.source_set_dummy_callback" }, { "cIdentifier" : "g_strdup_value_contents", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'value' type 'Value' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.strdup_value_contents" }, { "cIdentifier" : "g_type_add_class_cache_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'cache_func': callback 'GObject.TypeClassCacheFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.type_add_class_cache_func" }, - { - "cIdentifier" : "g_type_add_class_private", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_add_class_private" - }, - { - "cIdentifier" : "g_type_add_instance_private", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_add_instance_private" - }, { "cIdentifier" : "g_type_add_interface_check", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'check_func': callback 'GObject.TypeInterfaceCheckFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.type_add_interface_check" }, { "cIdentifier" : "g_type_add_interface_dynamic", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'plugin' type 'TypePlugin' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.type_add_interface_dynamic" }, { "cIdentifier" : "g_type_add_interface_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'info': 'GObject.InterfaceInfo' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_add_interface_static" }, { "cIdentifier" : "g_type_check_class_cast", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'g_class': 'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_class_cast" }, { "cIdentifier" : "g_type_check_class_is_a", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'g_class': 'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_class_is_a" }, { "cIdentifier" : "g_type_check_instance", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_instance" }, { "cIdentifier" : "g_type_check_instance_cast", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_instance_cast" }, { "cIdentifier" : "g_type_check_instance_is_a", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_instance_is_a" }, { "cIdentifier" : "g_type_check_instance_is_fundamentally_a", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_check_instance_is_fundamentally_a" }, - { - "cIdentifier" : "g_type_check_is_value_type", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_check_is_value_type" - }, { "cIdentifier" : "g_type_check_value", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'value' type 'Value' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.type_check_value" }, { "cIdentifier" : "g_type_check_value_holds", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'value' type 'Value' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.type_check_value_holds" }, { "cIdentifier" : "g_type_children", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'n_children' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.type_children" }, { "cIdentifier" : "g_type_class_adjust_private_offset", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'private_size_or_offset' C type 'gint*' is a pointer", "reason" : "unknownType", "symbol" : "GObject.type_class_adjust_private_offset" }, { "cIdentifier" : "g_type_class_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_class_get" }, { "cIdentifier" : "g_type_class_peek", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_class_peek" }, { "cIdentifier" : "g_type_class_peek_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_class_peek_static" }, { "cIdentifier" : "g_type_class_ref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_class_ref" }, { "cIdentifier" : "g_type_create_instance", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_create_instance" }, { "cIdentifier" : "g_type_default_interface_get", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeInterface' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_default_interface_get" }, { "cIdentifier" : "g_type_default_interface_peek", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeInterface' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_default_interface_peek" }, { "cIdentifier" : "g_type_default_interface_ref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeInterface' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_default_interface_ref" }, { "cIdentifier" : "g_type_default_interface_unref", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'g_iface': 'GObject.TypeInterface' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_default_interface_unref" }, - { - "cIdentifier" : "g_type_depth", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_depth" - }, - { - "cIdentifier" : "g_type_ensure", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_ensure" - }, { "cIdentifier" : "g_type_free_instance", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_free_instance" }, - { - "cIdentifier" : "g_type_from_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_from_name" - }, - { - "cIdentifier" : "g_type_fundamental", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_fundamental" - }, - { - "cIdentifier" : "g_type_fundamental_next", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_fundamental_next" - }, - { - "cIdentifier" : "g_type_get_instance_count", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_get_instance_count" - }, { "cIdentifier" : "g_type_get_plugin", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'TypePlugin' is not yet generated (category: needsClass)", "reason" : "unknownType", "symbol" : "GObject.type_get_plugin" }, - { - "cIdentifier" : "g_type_get_qdata", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_get_qdata" - }, - { - "cIdentifier" : "g_type_get_type_registration_serial", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_get_type_registration_serial" - }, - { - "cIdentifier" : "g_type_init", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_init" - }, - { - "cIdentifier" : "g_type_init_with_debug_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_init_with_debug_flags" - }, - { - "cIdentifier" : "g_type_interface_add_prerequisite", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_interface_add_prerequisite" - }, { "cIdentifier" : "g_type_interface_get_plugin", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "return type 'TypePlugin' is not yet generated (category: needsClass)", "reason" : "unknownType", "symbol" : "GObject.type_interface_get_plugin" }, - { - "cIdentifier" : "g_type_interface_instantiatable_prerequisite", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_interface_instantiatable_prerequisite" - }, { "cIdentifier" : "g_type_interface_peek", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance_class': 'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_interface_peek" }, { "cIdentifier" : "g_type_interface_prerequisites", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'n_prerequisites' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.type_interface_prerequisites" }, { "cIdentifier" : "g_type_interfaces", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'n_interfaces' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.type_interfaces" }, - { - "cIdentifier" : "g_type_is_a", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_is_a" - }, - { - "cIdentifier" : "g_type_name", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_name" - }, { "cIdentifier" : "g_type_name_from_class", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'g_class': 'GObject.TypeClass' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_name_from_class" }, { "cIdentifier" : "g_type_name_from_instance", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'instance': 'GObject.TypeInstance' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_name_from_instance" }, - { - "cIdentifier" : "g_type_next_base", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_next_base" - }, - { - "cIdentifier" : "g_type_parent", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_parent" - }, - { - "cIdentifier" : "g_type_qname", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_qname" - }, { "cIdentifier" : "g_type_query", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'query' has direction=out", + "reason" : "outParameter", "symbol" : "GObject.type_query" }, { "cIdentifier" : "g_type_register_dynamic", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "parameter 'plugin' type 'TypePlugin' is not yet generated", "reason" : "unknownType", "symbol" : "GObject.type_register_dynamic" }, { "cIdentifier" : "g_type_register_fundamental", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'info': 'GObject.TypeInfo' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_register_fundamental" }, { "cIdentifier" : "g_type_register_static", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'info': 'GObject.TypeInfo' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_register_static" }, { "cIdentifier" : "g_type_register_static_simple", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'class_init': callback 'GObject.ClassInitFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.type_register_static_simple" }, { "cIdentifier" : "g_type_remove_class_cache_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'cache_func': callback 'GObject.TypeClassCacheFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.type_remove_class_cache_func" }, { "cIdentifier" : "g_type_remove_interface_check", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'check_func': callback 'GObject.TypeInterfaceCheckFunc' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.type_remove_interface_check" }, - { - "cIdentifier" : "g_type_set_qdata", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_set_qdata" - }, - { - "cIdentifier" : "g_type_test_flags", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.type_test_flags" - }, { "cIdentifier" : "g_type_value_table_peek", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "'GObject.TypeValueTable' has no GType registration or lifetime functions", + "reason" : "plainRecord", "symbol" : "GObject.type_value_table_peek" }, { "cIdentifier" : "g_value_register_transform_func", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", + "detail" : "parameter 'transform_func': callback 'GObject.ValueTransform' not yet supported as a mapped type", + "reason" : "callbackWithoutUserData", "symbol" : "GObject.value_register_transform_func" }, - { - "cIdentifier" : "g_value_type_compatible", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.value_type_compatible" - }, - { - "cIdentifier" : "g_value_type_transformable", - "detail" : "function planned for Phase C (needs marshalling maturity)", - "reason" : "unknownType", - "symbol" : "GObject.value_type_transformable" - }, { "cIdentifier" : "g_variant_get_gtype", - "detail" : "function planned for Phase C (needs marshalling maturity)", + "detail" : "C symbol 'g_variant_get_gtype' is not exported by the system library", "reason" : "unknownType", "symbol" : "GObject.variant_get_gtype" } ], "module" : "GObject", "stats" : { - "boundCallables" : 0, - "boundTypes" : 56, - "totalCallables" : 0, - "totalTypes" : 307 + "boundCallables" : 34, + "boundTypes" : 60, + "totalCallables" : 185, + "totalTypes" : 122 } } diff --git a/monorepo-config.toml b/monorepo-config.toml deleted file mode 100644 index 58c85ba..0000000 --- a/monorepo-config.toml +++ /dev/null @@ -1,10 +0,0 @@ -output_dir = "/tmp/monorepo-gen" - -[packages.GLib] -gir = "/usr/share/gir-1.0/GLib-2.0.gir" - -[packages.GObject] -gir = "/usr/share/gir-1.0/GObject-2.0.gir" - -[packages.Gio] -gir = "/usr/share/gir-1.0/Gio-2.0.gir" diff --git a/scripts/compile-gate.sh b/scripts/compile-gate.sh new file mode 100755 index 0000000..e221962 --- /dev/null +++ b/scripts/compile-gate.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +# compile-gate.sh — the generator's primary acceptance gate. +# +# Generates the tier's monorepo from configs/tierN.toml, then requires the +# generated package to `swift build` with ZERO errors. Pass/fail only: error +# counts are not a metric. Also diffs each module's skip report against the +# committed baseline in docs/skip-baseline/tierN/ (if present) so that new +# skips in supported categories fail loudly. +# +# Usage: +# scripts/compile-gate.sh [--fresh] +# +# 1..6 (tier1 = GLib+GObject ... tier6 = full stack), or 'all' +# --fresh remove the tier's output directory before generating (use when +# the generated file set shrinks and stale files would linger) +# +# Output goes to ${TMPDIR:-/tmp}/swift-gtk-gen-gate/tier-N; a stable path so +# incremental swift builds stay fast between runs. + +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +GATE_ROOT="${TMPDIR:-/tmp}/swift-gtk-gen-gate" + +TIER_ARG="${1:-}" +FRESH=0 +[[ "${2:-}" == "--fresh" ]] && FRESH=1 + +if [[ -z "$TIER_ARG" ]]; then + echo "usage: $0 [--fresh]" >&2 + exit 2 +fi + +if [[ "$TIER_ARG" == "all" ]]; then + TIERS=(1 2 3 4 5 6) +else + TIERS=("$TIER_ARG") +fi + +echo "==> Building generator" +swift build --package-path "$ROOT" +BIN="$(swift build --package-path "$ROOT" --show-bin-path)/swift-gtk-gen" + +FAILED=0 + +run_tier() { + local tier="$1" + local config="$ROOT/configs/tier${tier}.toml" + local out="$GATE_ROOT/tier-${tier}" + + if [[ ! -f "$config" ]]; then + echo "!! tier $tier: missing $config" >&2 + return 1 + fi + + if [[ "$FRESH" == 1 ]]; then + rm -rf "$out" + fi + mkdir -p "$out" + + echo "==> Tier $tier: generating into $out" + if ! "$BIN" --monorepo-config "$config" --output "$out" --skip-report >"$out/generate.log" 2>&1; then + echo "!! tier $tier: GENERATION FAILED (see $out/generate.log)" >&2 + tail -n 20 "$out/generate.log" >&2 + return 1 + fi + + echo "==> Tier $tier: swift build" + if ! swift build --package-path "$out" >"$out/build.log" 2>&1; then + echo "!! tier $tier: BUILD FAILED (see $out/build.log)" >&2 + grep -m 10 'error:' "$out/build.log" >&2 || tail -n 20 "$out/build.log" >&2 + return 1 + fi + + local baseline="$ROOT/docs/skip-baseline/tier${tier}" + if [[ -d "$baseline" ]]; then + echo "==> Tier $tier: diffing skip reports against $baseline" + if ! diff -ru "$baseline" "$out/skip-reports" >"$out/skip-diff.log" 2>&1; then + echo "!! tier $tier: SKIP REPORT CHANGED (see $out/skip-diff.log)" >&2 + head -n 40 "$out/skip-diff.log" >&2 + echo " If the change is intentional (coverage grew), refresh the baseline:" >&2 + echo " cp -r $out/skip-reports/. $baseline/" >&2 + return 1 + fi + else + echo "==> Tier $tier: no skip baseline at $baseline (skipping diff)" + fi + + echo "==> Tier $tier: PASS" +} + +for tier in "${TIERS[@]}"; do + if ! run_tier "$tier"; then + FAILED=1 + fi +done + +exit "$FAILED" diff --git a/scripts/regression-test.sh b/scripts/regression-test.sh deleted file mode 100755 index 3813780..0000000 --- a/scripts/regression-test.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -# Regression test for swift-gtk-gen output. -# Run this after any change to CodeGen.swift to catch regressions. -# -# Steps: -# 1. Build the generator -# 2. Generate Gtk-4.0 wrapper from the system .gir file -# 3. Run unit tests -# 4. Try to build the generated wrapper; report dependency-ignored errors -# 5. Lint the generated wrapper - -set -euo pipefail - -cd "$(dirname "$0")/.." - -TEST_DIR="/tmp/regression-test-$$" -BIN_PATH=".build/debug/swift-gtk-gen" - -echo "=== swift-gtk-gen regression test ===" -echo "Test output directory: $TEST_DIR" - -# Cleanup trap (runs on exit, even on failure) -trap 'rm -rf "$TEST_DIR" /tmp/build-output.log' EXIT - -# Ensure binary is built -if [ ! -x "$BIN_PATH" ]; then - echo "Binary not found at $BIN_PATH — running 'swift build' first..." - swift build -fi - -# Generate -rm -rf "$TEST_DIR" -mkdir -p "$TEST_DIR" -"$BIN_PATH" \ - --gir-file /usr/share/gir-1.0/Gtk-4.0.gir \ - --output "$TEST_DIR" \ - --generate-all 2>/dev/null - -# Run unit tests -echo "" -echo "=== Unit tests ===" -swift test 2>&1 | tail -5 - -# Count errors -echo "" -echo "=== Generated output metrics ===" -file_count=$(find "$TEST_DIR" -name "*.swift" | wc -l) -echo "Generated Swift files: $file_count" - -# Try to build the generated code -echo "" -echo "=== Build generated code ===" -if swift build --package-path "$TEST_DIR" 2>&1 > /tmp/build-output.log; then - echo "Generated code BUILD: PASS" -else - total=$(grep -c "error:" /tmp/build-output.log || echo 0) - cannot_find=$(grep "error:" /tmp/build-output.log | grep -c "cannot find" || echo 0) - fixable=$((total - cannot_find)) - echo "Generated code BUILD: FAIL" - echo " Total errors: $total" - echo " Cannot find (deps): $cannot_find" - echo " Fixable errors: $fixable" - if [ "$fixable" -gt 0 ]; then - echo "" - echo "First 20 fixable errors:" - grep "error:" /tmp/build-output.log | grep -v "cannot find" | head -20 - fi -fi - -# Lint -echo "" -echo "=== Lint ===" -cd "$(dirname "$0")/.." -lint_errors=$(swift format lint --configuration .swift-format --recursive "$TEST_DIR" 2>&1 | grep -c "error:" || echo 0) -echo "Lint errors: $lint_errors" -if [ "$lint_errors" -gt 0 ]; then - echo "First 10 lint errors:" - swift format lint --configuration .swift-format --recursive "$TEST_DIR" 2>&1 | grep "error:" | head -10 -fi - -echo "" -echo "=== Done ==="