Skip to content

Commit

Permalink
Add option to annotate imports with @_implementationOnly
Browse files Browse the repository at this point in the history
# Conflicts:
#	Sources/protoc-gen-swift/FileGenerator.swift
  • Loading branch information
gjcairo authored and thomasvl committed Jun 2, 2023
1 parent 076f7e4 commit e6112f7
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
24 changes: 24 additions & 0 deletions Documentation/PLUGIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,30 @@ mapping {
The `proto_file_path` values here should match the paths used in the proto file
`import` statements.


##### Generation Option: `ImplementationOnlyImports` - `@_implementationOnly`-annotated imports

By default, SwiftProtobuf does not annotate any imports with `@_implementationOnly`.
However, in some scenarios, such as when distributing an `XCFramework`, imports
for types used only internally should be annotated as `@_implementationOnly` to
avoid exposing internal symbols to clients.
You can change this with the `ImplementationOnlyImports` option:

```
$ protoc --swift_opt=ImplementationOnlyImports=[value] --swift_out=. foo/bar/*.proto mumble/*.proto
```

The possible values for `ImplementationOnlyImports` are:

* `false` (default): The `@_implementationOnly` annotation will never be used.
* `true`: Imports of internal dependencies and any modules defined in the module
mappings will be annotated as `@_implementationOnly`.

**Important:** Modules cannot be imported as implementation-only if they're
exposed via public API, so even if `ImplementationOnlyImports` is set to `true`,
this will only work if the `Visibility` is set to `internal`.


### Building your project

After copying the `.pb.swift` files into your project, you will need
Expand Down
15 changes: 13 additions & 2 deletions Sources/protoc-gen-swift/FileGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,26 @@ class FileGenerator {
}

p.print("import Foundation\n")

// Import all other imports as @_implementationOnly if the visiblity is
// internal and the option is set, to avoid exposing internal types to users.
let visibilityAnnotation: String = {
if self.generatorOptions.implementationOnlyImports,
self.generatorOptions.visibility == .internal {
return "@_implementationOnly "
} else {
return ""
}
}()
if !fileDescriptor.isBundledProto {
// The well known types ship with the runtime, everything else needs
// to import the runtime.
p.print("import \(namer.swiftProtobufModuleName)\n")
p.print("\(visibilityAnnotation)import \(namer.swiftProtobufModuleName)\n")
}
if let neededImports = generatorOptions.protoToModuleMappings.neededModules(forFile: fileDescriptor) {
p.print("\n")
for i in neededImports {
p.print("import \(i)\n")
p.print("\(visibilityAnnotation)import \(i)\n")
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/protoc-gen-swift/GenerationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
// -----------------------------------------------------------------------------

enum GenerationError: Error {
/// Raised when parsing the parameter string and found an unknown key
/// Raised when parsing the parameter string and found an unknown key.
case unknownParameter(name: String)
/// Raised when a parameter was giving an invalid value
/// Raised when a parameter was given an invalid value.
case invalidParameterValue(name: String, value: String)
/// Raised to wrap another error but provide a context message.
case wrappedError(message: String, error: Error)
Expand Down
7 changes: 7 additions & 0 deletions Sources/protoc-gen-swift/GeneratorOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class GeneratorOptions {
let outputNaming: OutputNaming
let protoToModuleMappings: ProtoFileToModuleMappings
let visibility: Visibility
let implementationOnlyImports: Bool

/// A string snippet to insert for the visibility
let visibilitySourceSnippet: String
Expand All @@ -58,6 +59,7 @@ class GeneratorOptions {
var moduleMapPath: String?
var visibility: Visibility = .internal
var swiftProtobufModuleName: String? = nil
var implementationOnlyImports: Bool = false

for pair in parseParameter(string:parameter) {
switch pair.key {
Expand Down Expand Up @@ -88,6 +90,10 @@ class GeneratorOptions {
throw GenerationError.invalidParameterValue(name: pair.key,
value: pair.value)
}
case "ImplementationOnlyImports":
if let value = Bool(pair.value) {
implementationOnlyImports = value
}
default:
throw GenerationError.unknownParameter(name: pair.key)
}
Expand Down Expand Up @@ -115,5 +121,6 @@ class GeneratorOptions {
visibilitySourceSnippet = "public "
}

self.implementationOnlyImports = implementationOnlyImports
}
}

0 comments on commit e6112f7

Please sign in to comment.