1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
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 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <google/protobuf/compiler/cpp/cpp_file.h>
36 #include <google/protobuf/compiler/cpp/cpp_enum.h>
37 #include <google/protobuf/compiler/cpp/cpp_service.h>
38 #include <google/protobuf/compiler/cpp/cpp_extension.h>
39 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
40 #include <google/protobuf/compiler/cpp/cpp_message.h>
41 #include <google/protobuf/compiler/cpp/cpp_field.h>
42 #include <google/protobuf/io/printer.h>
43 #include <google/protobuf/descriptor.pb.h>
44 #include <google/protobuf/stubs/strutil.h>
45
46 namespace google {
47 namespace protobuf {
48 namespace compiler {
49 namespace cpp {
50
51 // ===================================================================
52
FileGenerator(const FileDescriptor * file,const string & dllexport_decl)53 FileGenerator::FileGenerator(const FileDescriptor* file,
54 const string& dllexport_decl)
55 : file_(file),
56 message_generators_(
57 new scoped_ptr<MessageGenerator>[file->message_type_count()]),
58 enum_generators_(
59 new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
60 service_generators_(
61 new scoped_ptr<ServiceGenerator>[file->service_count()]),
62 extension_generators_(
63 new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
64 dllexport_decl_(dllexport_decl) {
65
66 for (int i = 0; i < file->message_type_count(); i++) {
67 message_generators_[i].reset(
68 new MessageGenerator(file->message_type(i), dllexport_decl));
69 }
70
71 for (int i = 0; i < file->enum_type_count(); i++) {
72 enum_generators_[i].reset(
73 new EnumGenerator(file->enum_type(i), dllexport_decl));
74 }
75
76 for (int i = 0; i < file->service_count(); i++) {
77 service_generators_[i].reset(
78 new ServiceGenerator(file->service(i), dllexport_decl));
79 }
80
81 for (int i = 0; i < file->extension_count(); i++) {
82 extension_generators_[i].reset(
83 new ExtensionGenerator(file->extension(i), dllexport_decl));
84 }
85
86 SplitStringUsing(file_->package(), ".", &package_parts_);
87 }
88
~FileGenerator()89 FileGenerator::~FileGenerator() {}
90
GenerateHeader(io::Printer * printer)91 void FileGenerator::GenerateHeader(io::Printer* printer) {
92 string filename_identifier = FilenameIdentifier(file_->name());
93
94 // Generate top of header.
95 printer->Print(
96 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
97 "// source: $filename$\n"
98 "\n"
99 "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
100 "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
101 "\n"
102 "#include <string>\n"
103 "\n",
104 "filename", file_->name(),
105 "filename_identifier", filename_identifier);
106
107 printer->Print(
108 "#include <google/protobuf/stubs/common.h>\n"
109 "\n");
110
111 // Verify the protobuf library header version is compatible with the protoc
112 // version before going any further.
113 printer->Print(
114 "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
115 "#error This file was generated by a newer version of protoc which is\n"
116 "#error incompatible with your Protocol Buffer headers. Please update\n"
117 "#error your headers.\n"
118 "#endif\n"
119 "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
120 "#error This file was generated by an older version of protoc which is\n"
121 "#error incompatible with your Protocol Buffer headers. Please\n"
122 "#error regenerate this file with a newer version of protoc.\n"
123 "#endif\n"
124 "\n",
125 "min_header_version",
126 SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
127 "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
128
129 // OK, it's now safe to #include other files.
130 printer->Print(
131 "#include <google/protobuf/generated_message_util.h>\n"
132 "#include <google/protobuf/repeated_field.h>\n"
133 "#include <google/protobuf/extension_set.h>\n");
134
135 if (HasDescriptorMethods(file_)) {
136 printer->Print(
137 "#include <google/protobuf/generated_message_reflection.h>\n");
138 }
139
140 if (HasGenericServices(file_)) {
141 printer->Print(
142 "#include <google/protobuf/service.h>\n");
143 }
144
145
146 for (int i = 0; i < file_->dependency_count(); i++) {
147 printer->Print(
148 "#include \"$dependency$.pb.h\"\n",
149 "dependency", StripProto(file_->dependency(i)->name()));
150 }
151
152 printer->Print(
153 "// @@protoc_insertion_point(includes)\n");
154
155 // Open namespace.
156 GenerateNamespaceOpeners(printer);
157
158 // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
159 // functions, so that we can declare them to be friends of each class.
160 printer->Print(
161 "\n"
162 "// Internal implementation detail -- do not call these.\n"
163 "void $dllexport_decl$ $adddescriptorsname$();\n",
164 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
165 "dllexport_decl", dllexport_decl_);
166
167 printer->Print(
168 // Note that we don't put dllexport_decl on these because they are only
169 // called by the .pb.cc file in which they are defined.
170 "void $assigndescriptorsname$();\n"
171 "void $shutdownfilename$();\n"
172 "\n",
173 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
174 "shutdownfilename", GlobalShutdownFileName(file_->name()));
175
176 // Generate forward declarations of classes.
177 for (int i = 0; i < file_->message_type_count(); i++) {
178 message_generators_[i]->GenerateForwardDeclaration(printer);
179 }
180
181 printer->Print("\n");
182
183 // Generate enum definitions.
184 for (int i = 0; i < file_->message_type_count(); i++) {
185 message_generators_[i]->GenerateEnumDefinitions(printer);
186 }
187 for (int i = 0; i < file_->enum_type_count(); i++) {
188 enum_generators_[i]->GenerateDefinition(printer);
189 }
190
191 printer->Print(kThickSeparator);
192 printer->Print("\n");
193
194 // Generate class definitions.
195 for (int i = 0; i < file_->message_type_count(); i++) {
196 if (i > 0) {
197 printer->Print("\n");
198 printer->Print(kThinSeparator);
199 printer->Print("\n");
200 }
201 message_generators_[i]->GenerateClassDefinition(printer);
202 }
203
204 printer->Print("\n");
205 printer->Print(kThickSeparator);
206 printer->Print("\n");
207
208 if (HasGenericServices(file_)) {
209 // Generate service definitions.
210 for (int i = 0; i < file_->service_count(); i++) {
211 if (i > 0) {
212 printer->Print("\n");
213 printer->Print(kThinSeparator);
214 printer->Print("\n");
215 }
216 service_generators_[i]->GenerateDeclarations(printer);
217 }
218
219 printer->Print("\n");
220 printer->Print(kThickSeparator);
221 printer->Print("\n");
222 }
223
224 // Declare extension identifiers.
225 for (int i = 0; i < file_->extension_count(); i++) {
226 extension_generators_[i]->GenerateDeclaration(printer);
227 }
228
229 printer->Print("\n");
230 printer->Print(kThickSeparator);
231 printer->Print("\n");
232
233 // Generate class inline methods.
234 for (int i = 0; i < file_->message_type_count(); i++) {
235 if (i > 0) {
236 printer->Print(kThinSeparator);
237 printer->Print("\n");
238 }
239 message_generators_[i]->GenerateInlineMethods(printer);
240 }
241
242 printer->Print(
243 "\n"
244 "// @@protoc_insertion_point(namespace_scope)\n");
245
246 // Close up namespace.
247 GenerateNamespaceClosers(printer);
248
249 // Emit GetEnumDescriptor specializations into google::protobuf namespace:
250 if (HasDescriptorMethods(file_)) {
251 // The SWIG conditional is to avoid a null-pointer dereference
252 // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
253 // namespace X { void Y<Z::W>(); }
254 // which appears in GetEnumDescriptor() specializations.
255 printer->Print(
256 "\n"
257 "#ifndef SWIG\n"
258 "namespace google {\nnamespace protobuf {\n"
259 "\n");
260 for (int i = 0; i < file_->message_type_count(); i++) {
261 message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
262 }
263 for (int i = 0; i < file_->enum_type_count(); i++) {
264 enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
265 }
266 printer->Print(
267 "\n"
268 "} // namespace google\n} // namespace protobuf\n"
269 "#endif // SWIG\n");
270 }
271
272 printer->Print(
273 "\n"
274 "// @@protoc_insertion_point(global_scope)\n"
275 "\n");
276
277 printer->Print(
278 "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
279 "filename_identifier", filename_identifier);
280 }
281
GenerateSource(io::Printer * printer)282 void FileGenerator::GenerateSource(io::Printer* printer) {
283 printer->Print(
284 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
285 "\n"
286 // The generated code calls accessors that might be deprecated. We don't
287 // want the compiler to warn in generated code.
288 "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
289 "#include \"$basename$.pb.h\"\n"
290
291 "#include <google/protobuf/stubs/once.h>\n"
292 "#include <google/protobuf/io/coded_stream.h>\n"
293 "#include <google/protobuf/wire_format_lite_inl.h>\n",
294 "basename", StripProto(file_->name()));
295
296 if (HasDescriptorMethods(file_)) {
297 printer->Print(
298 "#include <google/protobuf/descriptor.h>\n"
299 "#include <google/protobuf/reflection_ops.h>\n"
300 "#include <google/protobuf/wire_format.h>\n");
301 }
302
303 printer->Print(
304 "// @@protoc_insertion_point(includes)\n");
305
306 GenerateNamespaceOpeners(printer);
307
308 if (HasDescriptorMethods(file_)) {
309 printer->Print(
310 "\n"
311 "namespace {\n"
312 "\n");
313 for (int i = 0; i < file_->message_type_count(); i++) {
314 message_generators_[i]->GenerateDescriptorDeclarations(printer);
315 }
316 for (int i = 0; i < file_->enum_type_count(); i++) {
317 printer->Print(
318 "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
319 "name", ClassName(file_->enum_type(i), false));
320 }
321
322 if (HasGenericServices(file_)) {
323 for (int i = 0; i < file_->service_count(); i++) {
324 printer->Print(
325 "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
326 "name", file_->service(i)->name());
327 }
328 }
329
330 printer->Print(
331 "\n"
332 "} // namespace\n"
333 "\n");
334 }
335
336 // Define our externally-visible BuildDescriptors() function. (For the lite
337 // library, all this does is initialize default instances.)
338 GenerateBuildDescriptors(printer);
339
340 // Generate enums.
341 for (int i = 0; i < file_->enum_type_count(); i++) {
342 enum_generators_[i]->GenerateMethods(printer);
343 }
344
345 // Generate classes.
346 for (int i = 0; i < file_->message_type_count(); i++) {
347 printer->Print("\n");
348 printer->Print(kThickSeparator);
349 printer->Print("\n");
350 message_generators_[i]->GenerateClassMethods(printer);
351 }
352
353 if (HasGenericServices(file_)) {
354 // Generate services.
355 for (int i = 0; i < file_->service_count(); i++) {
356 if (i == 0) printer->Print("\n");
357 printer->Print(kThickSeparator);
358 printer->Print("\n");
359 service_generators_[i]->GenerateImplementation(printer);
360 }
361 }
362
363 // Define extensions.
364 for (int i = 0; i < file_->extension_count(); i++) {
365 extension_generators_[i]->GenerateDefinition(printer);
366 }
367
368 printer->Print(
369 "\n"
370 "// @@protoc_insertion_point(namespace_scope)\n");
371
372 GenerateNamespaceClosers(printer);
373
374 printer->Print(
375 "\n"
376 "// @@protoc_insertion_point(global_scope)\n");
377 }
378
GenerateBuildDescriptors(io::Printer * printer)379 void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
380 // AddDescriptors() is a file-level procedure which adds the encoded
381 // FileDescriptorProto for this .proto file to the global DescriptorPool
382 // for generated files (DescriptorPool::generated_pool()). It always runs
383 // at static initialization time, so all files will be registered before
384 // main() starts. This procedure also constructs default instances and
385 // registers extensions.
386 //
387 // Its sibling, AssignDescriptors(), actually pulls the compiled
388 // FileDescriptor from the DescriptorPool and uses it to populate all of
389 // the global variables which store pointers to the descriptor objects.
390 // It also constructs the reflection objects. It is called the first time
391 // anyone calls descriptor() or GetReflection() on one of the types defined
392 // in the file.
393
394 // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
395 // and we only use AddDescriptors() to allocate default instances.
396 if (HasDescriptorMethods(file_)) {
397 printer->Print(
398 "\n"
399 "void $assigndescriptorsname$() {\n",
400 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
401 printer->Indent();
402
403 // Make sure the file has found its way into the pool. If a descriptor
404 // is requested *during* static init then AddDescriptors() may not have
405 // been called yet, so we call it manually. Note that it's fine if
406 // AddDescriptors() is called multiple times.
407 printer->Print(
408 "$adddescriptorsname$();\n",
409 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
410
411 // Get the file's descriptor from the pool.
412 printer->Print(
413 "const ::google::protobuf::FileDescriptor* file =\n"
414 " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
415 " \"$filename$\");\n"
416 // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
417 // being unused when compiling an empty .proto file.
418 "GOOGLE_CHECK(file != NULL);\n",
419 "filename", file_->name());
420
421 // Go through all the stuff defined in this file and generated code to
422 // assign the global descriptor pointers based on the file descriptor.
423 for (int i = 0; i < file_->message_type_count(); i++) {
424 message_generators_[i]->GenerateDescriptorInitializer(printer, i);
425 }
426 for (int i = 0; i < file_->enum_type_count(); i++) {
427 enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
428 }
429 if (HasGenericServices(file_)) {
430 for (int i = 0; i < file_->service_count(); i++) {
431 service_generators_[i]->GenerateDescriptorInitializer(printer, i);
432 }
433 }
434
435 printer->Outdent();
436 printer->Print(
437 "}\n"
438 "\n");
439
440 // ---------------------------------------------------------------
441
442 // protobuf_AssignDescriptorsOnce(): The first time it is called, calls
443 // AssignDescriptors(). All later times, waits for the first call to
444 // complete and then returns.
445 printer->Print(
446 "namespace {\n"
447 "\n"
448 "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
449 "inline void protobuf_AssignDescriptorsOnce() {\n"
450 " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
451 " &$assigndescriptorsname$);\n"
452 "}\n"
453 "\n",
454 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
455
456 // protobuf_RegisterTypes(): Calls
457 // MessageFactory::InternalRegisterGeneratedType() for each message type.
458 printer->Print(
459 "void protobuf_RegisterTypes(const ::std::string&) {\n"
460 " protobuf_AssignDescriptorsOnce();\n");
461 printer->Indent();
462
463 for (int i = 0; i < file_->message_type_count(); i++) {
464 message_generators_[i]->GenerateTypeRegistrations(printer);
465 }
466
467 printer->Outdent();
468 printer->Print(
469 "}\n"
470 "\n"
471 "} // namespace\n");
472 }
473
474 // -----------------------------------------------------------------
475
476 // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
477 printer->Print(
478 "\n"
479 "void $shutdownfilename$() {\n",
480 "shutdownfilename", GlobalShutdownFileName(file_->name()));
481 printer->Indent();
482
483 for (int i = 0; i < file_->message_type_count(); i++) {
484 message_generators_[i]->GenerateShutdownCode(printer);
485 }
486
487 printer->Outdent();
488 printer->Print(
489 "}\n");
490
491 // -----------------------------------------------------------------
492
493 // Now generate the AddDescriptors() function.
494 printer->Print(
495 "\n"
496 "void $adddescriptorsname$() {\n"
497 // We don't need any special synchronization here because this code is
498 // called at static init time before any threads exist.
499 " static bool already_here = false;\n"
500 " if (already_here) return;\n"
501 " already_here = true;\n"
502 " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
503 "\n",
504 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
505 printer->Indent();
506
507 // Call the AddDescriptors() methods for all of our dependencies, to make
508 // sure they get added first.
509 for (int i = 0; i < file_->dependency_count(); i++) {
510 const FileDescriptor* dependency = file_->dependency(i);
511 // Print the namespace prefix for the dependency.
512 vector<string> dependency_package_parts;
513 SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
514 printer->Print("::");
515 for (int i = 0; i < dependency_package_parts.size(); i++) {
516 printer->Print("$name$::",
517 "name", dependency_package_parts[i]);
518 }
519 // Call its AddDescriptors function.
520 printer->Print(
521 "$name$();\n",
522 "name", GlobalAddDescriptorsName(dependency->name()));
523 }
524
525 if (HasDescriptorMethods(file_)) {
526 // Embed the descriptor. We simply serialize the entire FileDescriptorProto
527 // and embed it as a string literal, which is parsed and built into real
528 // descriptors at initialization time.
529 FileDescriptorProto file_proto;
530 file_->CopyTo(&file_proto);
531 string file_data;
532 file_proto.SerializeToString(&file_data);
533
534 printer->Print(
535 "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
536
537 // Only write 40 bytes per line.
538 static const int kBytesPerLine = 40;
539 for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
540 printer->Print("\n \"$data$\"",
541 "data", CEscape(file_data.substr(i, kBytesPerLine)));
542 }
543 printer->Print(
544 ", $size$);\n",
545 "size", SimpleItoa(file_data.size()));
546
547 // Call MessageFactory::InternalRegisterGeneratedFile().
548 printer->Print(
549 "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
550 " \"$filename$\", &protobuf_RegisterTypes);\n",
551 "filename", file_->name());
552 }
553
554 // Allocate and initialize default instances. This can't be done lazily
555 // since default instances are returned by simple accessors and are used with
556 // extensions. Speaking of which, we also register extensions at this time.
557 for (int i = 0; i < file_->message_type_count(); i++) {
558 message_generators_[i]->GenerateDefaultInstanceAllocator(printer);
559 }
560 for (int i = 0; i < file_->extension_count(); i++) {
561 extension_generators_[i]->GenerateRegistration(printer);
562 }
563 for (int i = 0; i < file_->message_type_count(); i++) {
564 message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
565 }
566
567 printer->Print(
568 "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n",
569 "shutdownfilename", GlobalShutdownFileName(file_->name()));
570
571 printer->Outdent();
572
573 printer->Print(
574 "}\n"
575 "\n"
576 "// Force AddDescriptors() to be called at static initialization time.\n"
577 "struct StaticDescriptorInitializer_$filename$ {\n"
578 " StaticDescriptorInitializer_$filename$() {\n"
579 " $adddescriptorsname$();\n"
580 " }\n"
581 "} static_descriptor_initializer_$filename$_;\n"
582 "\n",
583 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
584 "filename", FilenameIdentifier(file_->name()));
585 }
586
GenerateNamespaceOpeners(io::Printer * printer)587 void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
588 if (package_parts_.size() > 0) printer->Print("\n");
589
590 for (int i = 0; i < package_parts_.size(); i++) {
591 printer->Print("namespace $part$ {\n",
592 "part", package_parts_[i]);
593 }
594 }
595
GenerateNamespaceClosers(io::Printer * printer)596 void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
597 if (package_parts_.size() > 0) printer->Print("\n");
598
599 for (int i = package_parts_.size() - 1; i >= 0; i--) {
600 printer->Print("} // namespace $part$\n",
601 "part", package_parts_[i]);
602 }
603 }
604
605 } // namespace cpp
606 } // namespace compiler
607 } // namespace protobuf
608 } // namespace google
609