From 5c215b25188d0e2049cfcee61fa2984cbbe1af03 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Thu, 4 Jan 2024 16:27:21 -0500 Subject: [PATCH] Add a CompileTest for "multi module" generation. - Add basic infrastructure to have Compile Tests. - Add a specific MultiModule CompileTest. - This ensure that with `import public` is properly handle and the generated code compiles even when a needed type is coming from a public import. - So the any relevant code changes are more visible, check the the generated code so the diffs for an changes related to the test will be easily reviewed. - The SPM plugin doesn't support multi module generation (https://github.com/apple/swift-protobuf/issues/1450), which is also why the code needs to be checked in, otherwise, it might simplify the tests. Note: The whole concept of CompileTests doesn't have to be a set up as distinct Swift Packages, but if we put the required targets in the main Package.swift, all projects using swift-protobuf would end up having the "overhead" of those test only targets, so I've errored on the side of a distinct package to make sure there is no impact of these tests on the folks using swift-protobuf. --- .github/workflows/build.yml | 3 + .gitignore | 2 + CompileTests/MultiModule/Package.swift | 40 ++++++ CompileTests/MultiModule/README.md | 7 ++ .../imports_a_publicly.pb.swift | 98 +++++++++++++++ .../imports_imports_a_publicly.pb.swift | 99 +++++++++++++++ .../MultiModule/Sources/ModuleA/a.pb.swift | 117 ++++++++++++++++++ .../MultiModule/Tests/Test1/test1.swift | 31 +++++ .../Tests/Test1/uses_a_transitively.pb.swift | 99 +++++++++++++++ .../MultiModule/Tests/Test2/test2.swift | 31 +++++ .../Tests/Test2/uses_a_transitively2.pb.swift | 100 +++++++++++++++ Makefile | 45 ++++++- .../ImportsAPublicly/imports_a_publicly.proto | 6 + .../imports_imports_a_publicly.proto | 6 + .../MultiModule/Sources/ModuleA/a.proto | 9 ++ .../Tests/Test1/uses_a_transitively.proto | 6 + .../Tests/Test2/uses_a_transitively2.proto | 6 + .../MultiModule/module_mappings.pbascii | 12 ++ .../imports_a_publicly.pb.swift | 98 +++++++++++++++ .../imports_imports_a_publicly.pb.swift | 99 +++++++++++++++ .../MultiModule/Sources/ModuleA/a.pb.swift | 117 ++++++++++++++++++ .../Tests/Test1/uses_a_transitively.pb.swift | 99 +++++++++++++++ .../Tests/Test2/uses_a_transitively2.pb.swift | 100 +++++++++++++++ 23 files changed, 1229 insertions(+), 1 deletion(-) create mode 100644 CompileTests/MultiModule/Package.swift create mode 100644 CompileTests/MultiModule/README.md create mode 100644 CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift create mode 100644 CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift create mode 100644 CompileTests/MultiModule/Sources/ModuleA/a.pb.swift create mode 100644 CompileTests/MultiModule/Tests/Test1/test1.swift create mode 100644 CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift create mode 100644 CompileTests/MultiModule/Tests/Test2/test2.swift create mode 100644 CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift create mode 100644 Protos/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.proto create mode 100644 Protos/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto create mode 100644 Protos/CompileTests/MultiModule/Sources/ModuleA/a.proto create mode 100644 Protos/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.proto create mode 100644 Protos/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.proto create mode 100644 Protos/CompileTests/MultiModule/module_mappings.pbascii create mode 100644 Reference/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift create mode 100644 Reference/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift create mode 100644 Reference/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift create mode 100644 Reference/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift create mode 100644 Reference/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c5eb529d8..fb3c62424 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -102,6 +102,9 @@ jobs: - name: Test SPM plugin working-directory: main run: make test-spm-plugin PROTOC=../protobuf/cmake_build/protoc + - name: Compilation Tests + working-directory: main + run: make compile-tests PROTOC=../protobuf/cmake_build/protoc sanitizer_testing: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ff388b930..941c0c823 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ xcbaselines /docs /build mined_words.txt +/CompileTests/MultiModule/.build +/CompileTests/MultiModule/.swiftpm /*DescriptorTestData.bin /Package.resolved diff --git a/CompileTests/MultiModule/Package.swift b/CompileTests/MultiModule/Package.swift new file mode 100644 index 000000000..4be7b44d2 --- /dev/null +++ b/CompileTests/MultiModule/Package.swift @@ -0,0 +1,40 @@ +// swift-tools-version: 5.6 + +import PackageDescription + +let package = Package( + name: "CompileTests", + dependencies: [ + .package(name: "swift-protobuf", path: "../..") + ], + targets: [ + .testTarget( + name: "Test1", + dependencies: ["ImportsAPublicly"] + ), + .testTarget( + name: "Test2", + dependencies: ["ImportsImportsAPublicly"] + ), + .target( + name: "ModuleA", + dependencies: [ + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + ] + ), + .target( + name: "ImportsAPublicly", + dependencies: [ + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + .target(name: "ModuleA"), + ] + ), + .target( + name: "ImportsImportsAPublicly", + dependencies: [ + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + .target(name: "ImportsAPublicly"), + ] + ), + ] +) diff --git a/CompileTests/MultiModule/README.md b/CompileTests/MultiModule/README.md new file mode 100644 index 000000000..245e25c16 --- /dev/null +++ b/CompileTests/MultiModule/README.md @@ -0,0 +1,7 @@ +# CompileTests/MultiModule + +This is a test case that uses sources generated into multiple modules and +ensures the generated code compiles with the cross modules references. + +This can't use the SwiftPM Plugin as that currently doesn't have support for the +module mappings. diff --git a/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift b/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift new file mode 100644 index 000000000..556b2ed19 --- /dev/null +++ b/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift @@ -0,0 +1,98 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ImportsAPublicly/imports_a_publicly.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct ImportsAPublicly: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension ImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "ImportsAPublicly" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 11: .same(proto: "a"), + 12: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 11: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 12: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 11) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 12) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: ImportsAPublicly, rhs: ImportsAPublicly) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift b/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift new file mode 100644 index 000000000..8a345f5d0 --- /dev/null +++ b/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift @@ -0,0 +1,99 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct ImportsImportsAPublicly: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension ImportsImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "ImportsImportsAPublicly" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 21: .same(proto: "a"), + 22: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 21: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 22: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 21) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 22) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: ImportsImportsAPublicly, rhs: ImportsImportsAPublicly) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift b/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift new file mode 100644 index 000000000..e456acc57 --- /dev/null +++ b/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift @@ -0,0 +1,117 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ModuleA/a.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public enum E: SwiftProtobuf.Enum { + public typealias RawValue = Int + case unset // = 0 + case a // = 1 + case b // = 2 + + public init() { + self = .unset + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .unset + case 1: self = .a + case 2: self = .b + default: return nil + } + } + + public var rawValue: Int { + switch self { + case .unset: return 0 + case .a: return 1 + case .b: return 2 + } + } + +} + +public struct A: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var e: E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _e: E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension E: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 0: .same(proto: "E_UNSET"), + 1: .same(proto: "E_A"), + 2: .same(proto: "E_B"), + ] +} + +extension A: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "A" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: A, rhs: A) -> Bool { + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/CompileTests/MultiModule/Tests/Test1/test1.swift b/CompileTests/MultiModule/Tests/Test1/test1.swift new file mode 100644 index 000000000..f186277bd --- /dev/null +++ b/CompileTests/MultiModule/Tests/Test1/test1.swift @@ -0,0 +1,31 @@ +import ImportsAPublicly +import ModuleA // Needed because `import public` doesn't help Swift + +import XCTest + +final class ExampleTests: XCTestCase { + func testA() { + let anA = A.with { $0.e = .a } + XCTAssertEqual(anA.e, .a) + } + + func testImportsAPublicly() { + let imports = ImportsAPublicly.with { $0.a.e = .a } + XCTAssertEqual(imports.a.e, .a) + } + + func testInterop() { + let anA = A.with { $0.e = .b } + let imports = ImportsAPublicly.with { + $0.a = anA + $0.e = .b + } + XCTAssertEqual(imports.a.e, imports.e) + let transtively = UsesATransitively.with { + $0.a = anA + $0.e = imports.e + } + XCTAssertEqual(transtively.a, anA) + XCTAssertEqual(transtively.e, imports.e) + } +} diff --git a/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift b/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift new file mode 100644 index 000000000..3bb4d6701 --- /dev/null +++ b/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift @@ -0,0 +1,99 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Tests/Test1/uses_a_transitively.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct UsesATransitively: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension UsesATransitively: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "UsesATransitively" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 101: .same(proto: "a"), + 102: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 101: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 102: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 101) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 102) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: UsesATransitively, rhs: UsesATransitively) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/CompileTests/MultiModule/Tests/Test2/test2.swift b/CompileTests/MultiModule/Tests/Test2/test2.swift new file mode 100644 index 000000000..e20ebd130 --- /dev/null +++ b/CompileTests/MultiModule/Tests/Test2/test2.swift @@ -0,0 +1,31 @@ +import ImportsImportsAPublicly +import ModuleA // Needed because `import public` doesn't help Swift + +import XCTest + +final class ExampleTests: XCTestCase { + func testA() { + let anA = A.with { $0.e = .a } + XCTAssertEqual(anA.e, .a) + } + + func testImportsImportsAPublicly() { + let imports = ImportsImportsAPublicly.with { $0.a.e = .a } + XCTAssertEqual(imports.a.e, .a) + } + + func testInterop() { + let anA = A.with { $0.e = .b } + let imports = ImportsImportsAPublicly.with { + $0.a = anA + $0.e = .b + } + XCTAssertEqual(imports.a.e, imports.e) + let transtively = UsesATransitively2.with { + $0.a = anA + $0.e = imports.e + } + XCTAssertEqual(transtively.a, anA) + XCTAssertEqual(transtively.e, imports.e) + } +} diff --git a/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift b/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift new file mode 100644 index 000000000..7dd0c210e --- /dev/null +++ b/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift @@ -0,0 +1,100 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Tests/Test2/uses_a_transitively2.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ImportsImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct UsesATransitively2: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension UsesATransitively2: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "UsesATransitively2" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 111: .same(proto: "a"), + 122: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 111: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 122: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 111) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 122) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: UsesATransitively2, rhs: UsesATransitively2) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Makefile b/Makefile index 8c7eee166..51c14fa7e 100644 --- a/Makefile +++ b/Makefile @@ -77,12 +77,16 @@ PROTOS_DIRS=Conformance protoc-gen-swiftTests SwiftProtobuf SwiftProtobufPluginL check-proto-files \ check-version-numbers \ clean \ + compile-tests \ + compile-tests-multimodule \ default \ docs \ install \ pod-lib-lint \ reference \ regenerate \ + regenerate-compiletests-multimodule-protos \ + regenerate-compiletests-protos \ regenerate-conformance-protos \ regenerate-fuzz-protos \ regenerate-library-protos \ @@ -93,6 +97,7 @@ PROTOS_DIRS=Conformance protoc-gen-swiftTests SwiftProtobuf SwiftProtobufPluginL test-everything \ test-plugin \ test-runtime \ + test-spm-plugin \ update-proto-files default: build @@ -182,11 +187,26 @@ test-plugin: build ${PROTOC_GEN_SWIFT} --tfiws_out=_test/$$d \ `find Protos/$$d -type f -name "*.proto"` || exit 1; \ done + @mkdir -p _test/CompileTests/MultiModule + ${GENERATE_SRCS} \ + -I Protos/CompileTests/MultiModule \ + --tfiws_opt=Visibility=Public \ + --tfiws_opt=ProtoPathModuleMappings=Protos/CompileTests/MultiModule/module_mappings.pbascii \ + --tfiws_out=_test/CompileTests/MultiModule \ + `(find Protos/CompileTests/MultiModule -type f -name "*.proto")` diff -ru _test Reference # Test the SPM plugin. test-spm-plugin: - env PROTOC_PATH=$(shell realpath ${PROTOC}) swift test --package-path PluginExamples + env PROTOC_PATH=$(shell realpath ${PROTOC}) ${SWIFT} test --package-path PluginExamples + +compile-tests: compile-tests-multimodule + +# Test that ensure generating public into multiple modules with `import public` +# yields buildable code. +compile-tests-multimodule: + ${SWIFT} test --package-path CompileTests/MultiModule + # Rebuild the reference files by running the local version of protoc-gen-swift # against our menagerie of sample protos. @@ -213,6 +233,13 @@ reference: build ${PROTOC_GEN_SWIFT} --tfiws_out=Reference/$$d \ `find Protos/$$d -type f -name "*.proto"` || exit 1; \ done + @mkdir -p Reference/CompileTests/MultiModule + ${GENERATE_SRCS} \ + -I Protos/CompileTests/MultiModule \ + --tfiws_opt=Visibility=Public \ + --tfiws_opt=ProtoPathModuleMappings=Protos/CompileTests/MultiModule/module_mappings.pbascii \ + --tfiws_out=Reference/CompileTests/MultiModule \ + `(find Protos/CompileTests/MultiModule -type f -name "*.proto")` # # Rebuild the generated .pb.swift test files by running @@ -228,6 +255,7 @@ regenerate: \ regenerate-fuzz-protos \ regenerate-plugin-protos \ regenerate-test-protos \ + regenerate-compiletests-protos \ regenerate-conformance-protos \ Tests/protoc-gen-swiftTests/DescriptorTestData.swift \ Tests/SwiftProtobufPluginLibraryTests/DescriptorTestData.swift @@ -419,6 +447,21 @@ regenerate-conformance-protos: build ${PROTOC_GEN_SWIFT} --tfiws_out=Sources/Conformance \ `find Protos/Conformance -type f -name "*.proto"` +# Rebuild just the protos used by the CompileTests. +regenerate-compiletests-protos: regenerate-compiletests-multimodule-protos + +# Update the CompileTests/MultiModule files. +# NOTE: Any changes here must be done of the "test-plugin" target so it +# generates in the same way. +regenerate-compiletests-multimodule-protos: build ${PROTOC_GEN_SWIFT} + find CompileTests/MultiModule -name "*.pb.swift" -exec rm -f {} \; + ${GENERATE_SRCS} \ + -I Protos/CompileTests/MultiModule \ + --tfiws_opt=Visibility=Public \ + --tfiws_opt=ProtoPathModuleMappings=Protos/CompileTests/MultiModule/module_mappings.pbascii \ + --tfiws_out=CompileTests/MultiModule \ + `(find Protos/CompileTests/MultiModule -type f -name "*.proto")` + # Helper to check if there is a protobuf checkout as expected. check-for-protobuf-checkout: @if [ ! -d "${GOOGLE_PROTOBUF_CHECKOUT}/src/google/protobuf" ]; then \ diff --git a/Protos/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.proto b/Protos/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.proto new file mode 100644 index 000000000..f8bdb3722 --- /dev/null +++ b/Protos/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.proto @@ -0,0 +1,6 @@ +import public "Sources/ModuleA/a.proto"; + +message ImportsAPublicly { + optional A a = 11; + optional E e = 12; +} diff --git a/Protos/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto b/Protos/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto new file mode 100644 index 000000000..0b34fc68d --- /dev/null +++ b/Protos/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto @@ -0,0 +1,6 @@ +import public "Sources/ImportsAPublicly/imports_a_publicly.proto"; + +message ImportsImportsAPublicly { + optional A a = 21; + optional E e = 22; +} diff --git a/Protos/CompileTests/MultiModule/Sources/ModuleA/a.proto b/Protos/CompileTests/MultiModule/Sources/ModuleA/a.proto new file mode 100644 index 000000000..7a2ef4496 --- /dev/null +++ b/Protos/CompileTests/MultiModule/Sources/ModuleA/a.proto @@ -0,0 +1,9 @@ +enum E { + E_UNSET = 0; + E_A = 1; + E_B = 2; +} + +message A { + optional E e = 1; +} diff --git a/Protos/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.proto b/Protos/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.proto new file mode 100644 index 000000000..f8c2c3a80 --- /dev/null +++ b/Protos/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.proto @@ -0,0 +1,6 @@ +import "Sources/ImportsAPublicly/imports_a_publicly.proto"; + +message UsesATransitively { + optional A a = 101; + optional E e = 102; +} diff --git a/Protos/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.proto b/Protos/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.proto new file mode 100644 index 000000000..e05621dfa --- /dev/null +++ b/Protos/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.proto @@ -0,0 +1,6 @@ +import "Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto"; + +message UsesATransitively2 { + optional A a = 111; + optional E e = 122; +} diff --git a/Protos/CompileTests/MultiModule/module_mappings.pbascii b/Protos/CompileTests/MultiModule/module_mappings.pbascii new file mode 100644 index 000000000..656198148 --- /dev/null +++ b/Protos/CompileTests/MultiModule/module_mappings.pbascii @@ -0,0 +1,12 @@ +mapping { + module_name: "ModuleA" + proto_file_path: "Sources/ModuleA/a.proto" +} +mapping { + module_name: "ImportsAPublicly" + proto_file_path: "Sources/ImportsAPublicly/imports_a_publicly.proto" +} +mapping { + module_name: "ImportsImportsAPublicly" + proto_file_path: "Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto" +} diff --git a/Reference/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift b/Reference/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift new file mode 100644 index 000000000..556b2ed19 --- /dev/null +++ b/Reference/CompileTests/MultiModule/Sources/ImportsAPublicly/imports_a_publicly.pb.swift @@ -0,0 +1,98 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ImportsAPublicly/imports_a_publicly.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct ImportsAPublicly: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension ImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "ImportsAPublicly" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 11: .same(proto: "a"), + 12: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 11: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 12: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 11) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 12) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: ImportsAPublicly, rhs: ImportsAPublicly) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Reference/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift b/Reference/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift new file mode 100644 index 000000000..8a345f5d0 --- /dev/null +++ b/Reference/CompileTests/MultiModule/Sources/ImportsImportsAPublicly/imports_imports_a_publicly.pb.swift @@ -0,0 +1,99 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct ImportsImportsAPublicly: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension ImportsImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "ImportsImportsAPublicly" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 21: .same(proto: "a"), + 22: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 21: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 22: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 21) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 22) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: ImportsImportsAPublicly, rhs: ImportsImportsAPublicly) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Reference/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift b/Reference/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift new file mode 100644 index 000000000..e456acc57 --- /dev/null +++ b/Reference/CompileTests/MultiModule/Sources/ModuleA/a.pb.swift @@ -0,0 +1,117 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Sources/ModuleA/a.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public enum E: SwiftProtobuf.Enum { + public typealias RawValue = Int + case unset // = 0 + case a // = 1 + case b // = 2 + + public init() { + self = .unset + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .unset + case 1: self = .a + case 2: self = .b + default: return nil + } + } + + public var rawValue: Int { + switch self { + case .unset: return 0 + case .a: return 1 + case .b: return 2 + } + } + +} + +public struct A: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var e: E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _e: E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension E: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 0: .same(proto: "E_UNSET"), + 1: .same(proto: "E_A"), + 2: .same(proto: "E_B"), + ] +} + +extension A: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "A" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: A, rhs: A) -> Bool { + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Reference/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift b/Reference/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift new file mode 100644 index 000000000..3bb4d6701 --- /dev/null +++ b/Reference/CompileTests/MultiModule/Tests/Test1/uses_a_transitively.pb.swift @@ -0,0 +1,99 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Tests/Test1/uses_a_transitively.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct UsesATransitively: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension UsesATransitively: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "UsesATransitively" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 101: .same(proto: "a"), + 102: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 101: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 102: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 101) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 102) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: UsesATransitively, rhs: UsesATransitively) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Reference/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift b/Reference/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift new file mode 100644 index 000000000..7dd0c210e --- /dev/null +++ b/Reference/CompileTests/MultiModule/Tests/Test2/uses_a_transitively2.pb.swift @@ -0,0 +1,100 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: Tests/Test2/uses_a_transitively2.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +import ImportsAPublicly +import ImportsImportsAPublicly +import ModuleA + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {} + typealias Version = _3 +} + +public struct UsesATransitively2: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var a: ModuleA.A { + get {return _a ?? ModuleA.A()} + set {_a = newValue} + } + /// Returns true if `a` has been explicitly set. + public var hasA: Bool {return self._a != nil} + /// Clears the value of `a`. Subsequent reads from it will return its default value. + public mutating func clearA() {self._a = nil} + + public var e: ModuleA.E { + get {return _e ?? .unset} + set {_e = newValue} + } + /// Returns true if `e` has been explicitly set. + public var hasE: Bool {return self._e != nil} + /// Clears the value of `e`. Subsequent reads from it will return its default value. + public mutating func clearE() {self._e = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _a: ModuleA.A? = nil + fileprivate var _e: ModuleA.E? = nil +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +extension UsesATransitively2: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = "UsesATransitively2" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 111: .same(proto: "a"), + 122: .same(proto: "e"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 111: try { try decoder.decodeSingularMessageField(value: &self._a) }() + case 122: try { try decoder.decodeSingularEnumField(value: &self._e) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._a { + try visitor.visitSingularMessageField(value: v, fieldNumber: 111) + } }() + try { if let v = self._e { + try visitor.visitSingularEnumField(value: v, fieldNumber: 122) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: UsesATransitively2, rhs: UsesATransitively2) -> Bool { + if lhs._a != rhs._a {return false} + if lhs._e != rhs._e {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +}