From 81725febf8d3e30caf6f56e816f7ab7b6a4578d9 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Sun, 31 Mar 2024 22:17:36 -0400 Subject: [PATCH] Reorganize output directories and files --- .../SwiftProjection+Module.swift | 13 +- .../Writing/ABIProjectionType.swift | 29 ----- .../Sources/SwiftWinRT/Writing/CAbi.swift | 35 +++--- .../Writing/COMInteropExtension.swift | 39 +----- .../SwiftWinRT/Writing/ExeManifest.swift | 8 +- .../SwiftWinRT/Writing/NamespaceAlias.swift | 12 -- .../SwiftWinRT/Writing/SwiftPackageFile.swift | 11 +- .../SwiftWinRT/writeProjectionFiles.swift | 113 +++++++++++++++--- 8 files changed, 131 insertions(+), 129 deletions(-) diff --git a/Generator/Sources/ProjectionModel/SwiftProjection+Module.swift b/Generator/Sources/ProjectionModel/SwiftProjection+Module.swift index d8b43ce7..96b48ffe 100644 --- a/Generator/Sources/ProjectionModel/SwiftProjection+Module.swift +++ b/Generator/Sources/ProjectionModel/SwiftProjection+Module.swift @@ -7,7 +7,7 @@ extension SwiftProjection { public unowned let projection: SwiftProjection public let name: String public let flattenNamespaces: Bool - public private(set) var typeDefinitionsByNamespace = OrderedDictionary>() + private var _typeDefinitions = OrderedSet() public private(set) var closedGenericTypesByDefinition = [TypeDefinition: [[TypeNode]]]() private(set) var weakReferences: Set = [] @@ -17,21 +17,26 @@ extension SwiftProjection { self.flattenNamespaces = flattenNamespaces } + public var typeDefinitions: OrderedSet { + _typeDefinitions.sort { $0.fullName < $1.fullName } + return _typeDefinitions + } + public var references: [Module] { weakReferences.map { $0.target } } - public var isEmpty: Bool { typeDefinitionsByNamespace.isEmpty } + public var isEmpty: Bool { _typeDefinitions.isEmpty } public func addAssembly(_ assembly: Assembly, documentation: AssemblyDocumentation? = nil) { projection.assembliesToModules[assembly] = AssemblyEntry(module: self, documentation: documentation) } public func hasTypeDefinition(_ type: TypeDefinition) -> Bool { - typeDefinitionsByNamespace[Module.getNamespaceOrEmpty(type)]?.contains(type) ?? false + _typeDefinitions.contains(type) } public func addTypeDefinition(_ type: TypeDefinition) { precondition(projection.getModule(type.assembly) === self) - typeDefinitionsByNamespace[Module.getNamespaceOrEmpty(type), default: Set()].insert(type) + _typeDefinitions.append(type) } public func addClosedGenericType(_ type: BoundType) { diff --git a/Generator/Sources/SwiftWinRT/Writing/ABIProjectionType.swift b/Generator/Sources/SwiftWinRT/Writing/ABIProjectionType.swift index 61760bb8..e13b5e6b 100644 --- a/Generator/Sources/SwiftWinRT/Writing/ABIProjectionType.swift +++ b/Generator/Sources/SwiftWinRT/Writing/ABIProjectionType.swift @@ -5,35 +5,6 @@ import ProjectionModel import CodeWriters import struct Foundation.UUID -internal func writeABIProjectionsFile(module: SwiftProjection.Module, toPath path: String) throws { - let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) - writeGeneratedCodePreamble(to: writer) - writeModulePreamble(module, to: writer) - - for (_, typeDefinitions) in module.typeDefinitionsByNamespace { - for typeDefinition in typeDefinitions.sorted(by: { $0.fullName < $1.fullName }) { - if let classDefinition = typeDefinition as? ClassDefinition, classDefinition.isStatic { continue } - guard typeDefinition.isPublic, - SupportModules.WinRT.getBuiltInTypeKind(typeDefinition) != .special, - try !typeDefinition.hasAttribute(ApiContractAttribute.self) else { continue } - - writer.writeMarkComment(typeDefinition.fullName) - try writeABIProjectionConformance(typeDefinition, genericArgs: nil, projection: module.projection, to: writer) - } - } - - let closedGenericTypesByDefinition = module.closedGenericTypesByDefinition - .sorted { $0.key.fullName < $1.key.fullName } - for (typeDefinition, instantiations) in closedGenericTypesByDefinition { - guard SupportModules.WinRT.getBuiltInTypeKind(typeDefinition) != .special else { continue } - - for genericArgs in instantiations { - writer.writeMarkComment(try WinRTTypeName.from(type: typeDefinition.bindType(genericArgs: genericArgs)).description) - try writeABIProjectionConformance(typeDefinition, genericArgs: genericArgs, projection: module.projection, to: writer) - } - } -} - /// Writes a type or extension providing the ABIProjection conformance for a given projected WinRT type. internal func writeABIProjectionConformance(_ typeDefinition: TypeDefinition, genericArgs: [TypeNode]?, projection: SwiftProjection, to writer: SwiftSourceFileWriter) throws { if SupportModules.WinRT.getBuiltInTypeKind(typeDefinition) == .definitionAndProjection { diff --git a/Generator/Sources/SwiftWinRT/Writing/CAbi.swift b/Generator/Sources/SwiftWinRT/Writing/CAbi.swift index 655f627e..a357cad5 100644 --- a/Generator/Sources/SwiftWinRT/Writing/CAbi.swift +++ b/Generator/Sources/SwiftWinRT/Writing/CAbi.swift @@ -38,11 +38,9 @@ internal func writeCAbiFile(module: SwiftProjection.Module, toPath path: String) fileprivate func getSortedEnums(module: SwiftProjection.Module) throws -> [EnumDefinition] { var enumDefinitions = [EnumDefinition]() - for (_, typeDefinitions) in module.typeDefinitionsByNamespace { - for typeDefinition in typeDefinitions { - guard let enumDefinition = typeDefinition as? EnumDefinition else { continue } - enumDefinitions.append(enumDefinition) - } + for typeDefinition in module.typeDefinitions { + guard let enumDefinition = typeDefinition as? EnumDefinition else { continue } + enumDefinitions.append(enumDefinition) } enumDefinitions.sort { $0.fullName < $1.fullName } @@ -53,12 +51,9 @@ fileprivate func getSortedEnums(module: SwiftProjection.Module) throws -> [EnumD fileprivate func getSortedStructs(module: SwiftProjection.Module) throws -> [StructDefinition] { // Create an initial deterministic ordering of structs var sortedByFullName = [StructDefinition]() - for (_, typeDefinitions) in module.typeDefinitionsByNamespace { - for typeDefinition in typeDefinitions { - if let structDefinition = typeDefinition as? StructDefinition { - sortedByFullName.append(structDefinition) - } - } + for typeDefinition in module.typeDefinitions { + guard let structDefinition = typeDefinition as? StructDefinition else { continue } + sortedByFullName.append(structDefinition) } sortedByFullName.sort { $0.fullName < $1.fullName } @@ -90,16 +85,14 @@ fileprivate func getSortedInterfaces(module: SwiftProjection.Module) throws -> [ var interfacesByMangledName = OrderedDictionary() // Add nongeneric type definitions - for (_, typeDefinitions) in module.typeDefinitionsByNamespace { - for typeDefinition in typeDefinitions { - guard typeDefinition.isReferenceType else { continue } - guard !(typeDefinition is ClassDefinition) else { continue } - guard typeDefinition.genericArity == 0 else { continue } - - let type = typeDefinition.bindType() - let mangledName = try CAbi.mangleName(type: type) - interfacesByMangledName[mangledName] = type - } + for typeDefinition in module.typeDefinitions { + guard typeDefinition.isReferenceType else { continue } + guard !(typeDefinition is ClassDefinition) else { continue } + guard typeDefinition.genericArity == 0 else { continue } + + let type = typeDefinition.bindType() + let mangledName = try CAbi.mangleName(type: type) + interfacesByMangledName[mangledName] = type } // Add closed generic type instanciations diff --git a/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift b/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift index 3eebbe04..435c2ff5 100644 --- a/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift +++ b/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift @@ -5,43 +5,6 @@ import ProjectionModel import CodeWriters import struct Foundation.UUID -/// Writes a file that extends COMInterop for every COM interface with -/// methods that translate from the Swift shape to the ABI shape. -internal func writeCOMInteropExtensionsFile(module: SwiftProjection.Module, toPath path: String) throws { - let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) - writeGeneratedCodePreamble(to: writer) - writeModulePreamble(module, to: writer) - - // Gather bound interfaces and delegates, generic or not, sorted by ABI name - var boundAbiTypes = [(interface: BoundType, abiName: String)]() - for (_, typeDefinitions) in module.typeDefinitionsByNamespace { - for typeDefinition in typeDefinitions { - guard typeDefinition.genericArity == 0 else { continue } - guard typeDefinition is InterfaceDefinition || typeDefinition is DelegateDefinition else { continue } - let boundType = typeDefinition.bindType() - boundAbiTypes.append((boundType, try CAbi.mangleName(type: boundType))) - } - } - - for (typeDefinition, instantiations) in module.closedGenericTypesByDefinition { - assert(typeDefinition is InterfaceDefinition || typeDefinition is DelegateDefinition) - for genericArgs in instantiations { - let boundType = typeDefinition.bindType(genericArgs: genericArgs) - boundAbiTypes.append((boundType, try CAbi.mangleName(type: boundType))) - } - } - - // Write the COMInterop extension for each interface - boundAbiTypes.sort { $0.abiName < $1.abiName } - for (boundType, _) in boundAbiTypes { - // IReference is special cased, with a single definition for all generic instantiations - guard boundType.definition.fullName != "Windows.Foundation.IReference`1" else { continue } - - writer.writeMarkComment(try WinRTTypeName.from(type: boundType).description) - try writeCOMInteropExtension(abiType: boundType, projection: module.projection, to: writer) - } -} - fileprivate enum ABIInterfaceUsage { case activationFactory case composableFactory @@ -65,7 +28,7 @@ fileprivate enum ABIInterfaceUsage { } } -fileprivate func writeCOMInteropExtension(abiType: BoundType, projection: SwiftProjection, to writer: SwiftSourceFileWriter) throws { +internal func writeCOMInteropExtension(abiType: BoundType, projection: SwiftProjection, to writer: SwiftSourceFileWriter) throws { let abiSwiftType = try projection.toABIType(abiType) let visibility: SwiftVisibility = abiType.genericArgs.isEmpty ? .public : .internal diff --git a/Generator/Sources/SwiftWinRT/Writing/ExeManifest.swift b/Generator/Sources/SwiftWinRT/Writing/ExeManifest.swift index 46ec0ad2..f105947e 100644 --- a/Generator/Sources/SwiftWinRT/Writing/ExeManifest.swift +++ b/Generator/Sources/SwiftWinRT/Writing/ExeManifest.swift @@ -10,11 +10,9 @@ internal func writeExeManifestFile(projectionConfig: ProjectionConfig, projectio guard let moduleConfig = projectionConfig.modules[module.name], let fileNameInManifest = moduleConfig.fileNameInManifest else { continue } - for typeDefinitions in module.typeDefinitionsByNamespace.values { - for typeDefinition in typeDefinitions { - guard typeDefinition is ClassDefinition else { continue } - activatableClassesPerFileName[fileNameInManifest, default: []].append(typeDefinition.fullName) - } + for typeDefinition in module.typeDefinitions { + guard typeDefinition is ClassDefinition else { continue } + activatableClassesPerFileName[fileNameInManifest, default: []].append(typeDefinition.fullName) } } diff --git a/Generator/Sources/SwiftWinRT/Writing/NamespaceAlias.swift b/Generator/Sources/SwiftWinRT/Writing/NamespaceAlias.swift index 1ae308a4..d1567a49 100644 --- a/Generator/Sources/SwiftWinRT/Writing/NamespaceAlias.swift +++ b/Generator/Sources/SwiftWinRT/Writing/NamespaceAlias.swift @@ -2,18 +2,6 @@ import CodeWriters import DotNetMetadata import ProjectionModel -internal func writeNamespaceAliasesFile(typeDefinitions: [TypeDefinition], module: SwiftProjection.Module, toPath path: String) throws { - let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) - writeGeneratedCodePreamble(to: writer) - writer.writeImport(module: module.name) - - for typeDefinition in typeDefinitions.sorted(by: { $0.fullName < $1.fullName }) { - guard typeDefinition.isPublic else { continue } - - try writeNamespaceAlias(typeDefinition, projection: module.projection, to: writer) - } -} - internal func writeNamespaceAlias(_ typeDefinition: TypeDefinition, projection: SwiftProjection, to writer: SwiftSourceFileWriter) throws { try writer.writeTypeAlias( visibility: SwiftProjection.toVisibility(typeDefinition.visibility), diff --git a/Generator/Sources/SwiftWinRT/Writing/SwiftPackageFile.swift b/Generator/Sources/SwiftWinRT/Writing/SwiftPackageFile.swift index 7b0ed5a7..25eb14b3 100644 --- a/Generator/Sources/SwiftWinRT/Writing/SwiftPackageFile.swift +++ b/Generator/Sources/SwiftWinRT/Writing/SwiftPackageFile.swift @@ -1,4 +1,5 @@ import CodeWriters +import Collections import DotNetMetadata import ProjectionModel import struct Foundation.URL @@ -47,7 +48,15 @@ func writeSwiftPackageFile(_ projection: SwiftProjection, supportPackageLocation // Namespace modules if !module.flattenNamespaces { - for (namespace, _) in module.typeDefinitionsByNamespace { + var namespaces = OrderedSet() + for typeDefinition in module.typeDefinitions { + guard let namespace = typeDefinition.namespace else { continue } + namespaces.append(namespace) + } + + namespaces.sort() + + for namespace in namespaces { var namespaceModuleTarget = SwiftPackage.Target( name: module.getNamespaceModuleName(namespace: namespace)) let compactNamespace = SwiftProjection.toCompactNamespace(namespace) diff --git a/Generator/Sources/SwiftWinRT/writeProjectionFiles.swift b/Generator/Sources/SwiftWinRT/writeProjectionFiles.swift index 2d0dc47a..ca13bdce 100644 --- a/Generator/Sources/SwiftWinRT/writeProjectionFiles.swift +++ b/Generator/Sources/SwiftWinRT/writeProjectionFiles.swift @@ -19,30 +19,38 @@ internal func writeProjectionFiles(_ projection: SwiftProjection, generateComman try writeCAbiFile(module: module, toPath: "\(abiModuleIncludeDirectoryPath)\\\(module.name).h") try writeClassLoaderGlobalFile(module: module, toPath: "\(assemblyModuleDirectoryPath)\\ClassLoader.swift") - try writeCOMInteropExtensionsFile(module: module, toPath: "\(assemblyModuleDirectoryPath)\\COMInterop.swift") - try writeABIProjectionsFile(module: module, toPath: "\(assemblyModuleDirectoryPath)\\ABIProjections.swift") - for (namespace, typeDefinitions) in module.typeDefinitionsByNamespace { - let compactNamespace = SwiftProjection.toCompactNamespace(namespace) - print("Generating types for namespace \(namespace)...") + for typeDefinition in module.typeDefinitions + Array(module.closedGenericTypesByDefinition.keys) { + guard try hasSwiftDefinition(typeDefinition) else { continue } + + let compactNamespace = SwiftProjection.toCompactNamespace(typeDefinition.namespace!) + let assemblyNamespaceDirectoryPath = "\(assemblyModuleDirectoryPath)\\\(compactNamespace)" - var typeDefinitions = Array(typeDefinitions) - try typeDefinitions.removeAll { - try !$0.isPublic || SupportModules.WinRT.getBuiltInTypeKind($0) == .special || $0.hasAttribute(ApiContractAttribute.self) + if module.typeDefinitions.contains(typeDefinition) { + try writeTypeDefinitionFile(typeDefinition, module: module, toPath: "\(assemblyNamespaceDirectoryPath)\\\(typeDefinition.nameWithoutGenericSuffix).swift") } - typeDefinitions.sort { $0.fullName < $1.fullName } - - // Write the type definition file - for typeDefinition in typeDefinitions { - let filePath = "\(assemblyModuleDirectoryPath)\\\(compactNamespace)\\\(typeDefinition.nameWithoutGenericSuffix).swift" - let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: filePath, directoryCreation: .ancestors)) - writeGeneratedCodePreamble(to: writer) - writeModulePreamble(module, to: writer) - try writeTypeDefinition(typeDefinition, projection: module.projection, to: writer) + + if (typeDefinition as? ClassDefinition)?.isStatic != true { + try writeABIProjectionConformanceFile(typeDefinition, module: module, + toPath: "\(assemblyNamespaceDirectoryPath)\\Projections\\\(typeDefinition.nameWithoutGenericSuffix)+Projection.swift") } + } - // Write the namespace aliases file - if !module.flattenNamespaces { + for abiType in try getABITypes(module: module) { + guard let namespace = abiType.definition.namespace else { continue } + let compactNamespace = SwiftProjection.toCompactNamespace(namespace) + let mangledName = try CAbi.mangleName(type: abiType) + try writeCOMInteropExtensionFile(abiType: abiType, module: module, + toPath: "\(assemblyModuleDirectoryPath)\\\(compactNamespace)\\COMInterop\\\(mangledName).swift") + } + + if !module.flattenNamespaces { + let typeDefinitionsByNamespace = OrderedDictionary(grouping: module.typeDefinitions, by: { $0.namespace }) + for (namespace, typeDefinitions) in typeDefinitionsByNamespace { + let typeDefinitions = try typeDefinitions.filter(hasSwiftDefinition) + guard !typeDefinitions.isEmpty else { continue } + + let compactNamespace = SwiftProjection.toCompactNamespace(namespace!) let namespaceAliasesPath = "\(moduleRootPath)\\Namespaces\\\(compactNamespace)\\Aliases.swift" try writeNamespaceAliasesFile(typeDefinitions: typeDefinitions, module: module, toPath: namespaceAliasesPath) } @@ -50,6 +58,73 @@ internal func writeProjectionFiles(_ projection: SwiftProjection, generateComman } } +fileprivate func hasSwiftDefinition(_ typeDefinition: TypeDefinition) throws -> Bool { + return try SupportModules.WinRT.getBuiltInTypeKind(typeDefinition) != .special + && !typeDefinition.hasAttribute(ApiContractAttribute.self) + && typeDefinition.isPublic +} + +fileprivate func writeTypeDefinitionFile(_ typeDefinition: TypeDefinition, module: SwiftProjection.Module, toPath path: String) throws { + let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) + writeGeneratedCodePreamble(to: writer) + writeModulePreamble(module, to: writer) + try writeTypeDefinition(typeDefinition, projection: module.projection, to: writer) +} + +fileprivate func writeABIProjectionConformanceFile(_ typeDefinition: TypeDefinition, module: SwiftProjection.Module, toPath path: String) throws { + let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) + writeGeneratedCodePreamble(to: writer) + writeModulePreamble(module, to: writer) + + if module.typeDefinitions.contains(typeDefinition) { + try writeABIProjectionConformance(typeDefinition, genericArgs: nil, projection: module.projection, to: writer) + } + + for genericArgs in module.closedGenericTypesByDefinition[typeDefinition] ?? [] { + let boundType = typeDefinition.bindType(genericArgs: genericArgs) + writer.writeMarkComment(try WinRTTypeName.from(type: boundType).description) + try writeABIProjectionConformance(typeDefinition, genericArgs: genericArgs, projection: module.projection, to: writer) + } +} + +fileprivate func getABITypes(module: SwiftProjection.Module) throws -> [BoundType] { + var abiTypes = [BoundType]() + for typeDefinition in module.typeDefinitions { + guard typeDefinition.genericArity == 0 else { continue } + guard typeDefinition is InterfaceDefinition || typeDefinition is DelegateDefinition else { continue } + abiTypes.append(typeDefinition.bindType()) + } + + for (typeDefinition, instantiations) in module.closedGenericTypesByDefinition { + // IReference is implemented generically in the support module. + if typeDefinition.namespace == "Windows.Foundation", typeDefinition.name == "IReference`1" { continue } + for genericArgs in instantiations { + abiTypes.append(typeDefinition.bindType(genericArgs: genericArgs)) + } + } + + return abiTypes +} + +fileprivate func writeCOMInteropExtensionFile(abiType: BoundType, module: SwiftProjection.Module, toPath path: String) throws { + let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) + writeGeneratedCodePreamble(to: writer) + writeModulePreamble(module, to: writer) + try writeCOMInteropExtension(abiType: abiType, projection: module.projection, to: writer) +} + +internal func writeNamespaceAliasesFile(typeDefinitions: [TypeDefinition], module: SwiftProjection.Module, toPath path: String) throws { + let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) + writeGeneratedCodePreamble(to: writer) + writer.writeImport(module: module.name) + + for typeDefinition in typeDefinitions.sorted(by: { $0.fullName < $1.fullName }) { + guard typeDefinition.isPublic else { continue } + + try writeNamespaceAlias(typeDefinition, projection: module.projection, to: writer) + } +} + fileprivate func writeClassLoaderGlobalFile(module: SwiftProjection.Module, toPath path: String) throws { let writer = SwiftSourceFileWriter(output: FileTextOutputStream(path: path, directoryCreation: .ancestors)) writeGeneratedCodePreamble(to: writer)