aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/config.h14
-rw-r--r--src/compiler/cpp_generator.cc14
-rw-r--r--src/compiler/cpp_generator.h14
-rw-r--r--src/compiler/cpp_plugin.cc28
-rw-r--r--src/compiler/csharp_generator.cc129
-rw-r--r--src/compiler/csharp_generator.h4
-rw-r--r--src/compiler/csharp_plugin.cc24
-rw-r--r--src/compiler/generator_helpers.h109
-rw-r--r--src/compiler/objective_c_generator.cc6
-rw-r--r--src/compiler/objective_c_plugin.cc6
-rw-r--r--src/compiler/python_generator.cc10
11 files changed, 326 insertions, 32 deletions
diff --git a/src/compiler/config.h b/src/compiler/config.h
index fea976c318..d8b95818db 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -42,8 +42,10 @@
#include <google/protobuf/descriptor.pb.h>
#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
+#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
+#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
#endif
#ifndef GRPC_CUSTOM_CODEGENERATOR
@@ -68,12 +70,19 @@
#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain
#endif
+#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER
+#include <google/protobuf/compiler/code_generator.h>
+#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
+#endif
+
namespace grpc {
namespace protobuf {
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
+typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
+typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
namespace compiler {
typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator;
typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext;
@@ -81,6 +90,11 @@ static inline int PluginMain(int argc, char* argv[],
const CodeGenerator* generator) {
return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
}
+static inline void ParseGeneratorParameter(const string& parameter,
+ std::vector<std::pair<string, string> >* options) {
+ GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options);
+}
+
} // namespace compiler
namespace io {
typedef GRPC_CUSTOM_PRINTER Printer;
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 9319c41934..e2f127094a 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -102,6 +102,11 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n");
+ grpc::string leading_comments = file->GetLeadingComments();
+ if (!leading_comments.empty()) {
+ printer->Print(vars, "// Original file comments:\n");
+ printer->Print(leading_comments.c_str());
+ }
printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
printer->Print(vars, "\n");
@@ -456,6 +461,7 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
+ printer->Print(method->GetLeadingComments().c_str());
if (method->NoStreaming()) {
printer->Print(*vars,
"virtual ::grpc::Status $Method$("
@@ -480,6 +486,7 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
"::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
"\n");
}
+ printer->Print(method->GetTrailingComments().c_str());
}
void PrintHeaderServerMethodAsync(
@@ -674,6 +681,7 @@ void PrintHeaderService(Printer *printer,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
+ printer->Print(service->GetLeadingComments().c_str());
printer->Print(*vars,
"class $Service$ GRPC_FINAL {\n"
" public:\n");
@@ -686,7 +694,9 @@ void PrintHeaderService(Printer *printer,
printer->Indent();
printer->Print("virtual ~StubInterface() {}\n");
for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(service->method(i)->GetLeadingComments().c_str());
PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
+ printer->Print(service->method(i)->GetTrailingComments().c_str());
}
printer->Outdent();
printer->Print("private:\n");
@@ -762,6 +772,7 @@ void PrintHeaderService(Printer *printer,
printer->Outdent();
printer->Print("};\n");
+ printer->Print(service->GetTrailingComments().c_str());
}
grpc::string GetHeaderServices(File *file,
@@ -817,6 +828,8 @@ grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
printer->Print(vars, "\n");
printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
+
+ printer->Print(file->GetTrailingComments().c_str());
}
return output;
}
@@ -837,6 +850,7 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n\n");
+
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
printer->Print(vars, file->additional_headers().c_str());
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 953ddfd569..2a003b1069 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -64,8 +64,16 @@ struct Parameters {
grpc::string grpc_search_path;
};
+// A common interface for objects having comments in the source.
+// Return formatted comments to be inserted in generated code.
+struct CommentHolder {
+ virtual ~CommentHolder() {}
+ virtual grpc::string GetLeadingComments() const = 0;
+ virtual grpc::string GetTrailingComments() const = 0;
+};
+
// An abstract interface representing a method.
-struct Method {
+struct Method : public CommentHolder {
virtual ~Method() {}
virtual grpc::string name() const = 0;
@@ -80,7 +88,7 @@ struct Method {
};
// An abstract interface representing a service.
-struct Service {
+struct Service : public CommentHolder {
virtual ~Service() {}
virtual grpc::string name() const = 0;
@@ -101,7 +109,7 @@ struct Printer {
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
-struct File {
+struct File : public CommentHolder {
virtual ~File() {}
virtual grpc::string filename() const = 0;
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index e321c64639..0ec183e474 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -35,11 +35,15 @@
//
#include <memory>
+#include <sstream>
#include "src/compiler/config.h"
#include "src/compiler/cpp_generator.h"
#include "src/compiler/cpp_generator_helpers.h"
+#include "src/compiler/generator_helpers.h"
+
+using grpc_generator::GetCppComments;
class ProtoBufMethod : public grpc_cpp_generator::Method {
public:
@@ -71,6 +75,14 @@ class ProtoBufMethod : public grpc_cpp_generator::Method {
return method_->client_streaming() && method_->server_streaming();
}
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(method_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(method_, false);
+ }
+
private:
const grpc::protobuf::MethodDescriptor *method_;
};
@@ -88,6 +100,14 @@ class ProtoBufService : public grpc_cpp_generator::Service {
new ProtoBufMethod(service_->method(i)));
};
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(service_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(service_, false);
+ }
+
private:
const grpc::protobuf::ServiceDescriptor *service_;
};
@@ -141,6 +161,14 @@ class ProtoBufFile : public grpc_cpp_generator::File {
new ProtoBufPrinter(str));
}
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(file_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(file_, false);
+ }
+
private:
const grpc::protobuf::FileDescriptor *file_;
};
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 4def6c5e31..ac0fee1ec4 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -52,6 +52,7 @@ using grpc::protobuf::MethodDescriptor;
using grpc::protobuf::io::Printer;
using grpc::protobuf::io::StringOutputStream;
using grpc_generator::MethodType;
+using grpc_generator::GetCppComments;
using grpc_generator::GetMethodType;
using grpc_generator::METHODTYPE_NO_STREAMING;
using grpc_generator::METHODTYPE_CLIENT_STREAMING;
@@ -65,6 +66,56 @@ using std::vector;
namespace grpc_csharp_generator {
namespace {
+// This function is a massaged version of
+// https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+// Currently, we cannot easily reuse the functionality as
+// google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
+// TODO(jtattermusch): reuse the functionality from google/protobuf.
+void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer, grpc::protobuf::SourceLocation location) {
+ grpc::string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (comments.empty()) {
+ return;
+ }
+ // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+ // node of a summary element, not part of an attribute.
+ comments = grpc_generator::StringReplace(comments, "&", "&amp;", true);
+ comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
+
+ std::vector<grpc::string> lines;
+ grpc_generator::Split(comments, '\n', &lines);
+ // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+ // but that needs to be part of a bigger effort to understand the markdown better anyway.
+ printer->Print("/// <summary>\n");
+ bool last_was_empty = false;
+ // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+ // to preserve the blank lines themselves, as this is relevant in the markdown.
+ // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+ // (We don't skip "just whitespace" lines, either.)
+ for (std::vector<grpc::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+ grpc::string line = *it;
+ if (line.empty()) {
+ last_was_empty = true;
+ } else {
+ if (last_was_empty) {
+ printer->Print("///\n");
+ }
+ last_was_empty = false;
+ printer->Print("/// $line$\n", "line", *it);
+ }
+ }
+ printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+void GenerateDocCommentBody(
+ grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
+ grpc::protobuf::SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ GenerateDocCommentBodyImpl(printer, location);
+ }
+}
+
std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
@@ -123,6 +174,10 @@ std::string GetMethodRequestParamMaybe(const MethodDescriptor *method,
return GetClassName(method->input_type()) + " request, ";
}
+std::string GetAccessLevel(bool internal_access) {
+ return internal_access ? "internal" : "public";
+}
+
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
@@ -238,7 +293,7 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
std::ostringstream index;
index << service->index();
- out->Print("// service descriptor\n");
+ out->Print("/// <summary>Service descriptor</summary>\n");
out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
out->Print("{\n");
out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
@@ -249,7 +304,8 @@ void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *se
}
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client interface\n");
+ out->Print("/// <summary>Client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Client side interfaced will be removed "
"in the next release. Use client class directly.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -262,6 +318,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method->name(), "request",
@@ -269,6 +326,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetClassName(method->output_type()));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, CallOptions options);\n",
"methodname", method->name(), "request",
@@ -280,6 +338,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method_name, "request_maybe",
@@ -287,6 +346,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetMethodReturnTypeClient(method));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$CallOptions options);\n",
"methodname", method_name, "request_maybe",
@@ -299,7 +359,8 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side interface\n");
+ out->Print("/// <summary>Interface of server-side implementations of $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Service implementations should inherit"
" from the generated abstract base class instead.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -308,6 +369,7 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
@@ -322,13 +384,15 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side abstract class\n");
+ out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public abstract class $name$\n", "name",
GetServerClassName(service));
out->Print("{\n");
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context)\n",
@@ -349,7 +413,8 @@ void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
}
void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client stub\n");
+ out->Print("/// <summary>Client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("#pragma warning disable 0618\n");
out->Print(
"public class $name$ : ClientBase<$name$>, $interface$\n",
@@ -388,6 +453,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -400,6 +466,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -416,6 +483,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe",
@@ -431,6 +499,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
"methodname", method_name, "request_maybe",
@@ -481,7 +550,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
bool use_server_class) {
out->Print(
- "// creates service definition that can be registered with a server\n");
+ "/// <summary>Creates service definition that can be registered with a server</summary>\n");
out->Print("#pragma warning disable 0618\n");
out->Print(
"public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
@@ -515,7 +584,8 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
}
void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
- out->Print("// creates a new client\n");
+ out->Print("/// <summary>Creates a new client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public static $classname$ NewClient(Channel channel)\n",
"classname", GetClientClassName(service));
out->Print("{\n");
@@ -527,8 +597,12 @@ void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
out->Print("\n");
}
-void GenerateService(Printer* out, const ServiceDescriptor *service) {
- out->Print("public static class $classname$\n", "classname",
+void GenerateService(Printer* out, const ServiceDescriptor *service,
+ bool generate_client, bool generate_server,
+ bool internal_access) {
+ GenerateDocCommentBody(out, service);
+ out->Print("$access_level$ static class $classname$\n", "access_level",
+ GetAccessLevel(internal_access), "classname",
GetServiceClassName(service));
out->Print("{\n");
out->Indent();
@@ -542,13 +616,22 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
GenerateStaticMethodField(out, service->method(i));
}
GenerateServiceDescriptorProperty(out, service);
- GenerateClientInterface(out, service);
- GenerateServerInterface(out, service);
- GenerateServerClass(out, service);
- GenerateClientStub(out, service);
- GenerateBindServiceMethod(out, service, false);
- GenerateBindServiceMethod(out, service, true);
- GenerateNewStubMethods(out, service);
+
+ if (generate_client) {
+ GenerateClientInterface(out, service);
+ }
+ if (generate_server) {
+ GenerateServerInterface(out, service);
+ GenerateServerClass(out, service);
+ }
+ if (generate_client) {
+ GenerateClientStub(out, service);
+ GenerateNewStubMethods(out, service);
+ }
+ if (generate_server) {
+ GenerateBindServiceMethod(out, service, false);
+ GenerateBindServiceMethod(out, service, true);
+ }
out->Outdent();
out->Print("}\n");
@@ -556,7 +639,8 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
} // anonymous namespace
-grpc::string GetServices(const FileDescriptor *file) {
+grpc::string GetServices(const FileDescriptor *file, bool generate_client,
+ bool generate_server, bool internal_access) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@@ -573,6 +657,14 @@ grpc::string GetServices(const FileDescriptor *file) {
// Write out a file header.
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("// source: $filename$\n", "filename", file->name());
+
+ // use C++ style as there are no file-level XML comments in .NET
+ grpc::string leading_comments = GetCppComments(file, true);
+ if (!leading_comments.empty()) {
+ out.Print("// Original file comments:\n");
+ out.Print(leading_comments.c_str());
+ }
+
out.Print("#region Designer generated code\n");
out.Print("\n");
out.Print("using System;\n");
@@ -584,7 +676,8 @@ grpc::string GetServices(const FileDescriptor *file) {
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
out.Indent();
for (int i = 0; i < file->service_count(); i++) {
- GenerateService(&out, file->service(i));
+ GenerateService(&out, file->service(i), generate_client, generate_server,
+ internal_access);
}
out.Outdent();
out.Print("}\n");
diff --git a/src/compiler/csharp_generator.h b/src/compiler/csharp_generator.h
index 90eb7e2984..f0585af4fd 100644
--- a/src/compiler/csharp_generator.h
+++ b/src/compiler/csharp_generator.h
@@ -40,7 +40,9 @@
namespace grpc_csharp_generator {
-grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file,
+ bool generate_client, bool generate_server,
+ bool internal_access);
} // namespace grpc_csharp_generator
diff --git a/src/compiler/csharp_plugin.cc b/src/compiler/csharp_plugin.cc
index 8b9395f9e2..5350e73f10 100644
--- a/src/compiler/csharp_plugin.cc
+++ b/src/compiler/csharp_plugin.cc
@@ -48,7 +48,29 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
const grpc::string &parameter,
grpc::protobuf::compiler::GeneratorContext *context,
grpc::string *error) const {
- grpc::string code = grpc_csharp_generator::GetServices(file);
+ std::vector<std::pair<grpc::string, grpc::string> > options;
+ grpc::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
+
+ bool generate_client = true;
+ bool generate_server = true;
+ bool internal_access = false;
+ for (size_t i = 0; i < options.size(); i++) {
+ if (options[i].first == "no_client") {
+ generate_client = false;
+ } else if (options[i].first == "no_server") {
+ generate_server = false;
+ } else if (options[i].first == "internal_access") {
+ internal_access = true;
+ } else {
+ *error = "Unknown generator option: " + options[i].first;
+ return false;
+ }
+ }
+
+ grpc::string code = grpc_csharp_generator::GetServices(file,
+ generate_client,
+ generate_server,
+ internal_access);
if (code.size() == 0) {
return true; // don't generate a file if there are no services
}
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 3ed0500efc..bd077cf798 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -34,7 +34,11 @@
#ifndef GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
#define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
+#include <iostream>
#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
#include "src/compiler/config.h"
@@ -175,6 +179,111 @@ inline MethodType GetMethodType(const grpc::protobuf::MethodDescriptor *method)
}
}
+inline void Split(const grpc::string &s, char delim,
+ std::vector<grpc::string> *append_to) {
+ std::istringstream iss(s);
+ grpc::string piece;
+ while (std::getline(iss, piece)) {
+ append_to->push_back(piece);
+ }
+}
+
+enum CommentType {
+ COMMENTTYPE_LEADING,
+ COMMENTTYPE_TRAILING,
+ COMMENTTYPE_LEADING_DETACHED
+};
+
+// Get all the raw comments and append each line without newline to out.
+template <typename DescriptorType>
+inline void GetComment(const DescriptorType *desc, CommentType type,
+ std::vector<grpc::string> *out) {
+ grpc::protobuf::SourceLocation location;
+ if (!desc->GetSourceLocation(&location)) {
+ return;
+ }
+ if (type == COMMENTTYPE_LEADING || type == COMMENTTYPE_TRAILING) {
+ const grpc::string &comments = type == COMMENTTYPE_LEADING
+ ? location.leading_comments
+ : location.trailing_comments;
+ Split(comments, '\n', out);
+ } else if (type == COMMENTTYPE_LEADING_DETACHED) {
+ for (unsigned int i = 0; i < location.leading_detached_comments.size();
+ i++) {
+ Split(location.leading_detached_comments[i], '\n', out);
+ out->push_back("");
+ }
+ } else {
+ std::cerr << "Unknown comment type " << type << std::endl;
+ abort();
+ }
+}
+
+// Each raw comment line without newline is appended to out.
+// For file level leading and detached leading comments, we return comments
+// above syntax line. Return nothing for trailing comments.
+template <>
+inline void GetComment(const grpc::protobuf::FileDescriptor *desc,
+ CommentType type, std::vector<grpc::string> *out) {
+ if (type == COMMENTTYPE_TRAILING) {
+ return;
+ }
+ grpc::protobuf::SourceLocation location;
+ std::vector<int> path;
+ path.push_back(grpc::protobuf::FileDescriptorProto::kSyntaxFieldNumber);
+ if (!desc->GetSourceLocation(path, &location)) {
+ return;
+ }
+ if (type == COMMENTTYPE_LEADING) {
+ Split(location.leading_comments, '\n', out);
+ } else if (type == COMMENTTYPE_LEADING_DETACHED) {
+ for (unsigned int i = 0; i < location.leading_detached_comments.size();
+ i++) {
+ Split(location.leading_detached_comments[i], '\n', out);
+ out->push_back("");
+ }
+ } else {
+ std::cerr << "Unknown comment type " << type << std::endl;
+ abort();
+ }
+}
+
+// Add prefix and newline to each comment line and concatenate them together.
+// Make sure there is a space after the prefix unless the line is empty.
+inline grpc::string GenerateCommentsWithPrefix(
+ const std::vector<grpc::string> &in, const grpc::string &prefix) {
+ std::ostringstream oss;
+ for (const grpc::string &elem : in) {
+ if (elem.empty()) {
+ oss << prefix << "\n";
+ } else if (elem[0] == ' ') {
+ oss << prefix << elem << "\n";
+ } else {
+ oss << prefix << " " << elem << "\n";
+ }
+ }
+ return oss.str();
+}
+
+// Get leading or trailing comments in a string. Comment lines start with "// ".
+// Leading detached comments are put in in front of leading comments.
+template <typename DescriptorType>
+inline grpc::string GetCppComments(const DescriptorType *desc, bool leading) {
+ std::vector<grpc::string> out;
+ if (leading) {
+ grpc_generator::GetComment(
+ desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &out);
+ std::vector<grpc::string> leading;
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
+ &leading);
+ out.insert(out.end(), leading.begin(), leading.end());
+ } else {
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
+ &out);
+ }
+ return GenerateCommentsWithPrefix(out, "//");
+}
+
} // namespace grpc_generator
#endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index ff092053ad..465491e385 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -75,11 +75,11 @@ void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
if (method->server_streaming()) {
printer->Print(vars,
" eventHandler:(void(^)(BOOL done, "
- "$response_class$ *response, NSError *error))eventHandler");
+ "$response_class$ *_Nullable response, NSError *_Nullable error))eventHandler");
} else {
printer->Print(vars,
- " handler:(void(^)($response_class$ *response, "
- "NSError *error))handler");
+ " handler:(void(^)($response_class$ *_Nullable response, "
+ "NSError *_Nullable error))handler");
}
}
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 17440358bb..3ccfd5b037 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -81,8 +81,12 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
declarations += grpc_objective_c_generator::GetHeader(service);
}
+ static const ::grpc::string kNonNullBegin = "\nNS_ASSUME_NONNULL_BEGIN\n\n";
+ static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
+
Write(context, file_name + ".pbrpc.h",
- imports + '\n' + proto_imports + '\n' + declarations);
+ imports + '\n' + proto_imports + '\n' + kNonNullBegin +
+ declarations + kNonNullEnd);
}
{
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 02c032800b..59137e1c92 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -190,7 +190,7 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
- out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n");
+ out->Print(dict, "class Beta$Service$Servicer(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -198,12 +198,11 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
auto meth = service->method(i);
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
- out->Print("@abc.abstractmethod\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
"Method", meth->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
- out->Print("raise NotImplementedError()\n");
+ out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
}
}
}
@@ -218,7 +217,7 @@ bool PrintBetaStub(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
- out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n");
+ out->Print(dict, "class Beta$Service$Stub(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -227,7 +226,6 @@ bool PrintBetaStub(const ServiceDescriptor* service,
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
- out->Print("@abc.abstractmethod\n");
out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
{
IndentScope raii_method_indent(out);
@@ -450,6 +448,8 @@ bool PrintPreamble(const FileDescriptor* file,
out->Print("import six\n");
out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root);
+ out->Print("from $Package$ import interfaces as beta_interfaces\n",
+ "Package", config.beta_package_root);
out->Print("from grpc.framework.common import cardinality\n");
out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
return true;