浏览代码

Generate conformances files containing a message are passed to the plugin (#837)

Motivation:

There was some code in the codegen which checked whether the codegen
request contained any services. If there were no services in the request
then no code would be generated. This was fine when we generated
conformance based on when request/response types of a service. Less see
now.

Modifications:

- Remove the conditional check
- Remove some related dead code
- Add a couple of tests which validate that we do the right thing when
  we generate a file with just a service and the same for just a
  message.

Result:

Less broken codegen
George Barnett 5 年之前
父节点
当前提交
0f0d4ccaf7

+ 3 - 0
Sources/protoc-gen-grpc-swift/Generator-Conformance.swift

@@ -18,6 +18,9 @@ import SwiftProtobufPluginLibrary
 
 extension Generator {
   internal func printProtobufExtensions() {
+    if self.file.messages.isEmpty {
+      return
+    }
     println("// Provides conformance to `GRPCPayload`")
     for message in self.file.messages {
       let name = self.protobufNamer.fullName(message: message)

+ 1 - 3
Sources/protoc-gen-grpc-swift/Generator.swift

@@ -23,13 +23,11 @@ class Generator {
   internal var service: ServiceDescriptor! // context during generation
   internal var method: MethodDescriptor!   // context during generation
 
-  internal var observedMessages: Set<String>
   internal let protobufNamer: SwiftProtobufNamer
 
-  init(_ file: FileDescriptor, options: GeneratorOptions, observedMessages: Set<String>) {
+  init(_ file: FileDescriptor, options: GeneratorOptions) {
     self.file = file
     self.options = options
-    self.observedMessages = observedMessages
     self.printer = CodePrinter()
     self.protobufNamer = SwiftProtobufNamer(
       currentFile: file,

+ 6 - 13
Sources/protoc-gen-grpc-swift/main.swift

@@ -102,23 +102,16 @@ func main() throws {
   // Build the SwiftProtobufPluginLibrary model of the plugin input
   let descriptorSet = DescriptorSet(protos: request.protoFile)
 
-  // We need to generate conformance to `GRPCPayload` for request/response types. Track which
-  // types we've seen to avoid generating the conformance multiple times.
-  var observedMessages = Set<String>()
-
   // process each .proto file in filename order in an attempt to stabilise the output (i.e. where
   // conformance to `GRPCPayload` is generated)
   for name in request.fileToGenerate.sorted() {
     let fileDescriptor = descriptorSet.lookupFileDescriptor(protoName: name)
-    if fileDescriptor.services.count > 0 {
-      let grpcFileName = uniqueOutputFileName(component: "grpc", fileDescriptor: fileDescriptor, fileNamingOption: options.fileNaming)
-      let grpcGenerator = Generator(fileDescriptor, options: options, observedMessages: observedMessages)
-      var grpcFile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
-      grpcFile.name = grpcFileName
-      grpcFile.content = grpcGenerator.code
-      response.file.append(grpcFile)
-      observedMessages.formUnion(grpcGenerator.observedMessages)
-    }
+    let grpcFileName = uniqueOutputFileName(component: "grpc", fileDescriptor: fileDescriptor, fileNamingOption: options.fileNaming)
+    let grpcGenerator = Generator(fileDescriptor, options: options)
+    var grpcFile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
+    grpcFile.name = grpcFileName
+    grpcFile.content = grpcGenerator.code
+    response.file.append(grpcFile)
   }
 
   // return everything to the caller

+ 36 - 0
dev/codegen-tests/04-messages-only/generate-and-diff.sh

@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Copyright 2020, gRPC Authors All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eu
+
+HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "${HERE}/../test-boilerplate.sh"
+
+function all_at_once {
+  echo "[${TEST}]"
+
+  prepare
+
+  protoc \
+    --proto_path="${PROTO_DIR}" \
+    --plugin="${PROTOC_GEN_GRPC_SWIFT}" \
+    --grpc-swift_out="${OUTPUT_DIR}" \
+    "${PROTO_DIR}"/*
+
+  validate
+}
+
+all_at_once

+ 32 - 0
dev/codegen-tests/04-messages-only/golden/test.grpc.swift

@@ -0,0 +1,32 @@
+//
+// DO NOT EDIT.
+//
+// Generated by the protocol buffer compiler.
+// Source: test.proto
+//
+
+//
+// Copyright 2018, gRPC Authors All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+import Foundation
+import GRPC
+import NIO
+import NIOHTTP1
+import SwiftProtobuf
+
+
+
+// Provides conformance to `GRPCPayload`
+extension Codegentest_Foo: GRPCProtobufPayload {}

+ 20 - 0
dev/codegen-tests/04-messages-only/proto/test.proto

@@ -0,0 +1,20 @@
+// Copyright 2020, gRPC Authors All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto3";
+
+package codegentest;
+
+message Foo {
+  string bar = 1;
+}

+ 36 - 0
dev/codegen-tests/05-service-only/generate-and-diff.sh

@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Copyright 2020, gRPC Authors All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eu
+
+HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "${HERE}/../test-boilerplate.sh"
+
+function all_at_once {
+  echo "[${TEST}]"
+
+  prepare
+
+  protoc \
+    --proto_path="${PROTO_DIR}" \
+    --plugin="${PROTOC_GEN_GRPC_SWIFT}" \
+    --grpc-swift_out="${OUTPUT_DIR}" \
+    "${PROTO_DIR}"/*
+
+  validate
+}
+
+all_at_once

+ 87 - 0
dev/codegen-tests/05-service-only/golden/test.grpc.swift

@@ -0,0 +1,87 @@
+//
+// DO NOT EDIT.
+//
+// Generated by the protocol buffer compiler.
+// Source: test.proto
+//
+
+//
+// Copyright 2018, gRPC Authors All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+import Foundation
+import GRPC
+import NIO
+import NIOHTTP1
+import SwiftProtobuf
+
+
+/// Usage: instantiate Codegentest_FooClient, then call methods of this protocol to make API calls.
+internal protocol Codegentest_FooClientProtocol {
+  func bar(_ request: SwiftProtobuf.Google_Protobuf_Empty, callOptions: CallOptions?) -> UnaryCall<SwiftProtobuf.Google_Protobuf_Empty, SwiftProtobuf.Google_Protobuf_Empty>
+}
+
+internal final class Codegentest_FooClient: GRPCClient, Codegentest_FooClientProtocol {
+  internal let channel: GRPCChannel
+  internal var defaultCallOptions: CallOptions
+
+  /// Creates a client for the codegentest.Foo service.
+  ///
+  /// - Parameters:
+  ///   - channel: `GRPCChannel` to the service host.
+  ///   - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
+  internal init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
+    self.channel = channel
+    self.defaultCallOptions = defaultCallOptions
+  }
+
+  /// Unary call to Bar
+  ///
+  /// - Parameters:
+  ///   - request: Request to send to Bar.
+  ///   - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
+  /// - Returns: A `UnaryCall` with futures for the metadata, status and response.
+  internal func bar(_ request: SwiftProtobuf.Google_Protobuf_Empty, callOptions: CallOptions? = nil) -> UnaryCall<SwiftProtobuf.Google_Protobuf_Empty, SwiftProtobuf.Google_Protobuf_Empty> {
+    return self.makeUnaryCall(path: "/codegentest.Foo/Bar",
+                              request: request,
+                              callOptions: callOptions ?? self.defaultCallOptions)
+  }
+
+}
+
+/// To build a server, implement a class that conforms to this protocol.
+internal protocol Codegentest_FooProvider: CallHandlerProvider {
+  func bar(request: SwiftProtobuf.Google_Protobuf_Empty, context: StatusOnlyCallContext) -> EventLoopFuture<SwiftProtobuf.Google_Protobuf_Empty>
+}
+
+extension Codegentest_FooProvider {
+  internal var serviceName: String { return "codegentest.Foo" }
+
+  /// Determines, calls and returns the appropriate request handler, depending on the request's method.
+  /// Returns nil for methods not handled by this service.
+  internal func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
+    switch methodName {
+    case "Bar":
+      return UnaryCallHandler(callHandlerContext: callHandlerContext) { context in
+        return { request in
+          self.bar(request: request, context: context)
+        }
+      }
+
+    default: return nil
+    }
+  }
+}
+
+

+ 22 - 0
dev/codegen-tests/05-service-only/proto/test.proto

@@ -0,0 +1,22 @@
+// Copyright 2020, gRPC Authors All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto3";
+
+package codegentest;
+
+import "google/protobuf/empty.proto";
+
+service Foo {
+  rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+}