Imported Upstream version 1.18.0
[platform/upstream/grpc.git] / src / compiler / objective_c_plugin.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 // Generates Objective C gRPC service interface out of Protobuf IDL.
20
21 #include <memory>
22
23 #include "src/compiler/config.h"
24 #include "src/compiler/objective_c_generator.h"
25 #include "src/compiler/objective_c_generator_helpers.h"
26
27 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
28
29 using ::google::protobuf::compiler::objectivec::
30     IsProtobufLibraryBundledProtoFile;
31 using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
32 using ::grpc_objective_c_generator::LocalImport;
33 using ::grpc_objective_c_generator::PreprocIfElse;
34 using ::grpc_objective_c_generator::PreprocIfNot;
35 using ::grpc_objective_c_generator::SystemImport;
36
37 namespace {
38
39 inline ::grpc::string ImportProtoHeaders(
40     const grpc::protobuf::FileDescriptor* dep, const char* indent) {
41   ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
42
43   if (!IsProtobufLibraryBundledProtoFile(dep)) {
44     return indent + LocalImport(header);
45   }
46
47   ::grpc::string base_name = header;
48   grpc_generator::StripPrefix(&base_name, "google/protobuf/");
49   // create the import code snippet
50   ::grpc::string framework_header =
51       ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
52
53   static const ::grpc::string kFrameworkImportsCondition =
54       "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
55   return PreprocIfElse(kFrameworkImportsCondition,
56                        indent + SystemImport(framework_header),
57                        indent + LocalImport(header));
58 }
59
60 }  // namespace
61
62 class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
63  public:
64   ObjectiveCGrpcGenerator() {}
65   virtual ~ObjectiveCGrpcGenerator() {}
66
67  public:
68   virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
69                         const ::grpc::string& parameter,
70                         grpc::protobuf::compiler::GeneratorContext* context,
71                         ::grpc::string* error) const {
72     if (file->service_count() == 0) {
73       // No services.  Do nothing.
74       return true;
75     }
76
77     static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
78     static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
79     static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
80     static const ::grpc::string kForwardDeclare =
81         "GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
82
83     ::grpc::string file_name =
84         google::protobuf::compiler::objectivec::FilePath(file);
85
86     {
87       // Generate .pbrpc.h
88
89       ::grpc::string imports = LocalImport(file_name + ".pbobjc.h");
90
91       ::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
92                                       SystemImport("ProtoRPC/ProtoRPC.h") +
93                                       SystemImport("RxLibrary/GRXWriteable.h") +
94                                       SystemImport("RxLibrary/GRXWriter.h");
95
96       ::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n";
97
98       ::grpc::string class_declarations =
99           grpc_objective_c_generator::GetAllMessageClasses(file);
100
101       ::grpc::string class_imports;
102       for (int i = 0; i < file->dependency_count(); i++) {
103         class_imports += ImportProtoHeaders(file->dependency(i), "  ");
104       }
105
106       ::grpc::string protocols;
107       for (int i = 0; i < file->service_count(); i++) {
108         const grpc::protobuf::ServiceDescriptor* service = file->service(i);
109         protocols += grpc_objective_c_generator::GetProtocol(service);
110       }
111
112       ::grpc::string interfaces;
113       for (int i = 0; i < file->service_count(); i++) {
114         const grpc::protobuf::ServiceDescriptor* service = file->service(i);
115         interfaces += grpc_objective_c_generator::GetInterface(service);
116       }
117
118       Write(context, file_name + ".pbrpc.h",
119             PreprocIfNot(kForwardDeclare, imports) + "\n" +
120                 PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
121                 class_declarations + "\n" +
122                 PreprocIfNot(kForwardDeclare, class_imports) + "\n" +
123                 forward_declarations + "\n" + kNonNullBegin + "\n" + protocols +
124                 "\n" + PreprocIfNot(kProtocolOnly, interfaces) + "\n" +
125                 kNonNullEnd + "\n");
126     }
127
128     {
129       // Generate .pbrpc.m
130
131       ::grpc::string imports = LocalImport(file_name + ".pbrpc.h") +
132                                LocalImport(file_name + ".pbobjc.h") +
133                                SystemImport("ProtoRPC/ProtoRPC.h") +
134                                SystemImport("RxLibrary/GRXWriter+Immediate.h");
135
136       ::grpc::string class_imports;
137       for (int i = 0; i < file->dependency_count(); i++) {
138         class_imports += ImportProtoHeaders(file->dependency(i), "");
139       }
140
141       ::grpc::string definitions;
142       for (int i = 0; i < file->service_count(); i++) {
143         const grpc::protobuf::ServiceDescriptor* service = file->service(i);
144         definitions += grpc_objective_c_generator::GetSource(service);
145       }
146
147       Write(context, file_name + ".pbrpc.m",
148             PreprocIfNot(kProtocolOnly,
149                          imports + "\n" + class_imports + "\n" + definitions));
150     }
151
152     return true;
153   }
154
155  private:
156   // Write the given code into the given file.
157   void Write(grpc::protobuf::compiler::GeneratorContext* context,
158              const ::grpc::string& filename, const ::grpc::string& code) const {
159     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
160         context->Open(filename));
161     grpc::protobuf::io::CodedOutputStream coded_out(output.get());
162     coded_out.WriteRaw(code.data(), code.size());
163   }
164 };
165
166 int main(int argc, char* argv[]) {
167   ObjectiveCGrpcGenerator generator;
168   return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
169 }