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 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_( 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 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" 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 282void 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 379void 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 587void 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 596void 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