• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 30001;
49 
50 namespace compiler {
51 namespace objectivec {
52 
FileGenerator(const FileDescriptor * file,const Options & options)53 FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
54     : file_(file),
55       root_class_name_(FileClassName(file)),
56       is_public_dep_(false),
57       options_(options) {
58   for (int i = 0; i < file_->enum_type_count(); i++) {
59     EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
60     enum_generators_.push_back(generator);
61   }
62   for (int i = 0; i < file_->message_type_count(); i++) {
63     MessageGenerator *generator =
64         new MessageGenerator(root_class_name_, file_->message_type(i), options_);
65     message_generators_.push_back(generator);
66   }
67   for (int i = 0; i < file_->extension_count(); i++) {
68     ExtensionGenerator *generator =
69         new ExtensionGenerator(root_class_name_, file_->extension(i));
70     extension_generators_.push_back(generator);
71   }
72 }
73 
~FileGenerator()74 FileGenerator::~FileGenerator() {
75   STLDeleteContainerPointers(dependency_generators_.begin(),
76                              dependency_generators_.end());
77   STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
78   STLDeleteContainerPointers(message_generators_.begin(),
79                              message_generators_.end());
80   STLDeleteContainerPointers(extension_generators_.begin(),
81                              extension_generators_.end());
82 }
83 
GenerateHeader(io::Printer * printer)84 void FileGenerator::GenerateHeader(io::Printer *printer) {
85   printer->Print(
86       "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
87       "// source: $filename$\n"
88       "\n",
89       "filename", file_->name());
90 
91   printer->Print(
92       "#import \"GPBProtocolBuffers.h\"\n"
93       "\n");
94 
95   // Add some verification that the generated code matches the source the
96   // code is being compiled with.
97   printer->Print(
98       "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
99       "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
100       "#endif\n"
101       "\n",
102       "protoc_gen_objc_version",
103       SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
104 
105   const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
106   for (vector<FileGenerator *>::const_iterator iter =
107            dependency_generators.begin();
108        iter != dependency_generators.end(); ++iter) {
109     if ((*iter)->IsPublicDependency()) {
110       printer->Print("#import \"$header$.pbobjc.h\"\n",
111                      "header", (*iter)->Path());
112     }
113   }
114 
115   printer->Print(
116       "// @@protoc_insertion_point(imports)\n"
117       "\n"
118       "#pragma clang diagnostic push\n"
119       "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
120       "\n"
121       "CF_EXTERN_C_BEGIN\n"
122       "\n");
123 
124   set<string> fwd_decls;
125   for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
126        iter != message_generators_.end(); ++iter) {
127     (*iter)->DetermineForwardDeclarations(&fwd_decls);
128   }
129   for (set<string>::const_iterator i(fwd_decls.begin());
130        i != fwd_decls.end(); ++i) {
131     printer->Print("$value$;\n", "value", *i);
132   }
133   if (fwd_decls.begin() != fwd_decls.end()) {
134     printer->Print("\n");
135   }
136 
137   printer->Print(
138       "NS_ASSUME_NONNULL_BEGIN\n"
139       "\n");
140 
141   // need to write out all enums first
142   for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
143        iter != enum_generators_.end(); ++iter) {
144     (*iter)->GenerateHeader(printer);
145   }
146 
147   for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
148        iter != message_generators_.end(); ++iter) {
149     (*iter)->GenerateEnumHeader(printer);
150   }
151 
152   // For extensions to chain together, the Root gets created even if there
153   // are no extensions.
154   printer->Print(
155       "#pragma mark - $root_class_name$\n"
156       "\n"
157       "/// Exposes the extension registry for this file.\n"
158       "///\n"
159       "/// The base class provides:\n"
160       "/// @code\n"
161       "///   + (GPBExtensionRegistry *)extensionRegistry;\n"
162       "/// @endcode\n"
163       "/// which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
164       "/// this file and all files that it depends on.\n"
165       "@interface $root_class_name$ : GPBRootObject\n"
166       "@end\n"
167       "\n",
168       "root_class_name", root_class_name_);
169 
170   if (extension_generators_.size() > 0) {
171     // The dynamic methods block is only needed if there are extensions.
172     printer->Print(
173         "@interface $root_class_name$ (DynamicMethods)\n",
174         "root_class_name", root_class_name_);
175 
176     for (vector<ExtensionGenerator *>::iterator iter =
177              extension_generators_.begin();
178          iter != extension_generators_.end(); ++iter) {
179       (*iter)->GenerateMembersHeader(printer);
180     }
181 
182     printer->Print("@end\n\n");
183   }  // extension_generators_.size() > 0
184 
185   for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
186        iter != message_generators_.end(); ++iter) {
187     (*iter)->GenerateMessageHeader(printer);
188   }
189 
190   printer->Print(
191       "NS_ASSUME_NONNULL_END\n"
192       "\n"
193       "CF_EXTERN_C_END\n"
194       "\n"
195       "#pragma clang diagnostic pop\n"
196       "\n"
197       "// @@protoc_insertion_point(global_scope)\n");
198 }
199 
GenerateSource(io::Printer * printer)200 void FileGenerator::GenerateSource(io::Printer *printer) {
201   printer->Print(
202       "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
203       "// source: $filename$\n"
204       "\n",
205       "filename", file_->name());
206 
207   string header_file = Path() + ".pbobjc.h";
208   printer->Print(
209       "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
210       "#import \"$header_file$\"\n",
211       "header_file", header_file);
212   const vector<FileGenerator *> &dependency_generators =
213       DependencyGenerators();
214   for (vector<FileGenerator *>::const_iterator iter =
215            dependency_generators.begin();
216        iter != dependency_generators.end(); ++iter) {
217     if (!(*iter)->IsPublicDependency()) {
218       printer->Print("#import \"$header$.pbobjc.h\"\n",
219                      "header", (*iter)->Path());
220     }
221   }
222   printer->Print(
223       "// @@protoc_insertion_point(imports)\n"
224       "\n"
225       "#pragma clang diagnostic push\n"
226       "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
227       "\n");
228 
229   printer->Print(
230       "#pragma mark - $root_class_name$\n"
231       "\n"
232       "@implementation $root_class_name$\n\n",
233       "root_class_name", root_class_name_);
234 
235   // Generate the extension initialization structures for the top level and
236   // any nested messages.
237   ostringstream extensions_stringstream;
238   if (file_->extension_count() + file_->message_type_count() > 0) {
239     io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
240     io::Printer extensions_printer(&extensions_outputstream, '$');
241     for (vector<ExtensionGenerator *>::iterator iter =
242              extension_generators_.begin();
243          iter != extension_generators_.end(); ++iter) {
244       (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
245     }
246     for (vector<MessageGenerator *>::iterator iter =
247              message_generators_.begin();
248          iter != message_generators_.end(); ++iter) {
249       (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
250     }
251     extensions_stringstream.flush();
252   }
253 
254   // If there were any extensions or this file has any dependencies, output
255   // a registry to override to create the file specific registry.
256   const string& extensions_str = extensions_stringstream.str();
257   if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
258     printer->Print(
259         "+ (GPBExtensionRegistry*)extensionRegistry {\n"
260         "  // This is called by +initialize so there is no need to worry\n"
261         "  // about thread safety and initialization of registry.\n"
262         "  static GPBExtensionRegistry* registry = nil;\n"
263         "  if (!registry) {\n"
264         "    GPBDebugCheckRuntimeVersion();\n"
265         "    registry = [[GPBExtensionRegistry alloc] init];\n");
266 
267     printer->Indent();
268     printer->Indent();
269 
270     if (extensions_str.length() > 0) {
271       printer->Print(
272           "static GPBExtensionDescription descriptions[] = {\n");
273       printer->Indent();
274       printer->Print(extensions_str.c_str());
275       printer->Outdent();
276       printer->Print(
277           "};\n"
278           "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
279           "  GPBExtensionDescriptor *extension =\n"
280           "      [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n"
281           "  [registry addExtension:extension];\n"
282           "  [self globallyRegisterExtension:extension];\n"
283           "  [extension release];\n"
284           "}\n");
285     }
286 
287     const vector<FileGenerator *> &dependency_generators =
288         DependencyGenerators();
289     for (vector<FileGenerator *>::const_iterator iter =
290              dependency_generators.begin();
291          iter != dependency_generators.end(); ++iter) {
292       printer->Print(
293           "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
294           "dependency", (*iter)->RootClassName());
295     }
296 
297     printer->Outdent();
298     printer->Outdent();
299 
300     printer->Print(
301         "  }\n"
302         "  return registry;\n"
303         "}\n"
304         "\n");
305   }
306 
307   printer->Print("@end\n\n");
308 
309   // File descriptor only needed if there are messages to use it.
310   if (message_generators_.size() > 0) {
311     string syntax;
312     switch (file_->syntax()) {
313       case FileDescriptor::SYNTAX_UNKNOWN:
314         syntax = "GPBFileSyntaxUnknown";
315         break;
316       case FileDescriptor::SYNTAX_PROTO2:
317         syntax = "GPBFileSyntaxProto2";
318         break;
319       case FileDescriptor::SYNTAX_PROTO3:
320         syntax = "GPBFileSyntaxProto3";
321         break;
322     }
323     printer->Print(
324         "#pragma mark - $root_class_name$_FileDescriptor\n"
325         "\n"
326         "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
327         "  // This is called by +initialize so there is no need to worry\n"
328         "  // about thread safety of the singleton.\n"
329         "  static GPBFileDescriptor *descriptor = NULL;\n"
330         "  if (!descriptor) {\n"
331         "    GPBDebugCheckRuntimeVersion();\n"
332         "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
333         "                                                     syntax:$syntax$];\n"
334         "  }\n"
335         "  return descriptor;\n"
336         "}\n"
337         "\n",
338         "root_class_name", root_class_name_,
339         "package", file_->package(),
340         "syntax", syntax);
341   }
342 
343   for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
344        iter != enum_generators_.end(); ++iter) {
345     (*iter)->GenerateSource(printer);
346   }
347   for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
348        iter != message_generators_.end(); ++iter) {
349     (*iter)->GenerateSource(printer);
350   }
351 
352   printer->Print(
353     "\n"
354     "#pragma clang diagnostic pop\n"
355     "\n"
356     "// @@protoc_insertion_point(global_scope)\n");
357 }
358 
Path() const359 const string FileGenerator::Path() const { return FilePath(file_); }
360 
DependencyGenerators()361 const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
362   if (file_->dependency_count() != dependency_generators_.size()) {
363     set<string> public_import_names;
364     for (int i = 0; i < file_->public_dependency_count(); i++) {
365       public_import_names.insert(file_->public_dependency(i)->name());
366     }
367     for (int i = 0; i < file_->dependency_count(); i++) {
368       FileGenerator *generator =
369           new FileGenerator(file_->dependency(i), options_);
370       const string& name = file_->dependency(i)->name();
371       bool public_import = (public_import_names.count(name) != 0);
372       generator->SetIsPublicDependency(public_import);
373       dependency_generators_.push_back(generator);
374     }
375   }
376   return dependency_generators_;
377 }
378 
379 }  // namespace objectivec
380 }  // namespace compiler
381 }  // namespace protobuf
382 }  // namespace google
383