diff --git a/Generator/Sources/CodeWriters/Swift/SyntaxWriters/SourceFile.swift b/Generator/Sources/CodeWriters/Swift/SyntaxWriters/SourceFile.swift index 691f29c..c75e27f 100644 --- a/Generator/Sources/CodeWriters/Swift/SyntaxWriters/SourceFile.swift +++ b/Generator/Sources/CodeWriters/Swift/SyntaxWriters/SourceFile.swift @@ -24,6 +24,7 @@ public struct SwiftSourceFileWriter: SwiftDeclarationWriter { } public func writeExtension( + attributes: [SwiftAttribute] = [], type: SwiftType, protocolConformances: [SwiftType] = [], whereClauses: [String] = [], @@ -31,6 +32,7 @@ public struct SwiftSourceFileWriter: SwiftDeclarationWriter { var output = output output.beginLine(group: .alone) + writeAttributes(attributes) output.write("extension ") type.write(to: &output) writeInheritanceClause(protocolConformances) diff --git a/Generator/Sources/ProjectionModel/Projection+conversion.swift b/Generator/Sources/ProjectionModel/Projection+conversion.swift index 5609d87..34e1a45 100644 --- a/Generator/Sources/ProjectionModel/Projection+conversion.swift +++ b/Generator/Sources/ProjectionModel/Projection+conversion.swift @@ -83,6 +83,16 @@ extension Projection { : definitionBindingType.member(try Projection.toBindingInstantiationTypeName(genericArgs: type.genericArgs)) } + public static func getAvailableAttribute( + _ attributable: any Attributable, + deprecator: (any Attributable)? = nil) throws -> SwiftAttribute? { + guard let deprecatedAttribute = try attributable.findAttribute(WindowsMetadata.DeprecatedAttribute.self) + ?? deprecator?.findAttribute(WindowsMetadata.DeprecatedAttribute.self) else { return nil } + // DeprecatedAttribute tells us the ContractVersion in which an attribute was deprecated, + // but since apps should run on any future OS version, we can mark it as unconditionally deprecated. + return SwiftAttribute("available(*, deprecated, message: \"\(deprecatedAttribute.message)\")") + } + public static func getAttributes( _ attributable: any Attributable, deprecator: (any Attributable)? = nil) throws -> [SwiftAttribute] { @@ -99,11 +109,8 @@ extension Projection { } // Also add deprecation attributes - if let deprecatedAttribute = try attributable.findAttribute(WindowsMetadata.DeprecatedAttribute.self) - ?? deprecator?.findAttribute(WindowsMetadata.DeprecatedAttribute.self) { - // DeprecatedAttribute tells us the ContractVersion in which an attribute was deprecated, - // but since apps should run on any future OS version, we can mark it as unconditionally deprecated. - attributes.append(SwiftAttribute("available(*, deprecated, message: \"\(deprecatedAttribute.message)\")")) + if let availableAttribute = try getAvailableAttribute(attributable, deprecator: deprecator) { + attributes.append(availableAttribute) } return attributes diff --git a/Generator/Sources/SwiftWinRT/Writing/ABIBinding.swift b/Generator/Sources/SwiftWinRT/Writing/ABIBinding.swift index 9cf55b6..c288630 100644 --- a/Generator/Sources/SwiftWinRT/Writing/ABIBinding.swift +++ b/Generator/Sources/SwiftWinRT/Writing/ABIBinding.swift @@ -28,18 +28,7 @@ internal func writeABIBindingConformance(_ typeDefinition: TypeDefinition, gener if let enumDefinition = typeDefinition as? EnumDefinition { assert(genericArgs == nil) - let enumBindingProtocol = try projection.isSwiftEnumEligible(enumDefinition) - ? SupportModules.WinRT.closedEnumBinding : SupportModules.WinRT.openEnumBinding - try writer.writeExtension( - type: projection.toTypeReference(enumDefinition.bindType()), - protocolConformances: [ enumBindingProtocol ]) { writer in - // public static var typeName: String { "..." } - try writeTypeNameProperty(type: enumDefinition.bindType(), to: writer) - - // public static var ireferenceID: COM.COMInterfaceID { .init(...) } - // public static var ireferenceArrayID: COM.COMInterfaceID { .init(...) } - try writeIReferenceIDProperties(boxableType: enumDefinition.bindType(), to: writer) - } + try writeEnumBindingExtension(enumDefinition, projection: projection, to: writer) return } @@ -69,6 +58,7 @@ internal func writeABIBindingConformance(_ typeDefinition: TypeDefinition, gener // internal final class Boolean: WinRTBinding... {} // } try writer.writeExtension( + attributes: [ Projection.getAvailableAttribute(typeDefinition) ].compactMap { $0 }, type: projection.toBindingType(typeDefinition)) { writer in try writeInterfaceOrDelegateBindingType( typeDefinition.bindType(genericArgs: genericArgs), @@ -80,11 +70,32 @@ internal func writeABIBindingConformance(_ typeDefinition: TypeDefinition, gener // Generic type definition. Create a namespace for projections of specializations. // public enum IVectorBinding {} try writer.writeEnum( + attributes: [ Projection.getAvailableAttribute(typeDefinition) ].compactMap { $0 }, visibility: Projection.toVisibility(typeDefinition.visibility), name: projection.toBindingTypeName(typeDefinition)) { _ in } } } +/// Writes an extension to an enum to provide the ABIBinding conformance. +fileprivate func writeEnumBindingExtension( + _ enumDefinition: EnumDefinition, + projection: Projection, + to writer: SwiftSourceFileWriter) throws { + let enumBindingProtocol = try projection.isSwiftEnumEligible(enumDefinition) + ? SupportModules.WinRT.closedEnumBinding : SupportModules.WinRT.openEnumBinding + try writer.writeExtension( + attributes: [ Projection.getAvailableAttribute(enumDefinition) ].compactMap { $0 }, + type: projection.toTypeReference(enumDefinition.bindType()), + protocolConformances: [ enumBindingProtocol ]) { writer in + // public static var typeName: String { "..." } + try writeTypeNameProperty(type: enumDefinition.bindType(), to: writer) + + // public static var ireferenceID: COM.COMInterfaceID { .init(...) } + // public static var ireferenceArrayID: COM.COMInterfaceID { .init(...) } + try writeIReferenceIDProperties(boxableType: enumDefinition.bindType(), to: writer) + } +} + /// Writes an extension to a struct to provide the ABIBinding conformance. fileprivate func writeStructBindingExtension( _ structDefinition: StructDefinition, @@ -99,6 +110,7 @@ fileprivate func writeStructBindingExtension( // extension : IReferenceableBinding[, PODBinding] try writer.writeExtension( + attributes: [ Projection.getAvailableAttribute(structDefinition) ].compactMap { $0 }, type: .named(projection.toTypeName(structDefinition)), protocolConformances: protocolConformances) { writer in @@ -261,7 +273,10 @@ fileprivate func writeClassBindingType( ? SupportModules.WinRT.composableClassBinding : SupportModules.WinRT.runtimeClassBinding + // Runtimeclass bindings are classes so they can be found using NSClassFromString, + // which allows supporting instantiating the most derived class wrapper when returned from WinRT. try writer.writeClass( + attributes: [ Projection.getAvailableAttribute(classDefinition) ].compactMap { $0 }, visibility: Projection.toVisibility(classDefinition.visibility), name: projection.toBindingTypeName(classDefinition), protocolConformances: [ bindingProtocol ]) { writer throws in @@ -362,6 +377,7 @@ fileprivate func writeInterfaceOrDelegateBindingType( // Projections of generic instantiations are not owned by any specific module. // Making them internal avoids clashes between redundant definitions across modules. try writer.writeEnum( + attributes: [ Projection.getAvailableAttribute(type.definition) ].compactMap { $0 }, visibility: type.genericArgs.isEmpty ? Projection.toVisibility(type.definition.visibility) : .internal, name: name, protocolConformances: [ bindingProtocol ]) { writer throws in diff --git a/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift b/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift index 7a7464e..b2d0206 100644 --- a/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift +++ b/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift @@ -136,13 +136,14 @@ fileprivate func writeProtocol(_ interfaceDefinition: InterfaceDefinition, proje } fileprivate func writeProtocolTypeAlias(_ interfaceDefinition: InterfaceDefinition, projection: Projection, to writer: SwiftSourceFileWriter) throws { - writer.writeTypeAlias( + try writer.writeTypeAlias( documentation: projection.getDocumentationComment(interfaceDefinition), + attributes: [ Projection.getAvailableAttribute(interfaceDefinition) ].compactMap { $0 }, visibility: Projection.toVisibility(interfaceDefinition.visibility), - name: try projection.toTypeName(interfaceDefinition), + name: projection.toTypeName(interfaceDefinition), typeParams: interfaceDefinition.genericParams.map { $0.name }, target: .named( - try projection.toProtocolName(interfaceDefinition), + projection.toProtocolName(interfaceDefinition), genericArgs: interfaceDefinition.genericParams.map {.named($0.name) }).existential()) } @@ -152,8 +153,10 @@ fileprivate func writeNonthrowingPropertiesExtension( let getSetProperties = try interfaceDefinition.properties.filter { try $0.getter != nil } guard !getSetProperties.isEmpty else { return } - let typeName: String = try projection.toProtocolName(interfaceDefinition) - try writer.writeExtension(type: .named(typeName)) { writer in + let protocolType = SwiftType.named(try projection.toProtocolName(interfaceDefinition)) + try writer.writeExtension( + attributes: [ Projection.getAvailableAttribute(interfaceDefinition) ].compactMap { $0 }, + type: protocolType) { writer in for property in getSetProperties { try writeNonthrowingPropertyImplementation( property: property, static: false, projection: projection, to: writer)