Merge pull request #14490 from nallohki/master

Updates Objective-C Generation to allow for omission of the generated @interface and @implementation
pull/14551/head
Muxi Yan 7 years ago committed by GitHub
commit cab345efe6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 104
      src/compiler/objective_c_generator.cc
  2. 10
      src/compiler/objective_c_generator.h
  3. 40
      src/compiler/objective_c_generator_helpers.h
  4. 145
      src/compiler/objective_c_plugin.cc

@ -212,37 +212,49 @@ void PrintMethodImplementations(Printer* printer,
return output; return output;
} }
::grpc::string GetHeader(const ServiceDescriptor* service) { ::grpc::string GetProtocol(const ServiceDescriptor* service) {
::grpc::string output; ::grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n"); // Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
for (int i = 0; i < service->method_count(); i++) { map< ::grpc::string, ::grpc::string> vars = {
PrintMethodDeclarations(&printer, service->method(i)); {"service_class", ServiceClassName(service)}};
}
printer.Print("@end\n\n");
printer.Print( printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
"/**\n" for (int i = 0; i < service->method_count(); i++) {
" * Basic service implementation, over gRPC, that only does\n" PrintMethodDeclarations(&printer, service->method(i));
" * marshalling and parsing.\n"
" */\n");
printer.Print(vars,
"@interface $service_class$ :"
" GRPCProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");
} }
printer.Print("@end\n\n");
return output;
}
::grpc::string GetInterface(const ServiceDescriptor* service) {
::grpc::string output;
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(vars,
"/**\n"
" * Basic service implementation, over gRPC, that only does\n"
" * marshalling and parsing.\n"
" */\n");
printer.Print(vars,
"@interface $service_class$ :"
" GRPCProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");
return output; return output;
} }
@ -258,26 +270,32 @@ void PrintMethodImplementations(Printer* printer,
{"service_class", ServiceClassName(service)}, {"service_class", ServiceClassName(service)},
{"package", service->file()->package()}}; {"package", service->file()->package()}};
printer.Print(vars, "@implementation $service_class$\n\n"); printer.Print(vars,
"@implementation $service_class$\n\n"
"// Designated initializer\n"
"- (instancetype)initWithHost:(NSString *)host {\n"
" self = [super initWithHost:host\n"
" packageName:@\"$package$\"\n"
" serviceName:@\"$service_name$\"];\n"
" return self;\n"
"}\n\n");
printer.Print("// Designated initializer\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
printer.Print(
vars,
" return (self = [super initWithHost:host"
" packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
printer.Print("}\n\n");
printer.Print( printer.Print(
"// Override superclass initializer to disallow different" "// Override superclass initializer to disallow different"
" package and service names.\n"); " package and service names.\n"
printer.Print("- (instancetype)initWithHost:(NSString *)host\n"); "- (instancetype)initWithHost:(NSString *)host\n"
printer.Print(" packageName:(NSString *)packageName\n"); " packageName:(NSString *)packageName\n"
printer.Print(" serviceName:(NSString *)serviceName {\n"); " serviceName:(NSString *)serviceName {\n"
printer.Print(" return [self initWithHost:host];\n"); " return [self initWithHost:host];\n"
printer.Print("}\n\n"); "}\n\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host {\n");
printer.Print(" return [[self alloc] initWithHost:host];\n"); printer.Print(
printer.Print("}\n\n\n"); "#pragma mark - Class Methods\n\n"
"+ (instancetype)serviceWithHost:(NSString *)host {\n"
" return [[self alloc] initWithHost:host];\n"
"}\n\n");
printer.Print("#pragma mark - Method Implementations\n\n");
for (int i = 0; i < service->method_count(); i++) { for (int i = 0; i < service->method_count(); i++) {
PrintMethodImplementations(&printer, service->method(i)); PrintMethodImplementations(&printer, service->method(i));

@ -31,9 +31,13 @@ using ::grpc::string;
// Returns forward declaration of classes in the generated header file. // Returns forward declaration of classes in the generated header file.
string GetAllMessageClasses(const FileDescriptor* file); string GetAllMessageClasses(const FileDescriptor* file);
// Returns the content to be included in the "global_scope" insertion point of // Returns the content to be included defining the @protocol segment at the
// the generated header file. // insertion point of the generated implementation file.
string GetHeader(const ServiceDescriptor* service); string GetProtocol(const ServiceDescriptor* service);
// Returns the content to be included defining the @interface segment at the
// insertion point of the generated implementation file.
string GetInterface(const ServiceDescriptor* service);
// Returns the content to be included in the "global_scope" insertion point of // Returns the content to be included in the "global_scope" insertion point of
// the generated implementation file. // the generated implementation file.

@ -40,5 +40,45 @@ inline string ServiceClassName(const ServiceDescriptor* service) {
string prefix = file->options().objc_class_prefix(); string prefix = file->options().objc_class_prefix();
return prefix + service->name(); return prefix + service->name();
} }
inline ::grpc::string LocalImport(const ::grpc::string& import) {
return ::grpc::string("#import \"" + import + "\"\n");
}
inline ::grpc::string SystemImport(const ::grpc::string& import) {
return ::grpc::string("#import <" + import + ">\n");
}
inline ::grpc::string PreprocConditional(::grpc::string symbol, bool invert) {
return invert ? "!defined(" + symbol + ") || !" + symbol
: "defined(" + symbol + ") && " + symbol;
}
inline ::grpc::string PreprocIf(const ::grpc::string& symbol,
const ::grpc::string& if_true) {
return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
if_true + "#endif\n");
}
inline ::grpc::string PreprocIfNot(const ::grpc::string& symbol,
const ::grpc::string& if_true) {
return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
if_true + "#endif\n");
}
inline ::grpc::string PreprocIfElse(const ::grpc::string& symbol,
const ::grpc::string& if_true,
const ::grpc::string& if_false) {
return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
if_true + "#else\n" + if_false + "#endif\n");
}
inline ::grpc::string PreprocIfNotElse(const ::grpc::string& symbol,
const ::grpc::string& if_true,
const ::grpc::string& if_false) {
return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
if_true + "#else\n" + if_false + "#endif\n");
}
} // namespace grpc_objective_c_generator } // namespace grpc_objective_c_generator
#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H #endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H

@ -29,12 +29,42 @@
using ::google::protobuf::compiler::objectivec:: using ::google::protobuf::compiler::objectivec::
IsProtobufLibraryBundledProtoFile; IsProtobufLibraryBundledProtoFile;
using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName; using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
using ::grpc_objective_c_generator::LocalImport;
using ::grpc_objective_c_generator::PreprocIfElse;
using ::grpc_objective_c_generator::PreprocIfNot;
using ::grpc_objective_c_generator::SystemImport;
namespace {
inline ::grpc::string ImportProtoHeaders(
const grpc::protobuf::FileDescriptor* dep, const char* indent) {
::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
if (!IsProtobufLibraryBundledProtoFile(dep)) {
return indent + LocalImport(header);
}
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
::grpc::string framework_header =
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
static const ::grpc::string kFrameworkImportsCondition =
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
return PreprocIfElse(kFrameworkImportsCondition,
indent + SystemImport(framework_header),
indent + LocalImport(header));
}
} // namespace
class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public: public:
ObjectiveCGrpcGenerator() {} ObjectiveCGrpcGenerator() {}
virtual ~ObjectiveCGrpcGenerator() {} virtual ~ObjectiveCGrpcGenerator() {}
public:
virtual bool Generate(const grpc::protobuf::FileDescriptor* file, virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
const ::grpc::string& parameter, const ::grpc::string& parameter,
grpc::protobuf::compiler::GeneratorContext* context, grpc::protobuf::compiler::GeneratorContext* context,
@ -44,97 +74,68 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
return true; return true;
} }
static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
static const ::grpc::string kForwardDeclare =
"GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
::grpc::string file_name = ::grpc::string file_name =
google::protobuf::compiler::objectivec::FilePath(file); google::protobuf::compiler::objectivec::FilePath(file);
::grpc::string prefix = file->options().objc_class_prefix();
{ {
// Generate .pbrpc.h // Generate .pbrpc.h
::grpc::string imports = ::grpc::string imports = LocalImport(file_name + ".pbobjc.h");
::grpc::string("#if !GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n") +
"#import \"" + file_name + ::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
".pbobjc.h\"\n" SystemImport("ProtoRPC/ProtoRPC.h") +
"#endif\n\n" SystemImport("RxLibrary/GRXWriteable.h") +
"#import <ProtoRPC/ProtoService.h>\n" SystemImport("RxLibrary/GRXWriter.h");
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n" ::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n";
"#import <RxLibrary/GRXWriter.h>\n";
::grpc::string class_declarations =
::grpc::string proto_imports; grpc_objective_c_generator::GetAllMessageClasses(file);
proto_imports += "#if GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n" +
grpc_objective_c_generator::GetAllMessageClasses(file) + ::grpc::string class_imports;
"#else\n";
for (int i = 0; i < file->dependency_count(); i++) { for (int i = 0; i < file->dependency_count(); i++) {
::grpc::string header = class_imports += ImportProtoHeaders(file->dependency(i), " ");
grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
if (IsProtobufLibraryBundledProtoFile(dependency)) {
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
proto_imports +=
" #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
" #import <" +
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
">\n"
" #else\n"
" #import \"" +
header +
"\"\n"
" #endif\n";
} else {
proto_imports += ::grpc::string(" #import \"") + header + "\"\n";
}
} }
proto_imports += "#endif\n";
::grpc::string declarations; ::grpc::string protocols;
for (int i = 0; i < file->service_count(); i++) { for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i); const grpc::protobuf::ServiceDescriptor* service = file->service(i);
declarations += grpc_objective_c_generator::GetHeader(service); protocols += grpc_objective_c_generator::GetProtocol(service);
} }
static const ::grpc::string kNonNullBegin = ::grpc::string interfaces;
"\nNS_ASSUME_NONNULL_BEGIN\n\n"; for (int i = 0; i < file->service_count(); i++) {
static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n"; const grpc::protobuf::ServiceDescriptor* service = file->service(i);
interfaces += grpc_objective_c_generator::GetInterface(service);
}
Write(context, file_name + ".pbrpc.h", Write(context, file_name + ".pbrpc.h",
imports + '\n' + proto_imports + '\n' + kNonNullBegin + PreprocIfNot(kForwardDeclare, imports) + "\n" +
declarations + kNonNullEnd); PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
PreprocIfElse(kForwardDeclare, class_declarations,
class_imports) +
"\n" + forward_declarations + "\n" + kNonNullBegin + "\n" +
protocols + "\n" + PreprocIfNot(kProtocolOnly, interfaces) +
"\n" + kNonNullEnd + "\n");
} }
{ {
// Generate .pbrpc.m // Generate .pbrpc.m
::grpc::string imports = ::grpc::string("#import \"") + file_name + ::grpc::string imports = LocalImport(file_name + ".pbrpc.h") +
".pbrpc.h\"\n" LocalImport(file_name + ".pbobjc.h") +
"#import \"" + SystemImport("ProtoRPC/ProtoRPC.h") +
file_name + SystemImport("RxLibrary/GRXWriter+Immediate.h");
".pbobjc.h\"\n\n"
"#import <ProtoRPC/ProtoRPC.h>\n" ::grpc::string class_imports;
"#import <RxLibrary/GRXWriter+Immediate.h>\n";
for (int i = 0; i < file->dependency_count(); i++) { for (int i = 0; i < file->dependency_count(); i++) {
::grpc::string header = class_imports += ImportProtoHeaders(file->dependency(i), "");
grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
if (IsProtobufLibraryBundledProtoFile(dependency)) {
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
imports +=
"#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
" #import <" +
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
">\n"
"#else\n"
" #import \"" +
header +
"\"\n"
"#endif\n";
} else {
imports += ::grpc::string("#import \"") + header + "\"\n";
}
} }
::grpc::string definitions; ::grpc::string definitions;
@ -143,7 +144,9 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
definitions += grpc_objective_c_generator::GetSource(service); definitions += grpc_objective_c_generator::GetSource(service);
} }
Write(context, file_name + ".pbrpc.m", imports + '\n' + definitions); Write(context, file_name + ".pbrpc.m",
PreprocIfNot(kProtocolOnly,
imports + "\n" + class_imports + "\n" + definitions));
} }
return true; return true;

Loading…
Cancel
Save