• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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