blob: 22d6fdba0be13a35c6cc0913d0c60f988995b9af [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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>
kenton@google.comfccb1462009-12-18 02:11:36 +000041#include <google/protobuf/compiler/cpp/cpp_field.h>
temporal40ee5512008-07-10 02:12:20 +000042#include <google/protobuf/io/printer.h>
43#include <google/protobuf/descriptor.pb.h>
44#include <google/protobuf/stubs/strutil.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace cpp {
50
51// ===================================================================
52
53FileGenerator::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_(
kenton@google.com9b10f582008-09-30 00:09:40 +000063 new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
64 dllexport_decl_(dllexport_decl) {
temporal40ee5512008-07-10 02:12:20 +000065
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
89FileGenerator::~FileGenerator() {}
90
91void 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"
kenton@google.comfccb1462009-12-18 02:11:36 +000097 "// source: $filename$\n"
temporal40ee5512008-07-10 02:12:20 +000098 "\n"
99 "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
100 "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
101 "\n"
102 "#include <string>\n"
103 "\n",
kenton@google.comfccb1462009-12-18 02:11:36 +0000104 "filename", file_->name(),
temporal40ee5512008-07-10 02:12:20 +0000105 "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(
kenton@google.com80b1d622009-07-29 01:13:20 +0000131 "#include <google/protobuf/generated_message_util.h>\n"
temporal40ee5512008-07-10 02:12:20 +0000132 "#include <google/protobuf/repeated_field.h>\n"
133 "#include <google/protobuf/extension_set.h>\n");
134
kenton@google.com80b1d622009-07-29 01:13:20 +0000135 if (HasDescriptorMethods(file_)) {
temporal40ee5512008-07-10 02:12:20 +0000136 printer->Print(
kenton@google.com80b1d622009-07-29 01:13:20 +0000137 "#include <google/protobuf/generated_message_reflection.h>\n");
temporal40ee5512008-07-10 02:12:20 +0000138 }
139
kenton@google.comfccb1462009-12-18 02:11:36 +0000140 if (HasGenericServices(file_)) {
141 printer->Print(
142 "#include <google/protobuf/service.h>\n");
143 }
144
145
temporal40ee5512008-07-10 02:12:20 +0000146 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
kenton@google.comfccb1462009-12-18 02:11:36 +0000152 printer->Print(
153 "// @@protoc_insertion_point(includes)\n");
154
temporal40ee5512008-07-10 02:12:20 +0000155 // Open namespace.
156 GenerateNamespaceOpeners(printer);
157
kenton@google.com63e646b2009-05-06 19:27:03 +0000158 // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
159 // functions, so that we can declare them to be friends of each class.
temporal779f61c2008-08-13 03:15:00 +0000160 printer->Print(
161 "\n"
kenton@google.com9b10f582008-09-30 00:09:40 +0000162 "// Internal implementation detail -- do not call these.\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000163 "void $dllexport_decl$ $adddescriptorsname$();\n",
164 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
kenton@google.com9b10f582008-09-30 00:09:40 +0000165 "dllexport_decl", dllexport_decl_);
kenton@google.com63e646b2009-05-06 19:27:03 +0000166
kenton@google.comd37d46d2009-04-25 02:53:47 +0000167 printer->Print(
kenton@google.com63e646b2009-05-06 19:27:03 +0000168 // 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.
kenton@google.comd37d46d2009-04-25 02:53:47 +0000170 "void $assigndescriptorsname$();\n"
kenton@google.com63e646b2009-05-06 19:27:03 +0000171 "void $shutdownfilename$();\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000172 "\n",
kenton@google.com63e646b2009-05-06 19:27:03 +0000173 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
174 "shutdownfilename", GlobalShutdownFileName(file_->name()));
temporal40ee5512008-07-10 02:12:20 +0000175
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
kenton@google.comfccb1462009-12-18 02:11:36 +0000208 if (HasGenericServices(file_)) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000209 // 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);
temporal40ee5512008-07-10 02:12:20 +0000217 }
temporal40ee5512008-07-10 02:12:20 +0000218
kenton@google.com80b1d622009-07-29 01:13:20 +0000219 printer->Print("\n");
220 printer->Print(kThickSeparator);
221 printer->Print("\n");
222 }
temporal40ee5512008-07-10 02:12:20 +0000223
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
kenton@google.comfccb1462009-12-18 02:11:36 +0000242 printer->Print(
243 "\n"
244 "// @@protoc_insertion_point(namespace_scope)\n");
245
temporal40ee5512008-07-10 02:12:20 +0000246 // Close up namespace.
247 GenerateNamespaceClosers(printer);
248
kenton@google.com80b1d622009-07-29 01:13:20 +0000249 // 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"
kenton@google.comfccb1462009-12-18 02:11:36 +0000269 "#endif // SWIG\n");
kenton@google.com80b1d622009-07-29 01:13:20 +0000270 }
271
temporal40ee5512008-07-10 02:12:20 +0000272 printer->Print(
kenton@google.comfccb1462009-12-18 02:11:36 +0000273 "\n"
274 "// @@protoc_insertion_point(global_scope)\n"
275 "\n");
276
277 printer->Print(
temporal40ee5512008-07-10 02:12:20 +0000278 "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
279 "filename_identifier", filename_identifier);
280}
281
282void FileGenerator::GenerateSource(io::Printer* printer) {
283 printer->Print(
284 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
285 "\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000286
kenton@google.com80b1d622009-07-29 01:13:20 +0000287 // The generated code calls accessors that might be deprecated. We don't
288 // want the compiler to warn in generated code.
289 "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
temporal40ee5512008-07-10 02:12:20 +0000290 "#include \"$basename$.pb.h\"\n"
kenton@google.comc65c0412010-02-01 20:35:34 +0000291 "\n"
292 "#include <algorithm>\n" // for swap()
293 "\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000294 "#include <google/protobuf/stubs/once.h>\n"
temporal40ee5512008-07-10 02:12:20 +0000295 "#include <google/protobuf/io/coded_stream.h>\n"
kenton@google.com80b1d622009-07-29 01:13:20 +0000296 "#include <google/protobuf/wire_format_lite_inl.h>\n",
temporal40ee5512008-07-10 02:12:20 +0000297 "basename", StripProto(file_->name()));
298
kenton@google.com80b1d622009-07-29 01:13:20 +0000299 if (HasDescriptorMethods(file_)) {
300 printer->Print(
301 "#include <google/protobuf/descriptor.h>\n"
302 "#include <google/protobuf/reflection_ops.h>\n"
303 "#include <google/protobuf/wire_format.h>\n");
304 }
305
kenton@google.comfccb1462009-12-18 02:11:36 +0000306 printer->Print(
307 "// @@protoc_insertion_point(includes)\n");
308
temporal40ee5512008-07-10 02:12:20 +0000309 GenerateNamespaceOpeners(printer);
310
kenton@google.com80b1d622009-07-29 01:13:20 +0000311 if (HasDescriptorMethods(file_)) {
temporal40ee5512008-07-10 02:12:20 +0000312 printer->Print(
kenton@google.com80b1d622009-07-29 01:13:20 +0000313 "\n"
314 "namespace {\n"
315 "\n");
316 for (int i = 0; i < file_->message_type_count(); i++) {
317 message_generators_[i]->GenerateDescriptorDeclarations(printer);
318 }
319 for (int i = 0; i < file_->enum_type_count(); i++) {
320 printer->Print(
321 "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
322 "name", ClassName(file_->enum_type(i), false));
323 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000324
325 if (HasGenericServices(file_)) {
326 for (int i = 0; i < file_->service_count(); i++) {
327 printer->Print(
328 "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
329 "name", file_->service(i)->name());
330 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000331 }
332
temporal40ee5512008-07-10 02:12:20 +0000333 printer->Print(
kenton@google.com80b1d622009-07-29 01:13:20 +0000334 "\n"
335 "} // namespace\n"
336 "\n");
temporal40ee5512008-07-10 02:12:20 +0000337 }
338
kenton@google.com80b1d622009-07-29 01:13:20 +0000339 // Define our externally-visible BuildDescriptors() function. (For the lite
340 // library, all this does is initialize default instances.)
temporal40ee5512008-07-10 02:12:20 +0000341 GenerateBuildDescriptors(printer);
342
343 // Generate enums.
344 for (int i = 0; i < file_->enum_type_count(); i++) {
345 enum_generators_[i]->GenerateMethods(printer);
346 }
347
348 // Generate classes.
349 for (int i = 0; i < file_->message_type_count(); i++) {
350 printer->Print("\n");
351 printer->Print(kThickSeparator);
352 printer->Print("\n");
353 message_generators_[i]->GenerateClassMethods(printer);
354 }
355
kenton@google.comfccb1462009-12-18 02:11:36 +0000356 if (HasGenericServices(file_)) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000357 // Generate services.
358 for (int i = 0; i < file_->service_count(); i++) {
359 if (i == 0) printer->Print("\n");
360 printer->Print(kThickSeparator);
361 printer->Print("\n");
362 service_generators_[i]->GenerateImplementation(printer);
363 }
temporal40ee5512008-07-10 02:12:20 +0000364 }
365
366 // Define extensions.
367 for (int i = 0; i < file_->extension_count(); i++) {
368 extension_generators_[i]->GenerateDefinition(printer);
369 }
370
kenton@google.comfccb1462009-12-18 02:11:36 +0000371 printer->Print(
372 "\n"
373 "// @@protoc_insertion_point(namespace_scope)\n");
374
temporal40ee5512008-07-10 02:12:20 +0000375 GenerateNamespaceClosers(printer);
kenton@google.comfccb1462009-12-18 02:11:36 +0000376
377 printer->Print(
378 "\n"
379 "// @@protoc_insertion_point(global_scope)\n");
temporal40ee5512008-07-10 02:12:20 +0000380}
381
382void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000383 // AddDescriptors() is a file-level procedure which adds the encoded
384 // FileDescriptorProto for this .proto file to the global DescriptorPool
385 // for generated files (DescriptorPool::generated_pool()). It always runs
386 // at static initialization time, so all files will be registered before
387 // main() starts. This procedure also constructs default instances and
388 // registers extensions.
temporal779f61c2008-08-13 03:15:00 +0000389 //
kenton@google.comd37d46d2009-04-25 02:53:47 +0000390 // Its sibling, AssignDescriptors(), actually pulls the compiled
391 // FileDescriptor from the DescriptorPool and uses it to populate all of
392 // the global variables which store pointers to the descriptor objects.
393 // It also constructs the reflection objects. It is called the first time
394 // anyone calls descriptor() or GetReflection() on one of the types defined
395 // in the file.
kenton@google.com24bf56f2008-09-24 20:31:01 +0000396
kenton@google.com80b1d622009-07-29 01:13:20 +0000397 // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
398 // and we only use AddDescriptors() to allocate default instances.
399 if (HasDescriptorMethods(file_)) {
400 printer->Print(
401 "\n"
402 "void $assigndescriptorsname$() {\n",
403 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
404 printer->Indent();
kenton@google.comd37d46d2009-04-25 02:53:47 +0000405
kenton@google.com80b1d622009-07-29 01:13:20 +0000406 // Make sure the file has found its way into the pool. If a descriptor
407 // is requested *during* static init then AddDescriptors() may not have
408 // been called yet, so we call it manually. Note that it's fine if
409 // AddDescriptors() is called multiple times.
410 printer->Print(
411 "$adddescriptorsname$();\n",
412 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
kenton@google.comd37d46d2009-04-25 02:53:47 +0000413
kenton@google.com80b1d622009-07-29 01:13:20 +0000414 // Get the file's descriptor from the pool.
415 printer->Print(
416 "const ::google::protobuf::FileDescriptor* file =\n"
417 " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
418 " \"$filename$\");\n"
419 // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
420 // being unused when compiling an empty .proto file.
421 "GOOGLE_CHECK(file != NULL);\n",
422 "filename", file_->name());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000423
kenton@google.com80b1d622009-07-29 01:13:20 +0000424 // Go through all the stuff defined in this file and generated code to
425 // assign the global descriptor pointers based on the file descriptor.
426 for (int i = 0; i < file_->message_type_count(); i++) {
427 message_generators_[i]->GenerateDescriptorInitializer(printer, i);
428 }
429 for (int i = 0; i < file_->enum_type_count(); i++) {
430 enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
431 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000432 if (HasGenericServices(file_)) {
433 for (int i = 0; i < file_->service_count(); i++) {
434 service_generators_[i]->GenerateDescriptorInitializer(printer, i);
435 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000436 }
437
438 printer->Outdent();
439 printer->Print(
440 "}\n"
441 "\n");
442
443 // ---------------------------------------------------------------
444
445 // protobuf_AssignDescriptorsOnce(): The first time it is called, calls
446 // AssignDescriptors(). All later times, waits for the first call to
447 // complete and then returns.
448 printer->Print(
449 "namespace {\n"
450 "\n"
451 "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
452 "inline void protobuf_AssignDescriptorsOnce() {\n"
453 " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
454 " &$assigndescriptorsname$);\n"
455 "}\n"
456 "\n",
457 "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
458
459 // protobuf_RegisterTypes(): Calls
460 // MessageFactory::InternalRegisterGeneratedType() for each message type.
461 printer->Print(
462 "void protobuf_RegisterTypes(const ::std::string&) {\n"
463 " protobuf_AssignDescriptorsOnce();\n");
464 printer->Indent();
465
466 for (int i = 0; i < file_->message_type_count(); i++) {
467 message_generators_[i]->GenerateTypeRegistrations(printer);
468 }
469
470 printer->Outdent();
471 printer->Print(
472 "}\n"
473 "\n"
474 "} // namespace\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000475 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000476
kenton@google.comd37d46d2009-04-25 02:53:47 +0000477 // -----------------------------------------------------------------
478
kenton@google.com63e646b2009-05-06 19:27:03 +0000479 // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
480 printer->Print(
481 "\n"
482 "void $shutdownfilename$() {\n",
483 "shutdownfilename", GlobalShutdownFileName(file_->name()));
484 printer->Indent();
485
486 for (int i = 0; i < file_->message_type_count(); i++) {
487 message_generators_[i]->GenerateShutdownCode(printer);
488 }
489
490 printer->Outdent();
491 printer->Print(
492 "}\n");
493
494 // -----------------------------------------------------------------
495
kenton@google.comd37d46d2009-04-25 02:53:47 +0000496 // Now generate the AddDescriptors() function.
temporal40ee5512008-07-10 02:12:20 +0000497 printer->Print(
498 "\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000499 "void $adddescriptorsname$() {\n"
500 // We don't need any special synchronization here because this code is
501 // called at static init time before any threads exist.
temporal40ee5512008-07-10 02:12:20 +0000502 " static bool already_here = false;\n"
503 " if (already_here) return;\n"
504 " already_here = true;\n"
505 " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
temporal40ee5512008-07-10 02:12:20 +0000506 "\n",
kenton@google.comd37d46d2009-04-25 02:53:47 +0000507 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
temporal40ee5512008-07-10 02:12:20 +0000508 printer->Indent();
509
kenton@google.comd37d46d2009-04-25 02:53:47 +0000510 // Call the AddDescriptors() methods for all of our dependencies, to make
511 // sure they get added first.
temporal40ee5512008-07-10 02:12:20 +0000512 for (int i = 0; i < file_->dependency_count(); i++) {
513 const FileDescriptor* dependency = file_->dependency(i);
514 // Print the namespace prefix for the dependency.
515 vector<string> dependency_package_parts;
516 SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
517 printer->Print("::");
518 for (int i = 0; i < dependency_package_parts.size(); i++) {
519 printer->Print("$name$::",
520 "name", dependency_package_parts[i]);
521 }
kenton@google.comd37d46d2009-04-25 02:53:47 +0000522 // Call its AddDescriptors function.
temporal40ee5512008-07-10 02:12:20 +0000523 printer->Print(
524 "$name$();\n",
kenton@google.comd37d46d2009-04-25 02:53:47 +0000525 "name", GlobalAddDescriptorsName(dependency->name()));
temporal40ee5512008-07-10 02:12:20 +0000526 }
527
kenton@google.com80b1d622009-07-29 01:13:20 +0000528 if (HasDescriptorMethods(file_)) {
529 // Embed the descriptor. We simply serialize the entire FileDescriptorProto
530 // and embed it as a string literal, which is parsed and built into real
531 // descriptors at initialization time.
532 FileDescriptorProto file_proto;
533 file_->CopyTo(&file_proto);
534 string file_data;
535 file_proto.SerializeToString(&file_data);
temporal40ee5512008-07-10 02:12:20 +0000536
kenton@google.com80b1d622009-07-29 01:13:20 +0000537 printer->Print(
538 "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
temporal40ee5512008-07-10 02:12:20 +0000539
kenton@google.com80b1d622009-07-29 01:13:20 +0000540 // Only write 40 bytes per line.
541 static const int kBytesPerLine = 40;
542 for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
543 printer->Print("\n \"$data$\"",
544 "data", CEscape(file_data.substr(i, kBytesPerLine)));
545 }
546 printer->Print(
547 ", $size$);\n",
548 "size", SimpleItoa(file_data.size()));
549
550 // Call MessageFactory::InternalRegisterGeneratedFile().
551 printer->Print(
552 "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
553 " \"$filename$\", &protobuf_RegisterTypes);\n",
554 "filename", file_->name());
temporal40ee5512008-07-10 02:12:20 +0000555 }
kenton@google.comd37d46d2009-04-25 02:53:47 +0000556
557 // Allocate and initialize default instances. This can't be done lazily
558 // since default instances are returned by simple accessors and are used with
559 // extensions. Speaking of which, we also register extensions at this time.
560 for (int i = 0; i < file_->message_type_count(); i++) {
561 message_generators_[i]->GenerateDefaultInstanceAllocator(printer);
562 }
563 for (int i = 0; i < file_->extension_count(); i++) {
564 extension_generators_[i]->GenerateRegistration(printer);
565 }
566 for (int i = 0; i < file_->message_type_count(); i++) {
567 message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
568 }
temporal40ee5512008-07-10 02:12:20 +0000569
kenton@google.com63e646b2009-05-06 19:27:03 +0000570 printer->Print(
571 "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n",
572 "shutdownfilename", GlobalShutdownFileName(file_->name()));
573
temporal40ee5512008-07-10 02:12:20 +0000574 printer->Outdent();
kenton@google.com24bf56f2008-09-24 20:31:01 +0000575
temporal40ee5512008-07-10 02:12:20 +0000576 printer->Print(
577 "}\n"
578 "\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000579 "// Force AddDescriptors() to be called at static initialization time.\n"
temporal40ee5512008-07-10 02:12:20 +0000580 "struct StaticDescriptorInitializer_$filename$ {\n"
581 " StaticDescriptorInitializer_$filename$() {\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000582 " $adddescriptorsname$();\n"
temporal40ee5512008-07-10 02:12:20 +0000583 " }\n"
584 "} static_descriptor_initializer_$filename$_;\n"
585 "\n",
kenton@google.comd37d46d2009-04-25 02:53:47 +0000586 "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
temporal40ee5512008-07-10 02:12:20 +0000587 "filename", FilenameIdentifier(file_->name()));
588}
589
590void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
591 if (package_parts_.size() > 0) printer->Print("\n");
592
593 for (int i = 0; i < package_parts_.size(); i++) {
594 printer->Print("namespace $part$ {\n",
595 "part", package_parts_[i]);
596 }
597}
598
599void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
600 if (package_parts_.size() > 0) printer->Print("\n");
601
602 for (int i = package_parts_.size() - 1; i >= 0; i--) {
603 printer->Print("} // namespace $part$\n",
604 "part", package_parts_[i]);
605 }
606}
607
608} // namespace cpp
609} // namespace compiler
610} // namespace protobuf
611} // namespace google