Line data Source code
1 : // Protocol Buffers - Google's data interchange format
2 : // Copyright 2008 Google Inc. All rights reserved.
3 : // https://developers.google.com/protocol-buffers/
4 : //
5 : // Redistribution and use in source and binary forms, with or without
6 : // modification, are permitted provided that the following conditions are
7 : // met:
8 : //
9 : // * Redistributions of source code must retain the above copyright
10 : // notice, this list of conditions and the following disclaimer.
11 : // * Redistributions in binary form must reproduce the above
12 : // copyright notice, this list of conditions and the following disclaimer
13 : // in the documentation and/or other materials provided with the
14 : // distribution.
15 : // * Neither the name of Google Inc. nor the names of its
16 : // contributors may be used to endorse or promote products derived from
17 : // this software without specific prior written permission.
18 : //
19 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 :
31 : #include <google/protobuf/compiler/objectivec/objectivec_file.h>
32 : #include <google/protobuf/compiler/objectivec/objectivec_enum.h>
33 : #include <google/protobuf/compiler/objectivec/objectivec_extension.h>
34 : #include <google/protobuf/compiler/objectivec/objectivec_message.h>
35 : #include <google/protobuf/compiler/code_generator.h>
36 : #include <google/protobuf/io/printer.h>
37 : #include <google/protobuf/io/zero_copy_stream_impl.h>
38 : #include <google/protobuf/stubs/stl_util.h>
39 : #include <google/protobuf/stubs/strutil.h>
40 : #include <sstream>
41 :
42 : namespace google {
43 : namespace protobuf {
44 :
45 : // This is also found in GPBBootstrap.h, and needs to be kept in sync. It
46 : // is the version check done to ensure generated code works with the current
47 : // runtime being used.
48 : const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000;
49 :
50 : namespace compiler {
51 : namespace objectivec {
52 :
53 0 : FileGenerator::FileGenerator(const FileDescriptor *file)
54 : : file_(file),
55 : root_class_name_(FileClassName(file)),
56 0 : is_public_dep_(false) {
57 0 : for (int i = 0; i < file_->enum_type_count(); i++) {
58 0 : EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
59 0 : enum_generators_.push_back(generator);
60 : }
61 0 : for (int i = 0; i < file_->message_type_count(); i++) {
62 : MessageGenerator *generator =
63 0 : new MessageGenerator(root_class_name_, file_->message_type(i));
64 0 : message_generators_.push_back(generator);
65 : }
66 0 : for (int i = 0; i < file_->extension_count(); i++) {
67 : ExtensionGenerator *generator =
68 0 : new ExtensionGenerator(root_class_name_, file_->extension(i));
69 0 : extension_generators_.push_back(generator);
70 : }
71 0 : }
72 :
73 0 : FileGenerator::~FileGenerator() {
74 : STLDeleteContainerPointers(dependency_generators_.begin(),
75 0 : dependency_generators_.end());
76 0 : STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
77 : STLDeleteContainerPointers(message_generators_.begin(),
78 0 : message_generators_.end());
79 : STLDeleteContainerPointers(extension_generators_.begin(),
80 0 : extension_generators_.end());
81 0 : }
82 :
83 0 : void FileGenerator::GenerateHeader(io::Printer *printer) {
84 : printer->Print(
85 : "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
86 : "// source: $filename$\n"
87 : "\n",
88 0 : "filename", file_->name());
89 :
90 : printer->Print(
91 : "#import \"GPBProtocolBuffers.h\"\n"
92 0 : "\n");
93 :
94 : // Add some verification that the generated code matches the source the
95 : // code is being compiled with.
96 : printer->Print(
97 : "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
98 : "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n"
99 : "#endif\n"
100 : "\n",
101 : "protoc_gen_objc_version",
102 0 : SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
103 :
104 0 : const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
105 0 : for (vector<FileGenerator *>::const_iterator iter =
106 0 : dependency_generators.begin();
107 0 : iter != dependency_generators.end(); ++iter) {
108 0 : if ((*iter)->IsPublicDependency()) {
109 : printer->Print("#import \"$header$.pbobjc.h\"\n",
110 0 : "header", (*iter)->Path());
111 : }
112 : }
113 :
114 : printer->Print(
115 : "// @@protoc_insertion_point(imports)\n"
116 : "\n"
117 : "CF_EXTERN_C_BEGIN\n"
118 0 : "\n");
119 :
120 : set<string> fwd_decls;
121 0 : for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
122 0 : iter != message_generators_.end(); ++iter) {
123 0 : (*iter)->DetermineForwardDeclarations(&fwd_decls);
124 : }
125 0 : for (set<string>::const_iterator i(fwd_decls.begin());
126 0 : i != fwd_decls.end(); ++i) {
127 0 : printer->Print("$value$;\n", "value", *i);
128 : }
129 0 : if (fwd_decls.begin() != fwd_decls.end()) {
130 0 : printer->Print("\n");
131 : }
132 :
133 : printer->Print(
134 : "NS_ASSUME_NONNULL_BEGIN\n"
135 0 : "\n");
136 :
137 : // need to write out all enums first
138 0 : for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
139 0 : iter != enum_generators_.end(); ++iter) {
140 0 : (*iter)->GenerateHeader(printer);
141 : }
142 :
143 0 : for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
144 0 : iter != message_generators_.end(); ++iter) {
145 0 : (*iter)->GenerateEnumHeader(printer);
146 : }
147 :
148 : // For extensions to chain together, the Root gets created even if there
149 : // are no extensions.
150 : printer->Print(
151 : "#pragma mark - $root_class_name$\n"
152 : "\n"
153 : "@interface $root_class_name$ : GPBRootObject\n"
154 : "\n"
155 : "// The base class provides:\n"
156 : "// + (GPBExtensionRegistry *)extensionRegistry;\n"
157 : "// which is an GPBExtensionRegistry that includes all the extensions defined by\n"
158 : "// this file and all files that it depends on.\n"
159 : "\n"
160 : "@end\n"
161 : "\n",
162 0 : "root_class_name", root_class_name_);
163 :
164 0 : if (extension_generators_.size() > 0) {
165 : // The dynamic methods block is only needed if there are extensions.
166 : printer->Print(
167 : "@interface $root_class_name$ (DynamicMethods)\n",
168 0 : "root_class_name", root_class_name_);
169 :
170 0 : for (vector<ExtensionGenerator *>::iterator iter =
171 0 : extension_generators_.begin();
172 0 : iter != extension_generators_.end(); ++iter) {
173 0 : (*iter)->GenerateMembersHeader(printer);
174 : }
175 :
176 0 : printer->Print("@end\n\n");
177 : } // extension_generators_.size() > 0
178 :
179 0 : for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
180 0 : iter != message_generators_.end(); ++iter) {
181 0 : (*iter)->GenerateMessageHeader(printer);
182 : }
183 :
184 : printer->Print(
185 : "NS_ASSUME_NONNULL_END\n"
186 : "\n"
187 : "CF_EXTERN_C_END\n"
188 : "\n"
189 0 : "// @@protoc_insertion_point(global_scope)\n");
190 0 : }
191 :
192 0 : void FileGenerator::GenerateSource(io::Printer *printer) {
193 : printer->Print(
194 : "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
195 : "// source: $filename$\n"
196 : "\n",
197 0 : "filename", file_->name());
198 :
199 0 : string header_file = Path() + ".pbobjc.h";
200 : printer->Print(
201 : "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
202 : "#import \"$header_file$\"\n",
203 0 : "header_file", header_file);
204 0 : const vector<FileGenerator *> &dependency_generators =
205 0 : DependencyGenerators();
206 0 : for (vector<FileGenerator *>::const_iterator iter =
207 0 : dependency_generators.begin();
208 0 : iter != dependency_generators.end(); ++iter) {
209 0 : if (!(*iter)->IsPublicDependency()) {
210 : printer->Print("#import \"$header$.pbobjc.h\"\n",
211 0 : "header", (*iter)->Path());
212 : }
213 : }
214 : printer->Print(
215 : "// @@protoc_insertion_point(imports)\n"
216 0 : "\n");
217 :
218 : printer->Print(
219 : "#pragma mark - $root_class_name$\n"
220 : "\n"
221 : "@implementation $root_class_name$\n\n",
222 0 : "root_class_name", root_class_name_);
223 :
224 : // Generate the extension initialization structures for the top level and
225 : // any nested messages.
226 0 : ostringstream extensions_stringstream;
227 0 : if (file_->extension_count() + file_->message_type_count() > 0) {
228 0 : io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
229 0 : io::Printer extensions_printer(&extensions_outputstream, '$');
230 0 : for (vector<ExtensionGenerator *>::iterator iter =
231 0 : extension_generators_.begin();
232 0 : iter != extension_generators_.end(); ++iter) {
233 0 : (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
234 : }
235 0 : for (vector<MessageGenerator *>::iterator iter =
236 0 : message_generators_.begin();
237 0 : iter != message_generators_.end(); ++iter) {
238 0 : (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
239 : }
240 0 : extensions_stringstream.flush();
241 : }
242 :
243 : // If there were any extensions or this file has any dependencies, output
244 : // a registry to override to create the file specific registry.
245 0 : const string& extensions_str = extensions_stringstream.str();
246 0 : if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
247 : printer->Print(
248 : "+ (GPBExtensionRegistry*)extensionRegistry {\n"
249 : " // This is called by +initialize so there is no need to worry\n"
250 : " // about thread safety and initialization of registry.\n"
251 : " static GPBExtensionRegistry* registry = nil;\n"
252 : " if (!registry) {\n"
253 : " GPBDebugCheckRuntimeVersion();\n"
254 0 : " registry = [[GPBExtensionRegistry alloc] init];\n");
255 :
256 0 : printer->Indent();
257 0 : printer->Indent();
258 :
259 0 : if (extensions_str.length() > 0) {
260 : printer->Print(
261 0 : "static GPBExtensionDescription descriptions[] = {\n");
262 0 : printer->Indent();
263 0 : printer->Print(extensions_str.c_str());
264 0 : printer->Outdent();
265 : printer->Print(
266 : "};\n"
267 : "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
268 : " GPBExtensionDescriptor *extension =\n"
269 : " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n"
270 : " [registry addExtension:extension];\n"
271 : " [self globallyRegisterExtension:extension];\n"
272 : " [extension release];\n"
273 0 : "}\n");
274 : }
275 :
276 0 : const vector<FileGenerator *> &dependency_generators =
277 0 : DependencyGenerators();
278 0 : for (vector<FileGenerator *>::const_iterator iter =
279 0 : dependency_generators.begin();
280 0 : iter != dependency_generators.end(); ++iter) {
281 : printer->Print(
282 : "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
283 0 : "dependency", (*iter)->RootClassName());
284 : }
285 :
286 0 : printer->Outdent();
287 0 : printer->Outdent();
288 :
289 : printer->Print(
290 : " }\n"
291 : " return registry;\n"
292 : "}\n"
293 0 : "\n");
294 : }
295 :
296 0 : printer->Print("@end\n\n");
297 :
298 : // File descriptor only needed if there are messages to use it.
299 0 : if (message_generators_.size() > 0) {
300 : string syntax;
301 0 : switch (file_->syntax()) {
302 : case FileDescriptor::SYNTAX_UNKNOWN:
303 : syntax = "GPBFileSyntaxUnknown";
304 : break;
305 : case FileDescriptor::SYNTAX_PROTO2:
306 : syntax = "GPBFileSyntaxProto2";
307 : break;
308 : case FileDescriptor::SYNTAX_PROTO3:
309 : syntax = "GPBFileSyntaxProto3";
310 : break;
311 : }
312 : printer->Print(
313 : "#pragma mark - $root_class_name$_FileDescriptor\n"
314 : "\n"
315 : "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
316 : " // This is called by +initialize so there is no need to worry\n"
317 : " // about thread safety of the singleton.\n"
318 : " static GPBFileDescriptor *descriptor = NULL;\n"
319 : " if (!descriptor) {\n"
320 : " GPBDebugCheckRuntimeVersion();\n"
321 : " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
322 : " syntax:$syntax$];\n"
323 : " }\n"
324 : " return descriptor;\n"
325 : "}\n"
326 : "\n",
327 : "root_class_name", root_class_name_,
328 0 : "package", file_->package(),
329 0 : "syntax", syntax);
330 : }
331 :
332 0 : for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
333 0 : iter != enum_generators_.end(); ++iter) {
334 0 : (*iter)->GenerateSource(printer);
335 : }
336 0 : for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
337 0 : iter != message_generators_.end(); ++iter) {
338 0 : (*iter)->GenerateSource(printer);
339 : }
340 :
341 : printer->Print(
342 : "\n"
343 0 : "// @@protoc_insertion_point(global_scope)\n");
344 0 : }
345 :
346 0 : const string FileGenerator::Path() const { return FilePath(file_); }
347 :
348 0 : const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
349 0 : if (file_->dependency_count() != dependency_generators_.size()) {
350 : set<string> public_import_names;
351 0 : for (int i = 0; i < file_->public_dependency_count(); i++) {
352 0 : public_import_names.insert(file_->public_dependency(i)->name());
353 : }
354 0 : for (int i = 0; i < file_->dependency_count(); i++) {
355 0 : FileGenerator *generator = new FileGenerator(file_->dependency(i));
356 0 : const string& name = file_->dependency(i)->name();
357 0 : bool public_import = (public_import_names.count(name) != 0);
358 0 : generator->SetIsPublicDependency(public_import);
359 0 : dependency_generators_.push_back(generator);
360 : }
361 : }
362 0 : return dependency_generators_;
363 : }
364 :
365 : } // namespace objectivec
366 : } // namespace compiler
367 : } // namespace protobuf
368 : } // namespace google
|