OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 19 matching lines...) Expand all Loading... |
30 | 30 |
31 #include <google/protobuf/compiler/objectivec/objectivec_file.h> | 31 #include <google/protobuf/compiler/objectivec/objectivec_file.h> |
32 #include <google/protobuf/compiler/objectivec/objectivec_enum.h> | 32 #include <google/protobuf/compiler/objectivec/objectivec_enum.h> |
33 #include <google/protobuf/compiler/objectivec/objectivec_extension.h> | 33 #include <google/protobuf/compiler/objectivec/objectivec_extension.h> |
34 #include <google/protobuf/compiler/objectivec/objectivec_message.h> | 34 #include <google/protobuf/compiler/objectivec/objectivec_message.h> |
35 #include <google/protobuf/compiler/code_generator.h> | 35 #include <google/protobuf/compiler/code_generator.h> |
36 #include <google/protobuf/io/printer.h> | 36 #include <google/protobuf/io/printer.h> |
37 #include <google/protobuf/io/zero_copy_stream_impl.h> | 37 #include <google/protobuf/io/zero_copy_stream_impl.h> |
38 #include <google/protobuf/stubs/stl_util.h> | 38 #include <google/protobuf/stubs/stl_util.h> |
39 #include <google/protobuf/stubs/strutil.h> | 39 #include <google/protobuf/stubs/strutil.h> |
40 #include <algorithm> // std::find() | |
41 #include <iostream> | |
42 #include <sstream> | 40 #include <sstream> |
43 | 41 |
44 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some | |
45 // error cases, so it seems to be ok to use as a back door for errors. | |
46 | |
47 namespace google { | 42 namespace google { |
48 namespace protobuf { | 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 |
49 namespace compiler { | 50 namespace compiler { |
50 namespace objectivec { | 51 namespace objectivec { |
51 | 52 |
52 namespace { | |
53 | |
54 // This is also found in GPBBootstrap.h, and needs to be kept in sync. | |
55 const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30002; | |
56 | |
57 const char* kHeaderExtension = ".pbobjc.h"; | |
58 | |
59 // Checks if a message contains any extension definitions (on the message or | |
60 // a nested message under it). | |
61 bool MessageContainsExtensions(const Descriptor* message) { | |
62 if (message->extension_count() > 0) { | |
63 return true; | |
64 } | |
65 for (int i = 0; i < message->nested_type_count(); i++) { | |
66 if (MessageContainsExtensions(message->nested_type(i))) { | |
67 return true; | |
68 } | |
69 } | |
70 return false; | |
71 } | |
72 | |
73 // Checks if the file contains any extensions definitions (at the root or | |
74 // nested under a message). | |
75 bool FileContainsExtensions(const FileDescriptor* file) { | |
76 if (file->extension_count() > 0) { | |
77 return true; | |
78 } | |
79 for (int i = 0; i < file->message_type_count(); i++) { | |
80 if (MessageContainsExtensions(file->message_type(i))) { | |
81 return true; | |
82 } | |
83 } | |
84 return false; | |
85 } | |
86 | |
87 // Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all | |
88 // deps as visited and prunes them from the needed files list. | |
89 void PruneFileAndDepsMarkingAsVisited( | |
90 const FileDescriptor* file, | |
91 vector<const FileDescriptor*>* files, | |
92 set<const FileDescriptor*>* files_visited) { | |
93 vector<const FileDescriptor*>::iterator iter = | |
94 std::find(files->begin(), files->end(), file); | |
95 if (iter != files->end()) { | |
96 files->erase(iter); | |
97 } | |
98 files_visited->insert(file); | |
99 for (int i = 0; i < file->dependency_count(); i++) { | |
100 PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited); | |
101 } | |
102 } | |
103 | |
104 // Helper for CollectMinimalFileDepsContainingExtensions. | |
105 void CollectMinimalFileDepsContainingExtensionsWorker( | |
106 const FileDescriptor* file, | |
107 vector<const FileDescriptor*>* files, | |
108 set<const FileDescriptor*>* files_visited) { | |
109 if (files_visited->find(file) != files_visited->end()) { | |
110 return; | |
111 } | |
112 files_visited->insert(file); | |
113 | |
114 if (FileContainsExtensions(file)) { | |
115 files->push_back(file); | |
116 for (int i = 0; i < file->dependency_count(); i++) { | |
117 const FileDescriptor* dep = file->dependency(i); | |
118 PruneFileAndDepsMarkingAsVisited(dep, files, files_visited); | |
119 } | |
120 } else { | |
121 for (int i = 0; i < file->dependency_count(); i++) { | |
122 const FileDescriptor* dep = file->dependency(i); | |
123 CollectMinimalFileDepsContainingExtensionsWorker(dep, files, | |
124 files_visited); | |
125 } | |
126 } | |
127 } | |
128 | |
129 // Collect the deps of the given file that contain extensions. This can be used
to | |
130 // create the chain of roots that need to be wired together. | |
131 // | |
132 // NOTE: If any changes are made to this and the supporting functions, you will | |
133 // need to manually validate what the generated code is for the test files: | |
134 // objectivec/Tests/unittest_extension_chain_*.proto | |
135 // There are comments about what the expected code should be line and limited | |
136 // testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports | |
137 // specifically). | |
138 void CollectMinimalFileDepsContainingExtensions( | |
139 const FileDescriptor* file, | |
140 vector<const FileDescriptor*>* files) { | |
141 set<const FileDescriptor*> files_visited; | |
142 for (int i = 0; i < file->dependency_count(); i++) { | |
143 const FileDescriptor* dep = file->dependency(i); | |
144 CollectMinimalFileDepsContainingExtensionsWorker(dep, files, | |
145 &files_visited); | |
146 } | |
147 } | |
148 | |
149 bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) { | |
150 for (int i = 0; i < file->dependency_count(); i++) { | |
151 if (dep == file->dependency(i)) { | |
152 return true; | |
153 } | |
154 } | |
155 return false; | |
156 } | |
157 | |
158 } // namespace | |
159 | |
160 FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) | 53 FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) |
161 : file_(file), | 54 : file_(file), |
162 root_class_name_(FileClassName(file)), | 55 root_class_name_(FileClassName(file)), |
| 56 is_public_dep_(false), |
163 options_(options) { | 57 options_(options) { |
164 for (int i = 0; i < file_->enum_type_count(); i++) { | 58 for (int i = 0; i < file_->enum_type_count(); i++) { |
165 EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); | 59 EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); |
166 enum_generators_.push_back(generator); | 60 enum_generators_.push_back(generator); |
167 } | 61 } |
168 for (int i = 0; i < file_->message_type_count(); i++) { | 62 for (int i = 0; i < file_->message_type_count(); i++) { |
169 MessageGenerator *generator = | 63 MessageGenerator *generator = |
170 new MessageGenerator(root_class_name_, file_->message_type(i), options_)
; | 64 new MessageGenerator(root_class_name_, file_->message_type(i), options_)
; |
171 message_generators_.push_back(generator); | 65 message_generators_.push_back(generator); |
172 } | 66 } |
173 for (int i = 0; i < file_->extension_count(); i++) { | 67 for (int i = 0; i < file_->extension_count(); i++) { |
174 ExtensionGenerator *generator = | 68 ExtensionGenerator *generator = |
175 new ExtensionGenerator(root_class_name_, file_->extension(i)); | 69 new ExtensionGenerator(root_class_name_, file_->extension(i)); |
176 extension_generators_.push_back(generator); | 70 extension_generators_.push_back(generator); |
177 } | 71 } |
178 } | 72 } |
179 | 73 |
180 FileGenerator::~FileGenerator() { | 74 FileGenerator::~FileGenerator() { |
| 75 STLDeleteContainerPointers(dependency_generators_.begin(), |
| 76 dependency_generators_.end()); |
181 STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); | 77 STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); |
182 STLDeleteContainerPointers(message_generators_.begin(), | 78 STLDeleteContainerPointers(message_generators_.begin(), |
183 message_generators_.end()); | 79 message_generators_.end()); |
184 STLDeleteContainerPointers(extension_generators_.begin(), | 80 STLDeleteContainerPointers(extension_generators_.begin(), |
185 extension_generators_.end()); | 81 extension_generators_.end()); |
186 } | 82 } |
187 | 83 |
188 void FileGenerator::GenerateHeader(io::Printer *printer) { | 84 void FileGenerator::GenerateHeader(io::Printer *printer) { |
189 PrintFileRuntimePreamble(printer, "GPBProtocolBuffers.h"); | 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"); |
190 | 94 |
191 // Add some verification that the generated code matches the source the | 95 // Add some verification that the generated code matches the source the |
192 // code is being compiled with. | 96 // code is being compiled with. |
193 // NOTE: This captures the raw numeric values at the time the generator was | |
194 // compiled, since that will be the versions for the ObjC runtime at that | |
195 // time. The constants in the generated code will then get their values at | |
196 // at compile time (so checking against the headers being used to compile). | |
197 printer->Print( | 97 printer->Print( |
198 "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" | 98 "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n" |
199 "#error This file was generated by a newer version of protoc which is inco
mpatible with your Protocol Buffer library sources.\n" | 99 "#error This file was generated by a different version of protoc which is
incompatible with your Protocol Buffer library sources.\n" |
200 "#endif\n" | |
201 "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_V
ERSION\n" | |
202 "#error This file was generated by an older version of protoc which is inc
ompatible with your Protocol Buffer library sources.\n" | |
203 "#endif\n" | 100 "#endif\n" |
204 "\n", | 101 "\n", |
205 "google_protobuf_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_VERSION)); | 102 "protoc_gen_objc_version", |
| 103 SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION)); |
206 | 104 |
207 // #import any headers for "public imports" in the proto file. | 105 const vector<FileGenerator *> &dependency_generators = DependencyGenerators(); |
208 { | 106 for (vector<FileGenerator *>::const_iterator iter = |
209 ImportWriter import_writer( | 107 dependency_generators.begin(); |
210 options_.generate_for_named_framework, | 108 iter != dependency_generators.end(); ++iter) { |
211 options_.named_framework_to_proto_path_mappings_path); | 109 if ((*iter)->IsPublicDependency()) { |
212 const string header_extension(kHeaderExtension); | 110 printer->Print("#import \"$header$.pbobjc.h\"\n", |
213 for (int i = 0; i < file_->public_dependency_count(); i++) { | 111 "header", (*iter)->Path()); |
214 import_writer.AddFile(file_->public_dependency(i), header_extension); | |
215 } | 112 } |
216 import_writer.Print(printer); | |
217 } | 113 } |
218 | 114 |
219 // Note: | |
220 // deprecated-declarations suppression is only needed if some place in this | |
221 // proto file is something deprecated or if it references something from | |
222 // another file that is deprecated. | |
223 printer->Print( | 115 printer->Print( |
224 "// @@protoc_insertion_point(imports)\n" | 116 "// @@protoc_insertion_point(imports)\n" |
225 "\n" | 117 "\n" |
226 "#pragma clang diagnostic push\n" | 118 "#pragma clang diagnostic push\n" |
227 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" | 119 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" |
228 "\n" | 120 "\n" |
229 "CF_EXTERN_C_BEGIN\n" | 121 "CF_EXTERN_C_BEGIN\n" |
230 "\n"); | 122 "\n"); |
231 | 123 |
232 set<string> fwd_decls; | 124 set<string> fwd_decls; |
(...skipping 22 matching lines...) Expand all Loading... |
255 for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); | 147 for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); |
256 iter != message_generators_.end(); ++iter) { | 148 iter != message_generators_.end(); ++iter) { |
257 (*iter)->GenerateEnumHeader(printer); | 149 (*iter)->GenerateEnumHeader(printer); |
258 } | 150 } |
259 | 151 |
260 // For extensions to chain together, the Root gets created even if there | 152 // For extensions to chain together, the Root gets created even if there |
261 // are no extensions. | 153 // are no extensions. |
262 printer->Print( | 154 printer->Print( |
263 "#pragma mark - $root_class_name$\n" | 155 "#pragma mark - $root_class_name$\n" |
264 "\n" | 156 "\n" |
265 "/**\n" | 157 "/// Exposes the extension registry for this file.\n" |
266 " * Exposes the extension registry for this file.\n" | 158 "///\n" |
267 " *\n" | 159 "/// The base class provides:\n" |
268 " * The base class provides:\n" | 160 "/// @code\n" |
269 " * @code\n" | 161 "/// + (GPBExtensionRegistry *)extensionRegistry;\n" |
270 " * + (GPBExtensionRegistry *)extensionRegistry;\n" | 162 "/// @endcode\n" |
271 " * @endcode\n" | 163 "/// which is a @c GPBExtensionRegistry that includes all the extensions d
efined by\n" |
272 " * which is a @c GPBExtensionRegistry that includes all the extensions de
fined by\n" | 164 "/// this file and all files that it depends on.\n" |
273 " * this file and all files that it depends on.\n" | |
274 " **/\n" | |
275 "@interface $root_class_name$ : GPBRootObject\n" | 165 "@interface $root_class_name$ : GPBRootObject\n" |
276 "@end\n" | 166 "@end\n" |
277 "\n", | 167 "\n", |
278 "root_class_name", root_class_name_); | 168 "root_class_name", root_class_name_); |
279 | 169 |
280 if (extension_generators_.size() > 0) { | 170 if (extension_generators_.size() > 0) { |
281 // The dynamic methods block is only needed if there are extensions. | 171 // The dynamic methods block is only needed if there are extensions. |
282 printer->Print( | 172 printer->Print( |
283 "@interface $root_class_name$ (DynamicMethods)\n", | 173 "@interface $root_class_name$ (DynamicMethods)\n", |
284 "root_class_name", root_class_name_); | 174 "root_class_name", root_class_name_); |
(...skipping 16 matching lines...) Expand all Loading... |
301 "NS_ASSUME_NONNULL_END\n" | 191 "NS_ASSUME_NONNULL_END\n" |
302 "\n" | 192 "\n" |
303 "CF_EXTERN_C_END\n" | 193 "CF_EXTERN_C_END\n" |
304 "\n" | 194 "\n" |
305 "#pragma clang diagnostic pop\n" | 195 "#pragma clang diagnostic pop\n" |
306 "\n" | 196 "\n" |
307 "// @@protoc_insertion_point(global_scope)\n"); | 197 "// @@protoc_insertion_point(global_scope)\n"); |
308 } | 198 } |
309 | 199 |
310 void FileGenerator::GenerateSource(io::Printer *printer) { | 200 void FileGenerator::GenerateSource(io::Printer *printer) { |
311 // #import the runtime support. | 201 printer->Print( |
312 PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h"); | 202 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
| 203 "// source: $filename$\n" |
| 204 "\n", |
| 205 "filename", file_->name()); |
313 | 206 |
314 vector<const FileDescriptor*> deps_with_extensions; | 207 string header_file = Path() + ".pbobjc.h"; |
315 CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions); | 208 printer->Print( |
316 | 209 "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n" |
317 { | 210 "#import \"$header_file$\"\n", |
318 ImportWriter import_writer( | 211 "header_file", header_file); |
319 options_.generate_for_named_framework, | 212 const vector<FileGenerator *> &dependency_generators = |
320 options_.named_framework_to_proto_path_mappings_path); | 213 DependencyGenerators(); |
321 const string header_extension(kHeaderExtension); | 214 for (vector<FileGenerator *>::const_iterator iter = |
322 | 215 dependency_generators.begin(); |
323 // #import the header for this proto file. | 216 iter != dependency_generators.end(); ++iter) { |
324 import_writer.AddFile(file_, header_extension); | 217 if (!(*iter)->IsPublicDependency()) { |
325 | 218 printer->Print("#import \"$header$.pbobjc.h\"\n", |
326 // #import the headers for anything that a plain dependency of this proto | 219 "header", (*iter)->Path()); |
327 // file (that means they were just an include, not a "public" include). | |
328 set<string> public_import_names; | |
329 for (int i = 0; i < file_->public_dependency_count(); i++) { | |
330 public_import_names.insert(file_->public_dependency(i)->name()); | |
331 } | |
332 for (int i = 0; i < file_->dependency_count(); i++) { | |
333 const FileDescriptor *dep = file_->dependency(i); | |
334 bool public_import = (public_import_names.count(dep->name()) != 0); | |
335 if (!public_import) { | |
336 import_writer.AddFile(dep, header_extension); | |
337 } | |
338 } | |
339 | |
340 // If any indirect dependency provided extensions, it needs to be directly | |
341 // imported so it can get merged into the root's extensions registry. | |
342 // See the Note by CollectMinimalFileDepsContainingExtensions before | |
343 // changing this. | |
344 for (vector<const FileDescriptor *>::iterator iter = | |
345 deps_with_extensions.begin(); | |
346 iter != deps_with_extensions.end(); ++iter) { | |
347 if (!IsDirectDependency(*iter, file_)) { | |
348 import_writer.AddFile(*iter, header_extension); | |
349 } | |
350 } | |
351 | |
352 import_writer.Print(printer); | |
353 } | |
354 | |
355 bool includes_oneof = false; | |
356 for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); | |
357 iter != message_generators_.end(); ++iter) { | |
358 if ((*iter)->IncludesOneOfDefinition()) { | |
359 includes_oneof = true; | |
360 break; | |
361 } | 220 } |
362 } | 221 } |
363 | |
364 // Note: | |
365 // deprecated-declarations suppression is only needed if some place in this | |
366 // proto file is something deprecated or if it references something from | |
367 // another file that is deprecated. | |
368 printer->Print( | 222 printer->Print( |
369 "// @@protoc_insertion_point(imports)\n" | 223 "// @@protoc_insertion_point(imports)\n" |
370 "\n" | 224 "\n" |
371 "#pragma clang diagnostic push\n" | 225 "#pragma clang diagnostic push\n" |
372 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); | 226 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" |
373 if (includes_oneof) { | 227 "\n"); |
374 // The generated code for oneof's uses direct ivar access, suppress the | |
375 // warning incase developer turn that on in the context they compile the | |
376 // generated code. | |
377 printer->Print( | |
378 "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); | |
379 } | |
380 | 228 |
381 printer->Print( | 229 printer->Print( |
382 "\n" | |
383 "#pragma mark - $root_class_name$\n" | 230 "#pragma mark - $root_class_name$\n" |
384 "\n" | 231 "\n" |
385 "@implementation $root_class_name$\n\n", | 232 "@implementation $root_class_name$\n\n", |
386 "root_class_name", root_class_name_); | 233 "root_class_name", root_class_name_); |
387 | 234 |
388 const bool file_contains_extensions = FileContainsExtensions(file_); | 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 } |
389 | 253 |
390 // If there were any extensions or this file has any dependencies, output | 254 // If there were any extensions or this file has any dependencies, output |
391 // a registry to override to create the file specific registry. | 255 // a registry to override to create the file specific registry. |
392 if (file_contains_extensions || !deps_with_extensions.empty()) { | 256 const string& extensions_str = extensions_stringstream.str(); |
| 257 if (extensions_str.length() > 0 || file_->dependency_count() > 0) { |
393 printer->Print( | 258 printer->Print( |
394 "+ (GPBExtensionRegistry*)extensionRegistry {\n" | 259 "+ (GPBExtensionRegistry*)extensionRegistry {\n" |
395 " // This is called by +initialize so there is no need to worry\n" | 260 " // This is called by +initialize so there is no need to worry\n" |
396 " // about thread safety and initialization of registry.\n" | 261 " // about thread safety and initialization of registry.\n" |
397 " static GPBExtensionRegistry* registry = nil;\n" | 262 " static GPBExtensionRegistry* registry = nil;\n" |
398 " if (!registry) {\n" | 263 " if (!registry) {\n" |
399 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" | 264 " GPBDebugCheckRuntimeVersion();\n" |
400 " registry = [[GPBExtensionRegistry alloc] init];\n"); | 265 " registry = [[GPBExtensionRegistry alloc] init];\n"); |
401 | 266 |
402 printer->Indent(); | 267 printer->Indent(); |
403 printer->Indent(); | 268 printer->Indent(); |
404 | 269 |
405 if (file_contains_extensions) { | 270 if (extensions_str.length() > 0) { |
406 printer->Print( | 271 printer->Print( |
407 "static GPBExtensionDescription descriptions[] = {\n"); | 272 "static GPBExtensionDescription descriptions[] = {\n"); |
408 printer->Indent(); | 273 printer->Indent(); |
409 for (vector<ExtensionGenerator *>::iterator iter = | 274 printer->Print(extensions_str.c_str()); |
410 extension_generators_.begin(); | |
411 iter != extension_generators_.end(); ++iter) { | |
412 (*iter)->GenerateStaticVariablesInitialization(printer); | |
413 } | |
414 for (vector<MessageGenerator *>::iterator iter = | |
415 message_generators_.begin(); | |
416 iter != message_generators_.end(); ++iter) { | |
417 (*iter)->GenerateStaticVariablesInitialization(printer); | |
418 } | |
419 printer->Outdent(); | 275 printer->Outdent(); |
420 printer->Print( | 276 printer->Print( |
421 "};\n" | 277 "};\n" |
422 "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0])
; ++i) {\n" | 278 "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0])
; ++i) {\n" |
423 " GPBExtensionDescriptor *extension =\n" | 279 " GPBExtensionDescriptor *extension =\n" |
424 " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&d
escriptions[i]];\n" | 280 " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&d
escriptions[i]];\n" |
425 " [registry addExtension:extension];\n" | 281 " [registry addExtension:extension];\n" |
426 " [self globallyRegisterExtension:extension];\n" | 282 " [self globallyRegisterExtension:extension];\n" |
427 " [extension release];\n" | 283 " [extension release];\n" |
428 "}\n"); | 284 "}\n"); |
429 } | 285 } |
430 | 286 |
431 if (deps_with_extensions.empty()) { | 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) { |
432 printer->Print( | 292 printer->Print( |
433 "// None of the imports (direct or indirect) defined extensions, so no
need to add\n" | 293 "[registry addExtensions:[$dependency$ extensionRegistry]];\n", |
434 "// them to this registry.\n"); | 294 "dependency", (*iter)->RootClassName()); |
435 } else { | |
436 printer->Print( | |
437 "// Merge in the imports (direct or indirect) that defined extensions.
\n"); | |
438 for (vector<const FileDescriptor *>::iterator iter = | |
439 deps_with_extensions.begin(); | |
440 iter != deps_with_extensions.end(); ++iter) { | |
441 const string root_class_name(FileClassName((*iter))); | |
442 printer->Print( | |
443 "[registry addExtensions:[$dependency$ extensionRegistry]];\n", | |
444 "dependency", root_class_name); | |
445 } | |
446 } | 295 } |
447 | 296 |
448 printer->Outdent(); | 297 printer->Outdent(); |
449 printer->Outdent(); | 298 printer->Outdent(); |
450 | 299 |
451 printer->Print( | 300 printer->Print( |
452 " }\n" | 301 " }\n" |
453 " return registry;\n" | 302 " return registry;\n" |
454 "}\n"); | 303 "}\n" |
455 } else { | 304 "\n"); |
456 if (file_->dependency_count() > 0) { | |
457 printer->Print( | |
458 "// No extensions in the file and none of the imports (direct or indir
ect)\n" | |
459 "// defined extensions, so no need to generate +extensionRegistry.\n")
; | |
460 } else { | |
461 printer->Print( | |
462 "// No extensions in the file and no imports, so no need to generate\n
" | |
463 "// +extensionRegistry.\n"); | |
464 } | |
465 } | 305 } |
466 | 306 |
467 printer->Print("\n@end\n\n"); | 307 printer->Print("@end\n\n"); |
468 | 308 |
469 // File descriptor only needed if there are messages to use it. | 309 // File descriptor only needed if there are messages to use it. |
470 if (message_generators_.size() > 0) { | 310 if (message_generators_.size() > 0) { |
471 map<string, string> vars; | 311 string syntax; |
472 vars["root_class_name"] = root_class_name_; | |
473 vars["package"] = file_->package(); | |
474 vars["objc_prefix"] = FileClassPrefix(file_); | |
475 switch (file_->syntax()) { | 312 switch (file_->syntax()) { |
476 case FileDescriptor::SYNTAX_UNKNOWN: | 313 case FileDescriptor::SYNTAX_UNKNOWN: |
477 vars["syntax"] = "GPBFileSyntaxUnknown"; | 314 syntax = "GPBFileSyntaxUnknown"; |
478 break; | 315 break; |
479 case FileDescriptor::SYNTAX_PROTO2: | 316 case FileDescriptor::SYNTAX_PROTO2: |
480 vars["syntax"] = "GPBFileSyntaxProto2"; | 317 syntax = "GPBFileSyntaxProto2"; |
481 break; | 318 break; |
482 case FileDescriptor::SYNTAX_PROTO3: | 319 case FileDescriptor::SYNTAX_PROTO3: |
483 vars["syntax"] = "GPBFileSyntaxProto3"; | 320 syntax = "GPBFileSyntaxProto3"; |
484 break; | 321 break; |
485 } | 322 } |
486 printer->Print(vars, | 323 printer->Print( |
487 "#pragma mark - $root_class_name$_FileDescriptor\n" | 324 "#pragma mark - $root_class_name$_FileDescriptor\n" |
488 "\n" | 325 "\n" |
489 "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" | 326 "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" |
490 " // This is called by +initialize so there is no need to worry\n" | 327 " // This is called by +initialize so there is no need to worry\n" |
491 " // about thread safety of the singleton.\n" | 328 " // about thread safety of the singleton.\n" |
492 " static GPBFileDescriptor *descriptor = NULL;\n" | 329 " static GPBFileDescriptor *descriptor = NULL;\n" |
493 " if (!descriptor) {\n" | 330 " if (!descriptor) {\n" |
494 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); | 331 " GPBDebugCheckRuntimeVersion();\n" |
495 if (vars["objc_prefix"].size() > 0) { | 332 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package
$\"\n" |
496 printer->Print( | 333 " syntax:$syntax$];\
n" |
497 vars, | |
498 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$packa
ge$\"\n" | |
499 " objcPrefix:@\"$objc_
prefix$\"\n" | |
500 " syntax:$syntax$]
;\n"); | |
501 } else { | |
502 printer->Print( | |
503 vars, | |
504 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$packa
ge$\"\n" | |
505 " syntax:$syntax$]
;\n"); | |
506 } | |
507 printer->Print( | |
508 " }\n" | 334 " }\n" |
509 " return descriptor;\n" | 335 " return descriptor;\n" |
510 "}\n" | 336 "}\n" |
511 "\n"); | 337 "\n", |
| 338 "root_class_name", root_class_name_, |
| 339 "package", file_->package(), |
| 340 "syntax", syntax); |
512 } | 341 } |
513 | 342 |
514 for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin(); | 343 for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin(); |
515 iter != enum_generators_.end(); ++iter) { | 344 iter != enum_generators_.end(); ++iter) { |
516 (*iter)->GenerateSource(printer); | 345 (*iter)->GenerateSource(printer); |
517 } | 346 } |
518 for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); | 347 for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); |
519 iter != message_generators_.end(); ++iter) { | 348 iter != message_generators_.end(); ++iter) { |
520 (*iter)->GenerateSource(printer); | 349 (*iter)->GenerateSource(printer); |
521 } | 350 } |
522 | 351 |
523 printer->Print( | 352 printer->Print( |
524 "\n" | 353 "\n" |
525 "#pragma clang diagnostic pop\n" | 354 "#pragma clang diagnostic pop\n" |
526 "\n" | 355 "\n" |
527 "// @@protoc_insertion_point(global_scope)\n"); | 356 "// @@protoc_insertion_point(global_scope)\n"); |
528 } | 357 } |
529 | 358 |
530 // Helper to print the import of the runtime support at the top of generated | 359 const string FileGenerator::Path() const { return FilePath(file_); } |
531 // files. This currently only supports the runtime coming from a framework | |
532 // as defined by the official CocoaPod. | |
533 void FileGenerator::PrintFileRuntimePreamble( | |
534 io::Printer* printer, const string& header_to_import) const { | |
535 printer->Print( | |
536 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" | |
537 "// source: $filename$\n" | |
538 "\n", | |
539 "filename", file_->name()); | |
540 | 360 |
541 const string framework_name(ProtobufLibraryFrameworkName); | 361 const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { |
542 const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); | 362 if (file_->dependency_count() != dependency_generators_.size()) { |
543 printer->Print( | 363 set<string> public_import_names; |
544 "// This CPP symbol can be defined to use imports that match up to the fra
mework\n" | 364 for (int i = 0; i < file_->public_dependency_count(); i++) { |
545 "// imports needed when using CocoaPods.\n" | 365 public_import_names.insert(file_->public_dependency(i)->name()); |
546 "#if !defined($cpp_symbol$)\n" | 366 } |
547 " #define $cpp_symbol$ 0\n" | 367 for (int i = 0; i < file_->dependency_count(); i++) { |
548 "#endif\n" | 368 FileGenerator *generator = |
549 "\n" | 369 new FileGenerator(file_->dependency(i), options_); |
550 "#if $cpp_symbol$\n" | 370 const string& name = file_->dependency(i)->name(); |
551 " #import <$framework_name$/$header$>\n" | 371 bool public_import = (public_import_names.count(name) != 0); |
552 "#else\n" | 372 generator->SetIsPublicDependency(public_import); |
553 " #import \"$header$\"\n" | 373 dependency_generators_.push_back(generator); |
554 "#endif\n" | 374 } |
555 "\n", | 375 } |
556 "cpp_symbol", cpp_symbol, | 376 return dependency_generators_; |
557 "header", header_to_import, | |
558 "framework_name", framework_name); | |
559 } | 377 } |
560 | 378 |
561 } // namespace objectivec | 379 } // namespace objectivec |
562 } // namespace compiler | 380 } // namespace compiler |
563 } // namespace protobuf | 381 } // namespace protobuf |
564 } // namespace google | 382 } // namespace google |
OLD | NEW |