1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 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 37#include <iostream> 38#include <map> 39#include <memory> 40#include <set> 41#include <unordered_set> 42#include <vector> 43 44#include <google/protobuf/compiler/cpp/cpp_enum.h> 45#include <google/protobuf/compiler/cpp/cpp_extension.h> 46#include <google/protobuf/compiler/cpp/cpp_field.h> 47#include <google/protobuf/compiler/cpp/cpp_helpers.h> 48#include <google/protobuf/compiler/cpp/cpp_message.h> 49#include <google/protobuf/compiler/cpp/cpp_service.h> 50#include <google/protobuf/compiler/scc.h> 51#include <google/protobuf/descriptor.pb.h> 52#include <google/protobuf/io/printer.h> 53#include <google/protobuf/stubs/strutil.h> 54 55#include <google/protobuf/port_def.inc> 56 57namespace google { 58namespace protobuf { 59namespace compiler { 60namespace cpp { 61 62namespace { 63 64// When we forward-declare things, we want to create a sorted order so our 65// output is deterministic and minimizes namespace changes. 66template <class T> 67std::string GetSortKey(const T& val) { 68 return val.full_name(); 69} 70 71template <> 72std::string GetSortKey<FileDescriptor>(const FileDescriptor& val) { 73 return val.name(); 74} 75 76template <> 77std::string GetSortKey<SCC>(const SCC& val) { 78 return val.GetRepresentative()->full_name(); 79} 80 81template <class T> 82bool CompareSortKeys(const T* a, const T* b) { 83 return GetSortKey(*a) < GetSortKey(*b); 84} 85 86template <class T> 87std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) { 88 std::vector<const T*> sorted(vals.begin(), vals.end()); 89 std::sort(sorted.begin(), sorted.end(), CompareSortKeys<T>); 90 return sorted; 91} 92 93} // namespace 94 95FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) 96 : file_(file), options_(options), scc_analyzer_(options) { 97 // These variables are the same on a file level 98 SetCommonVars(options, &variables_); 99 variables_["dllexport_decl"] = options.dllexport_decl; 100 variables_["tablename"] = UniqueName("TableStruct", file_, options_); 101 variables_["file_level_metadata"] = 102 UniqueName("file_level_metadata", file_, options_); 103 variables_["desc_table"] = DescriptorTableName(file_, options_); 104 variables_["file_level_enum_descriptors"] = 105 UniqueName("file_level_enum_descriptors", file_, options_); 106 variables_["file_level_service_descriptors"] = 107 UniqueName("file_level_service_descriptors", file_, options_); 108 variables_["filename"] = file_->name(); 109 variables_["package_ns"] = Namespace(file_, options); 110 111 std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); 112 for (int i = 0; i < msgs.size(); i++) { 113 // Deleted in destructor 114 MessageGenerator* msg_gen = 115 new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_); 116 message_generators_.emplace_back(msg_gen); 117 msg_gen->AddGenerators(&enum_generators_, &extension_generators_); 118 } 119 120 for (int i = 0; i < file->enum_type_count(); i++) { 121 enum_generators_.emplace_back( 122 new EnumGenerator(file->enum_type(i), variables_, options)); 123 } 124 125 for (int i = 0; i < file->service_count(); i++) { 126 service_generators_.emplace_back( 127 new ServiceGenerator(file->service(i), variables_, options)); 128 } 129 if (HasGenericServices(file_, options_)) { 130 for (int i = 0; i < service_generators_.size(); i++) { 131 service_generators_[i]->index_in_metadata_ = i; 132 } 133 } 134 for (int i = 0; i < file->extension_count(); i++) { 135 extension_generators_.emplace_back( 136 new ExtensionGenerator(file->extension(i), options)); 137 } 138 for (int i = 0; i < file->weak_dependency_count(); ++i) { 139 weak_deps_.insert(file->weak_dependency(i)); 140 } 141 for (int i = 0; i < message_generators_.size(); i++) { 142 if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { 143 sccs_.push_back(GetSCC(message_generators_[i]->descriptor_)); 144 } 145 } 146 147 std::sort(sccs_.begin(), sccs_.end(), CompareSortKeys<SCC>); 148} 149 150FileGenerator::~FileGenerator() = default; 151 152void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { 153 Formatter format(printer, variables_); 154 // Only do this for protobuf's own types. There are some google3 protos using 155 // macros as field names and the generated code compiles after the macro 156 // expansion. Undefing these macros actually breaks such code. 157 if (file_->name() != "net/proto2/compiler/proto/plugin.proto" && 158 file_->name() != "google/protobuf/compiler/plugin.proto") { 159 return; 160 } 161 std::vector<std::string> names_to_undef; 162 std::vector<const FieldDescriptor*> fields; 163 ListAllFields(file_, &fields); 164 for (int i = 0; i < fields.size(); i++) { 165 const std::string& name = fields[i]->name(); 166 static const char* kMacroNames[] = {"major", "minor"}; 167 for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) { 168 if (name == kMacroNames[i]) { 169 names_to_undef.push_back(name); 170 break; 171 } 172 } 173 } 174 for (int i = 0; i < names_to_undef.size(); ++i) { 175 format( 176 "#ifdef $1$\n" 177 "#undef $1$\n" 178 "#endif\n", 179 names_to_undef[i]); 180 } 181} 182 183void FileGenerator::GenerateHeader(io::Printer* printer) { 184 Formatter format(printer, variables_); 185 186 // port_def.inc must be included after all other includes. 187 IncludeFile("net/proto2/public/port_def.inc", printer); 188 format("#define $1$$ dllexport_decl$\n", FileDllExport(file_, options_)); 189 GenerateMacroUndefs(printer); 190 191 // For Any support with lite protos, we need to friend AnyMetadata, so we 192 // forward-declare it here. 193 format( 194 "PROTOBUF_NAMESPACE_OPEN\n" 195 "namespace internal {\n" 196 "class AnyMetadata;\n" 197 "} // namespace internal\n" 198 "PROTOBUF_NAMESPACE_CLOSE\n"); 199 200 GenerateGlobalStateFunctionDeclarations(printer); 201 202 GenerateForwardDeclarations(printer); 203 204 { 205 NamespaceOpener ns(Namespace(file_, options_), format); 206 207 format("\n"); 208 209 GenerateEnumDefinitions(printer); 210 211 format(kThickSeparator); 212 format("\n"); 213 214 GenerateMessageDefinitions(printer); 215 216 format("\n"); 217 format(kThickSeparator); 218 format("\n"); 219 220 GenerateServiceDefinitions(printer); 221 222 GenerateExtensionIdentifiers(printer); 223 224 format("\n"); 225 format(kThickSeparator); 226 format("\n"); 227 228 GenerateInlineFunctionDefinitions(printer); 229 230 format( 231 "\n" 232 "// @@protoc_insertion_point(namespace_scope)\n" 233 "\n"); 234 } 235 236 // We need to specialize some templates in the ::google::protobuf namespace: 237 GenerateProto2NamespaceEnumSpecializations(printer); 238 239 format( 240 "\n" 241 "// @@protoc_insertion_point(global_scope)\n" 242 "\n"); 243 IncludeFile("net/proto2/public/port_undef.inc", printer); 244} 245 246void FileGenerator::GenerateProtoHeader(io::Printer* printer, 247 const std::string& info_path) { 248 Formatter format(printer, variables_); 249 if (!options_.proto_h) { 250 return; 251 } 252 253 GenerateTopHeaderGuard(printer, false); 254 255 if (!options_.opensource_runtime) { 256 format( 257 "#ifdef SWIG\n" 258 "#error \"Do not SWIG-wrap protobufs.\"\n" 259 "#endif // SWIG\n" 260 "\n"); 261 } 262 263 if (IsBootstrapProto(options_, file_)) { 264 format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n", 265 StripProto(file_->name())); 266 } 267 268 GenerateLibraryIncludes(printer); 269 270 for (int i = 0; i < file_->public_dependency_count(); i++) { 271 const FileDescriptor* dep = file_->public_dependency(i); 272 format("#include \"$1$.proto.h\"\n", StripProto(dep->name())); 273 } 274 275 format("// @@protoc_insertion_point(includes)\n"); 276 277 GenerateMetadataPragma(printer, info_path); 278 279 GenerateHeader(printer); 280 281 GenerateBottomHeaderGuard(printer, false); 282} 283 284void FileGenerator::GeneratePBHeader(io::Printer* printer, 285 const std::string& info_path) { 286 Formatter format(printer, variables_); 287 GenerateTopHeaderGuard(printer, true); 288 289 if (options_.proto_h) { 290 std::string target_basename = StripProto(file_->name()); 291 if (!options_.opensource_runtime) { 292 GetBootstrapBasename(options_, target_basename, &target_basename); 293 } 294 format("#include \"$1$.proto.h\" // IWYU pragma: export\n", 295 target_basename); 296 } else { 297 GenerateLibraryIncludes(printer); 298 } 299 300 if (options_.transitive_pb_h) { 301 GenerateDependencyIncludes(printer); 302 } 303 304 // This is unfortunately necessary for some plugins. I don't see why we 305 // need two of the same insertion points. 306 // TODO(gerbens) remove this. 307 format("// @@protoc_insertion_point(includes)\n"); 308 309 GenerateMetadataPragma(printer, info_path); 310 311 if (!options_.proto_h) { 312 GenerateHeader(printer); 313 } else { 314 { 315 NamespaceOpener ns(Namespace(file_, options_), format); 316 format( 317 "\n" 318 "// @@protoc_insertion_point(namespace_scope)\n"); 319 } 320 format( 321 "\n" 322 "// @@protoc_insertion_point(global_scope)\n" 323 "\n"); 324 } 325 326 GenerateBottomHeaderGuard(printer, true); 327} 328 329void FileGenerator::DoIncludeFile(const std::string& google3_name, 330 bool do_export, io::Printer* printer) { 331 Formatter format(printer, variables_); 332 const std::string prefix = "net/proto2/"; 333 GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name; 334 335 if (options_.opensource_runtime) { 336 std::string path = google3_name.substr(prefix.size()); 337 338 path = StringReplace(path, "internal/", "", false); 339 path = StringReplace(path, "proto/", "", false); 340 path = StringReplace(path, "public/", "", false); 341 if (options_.runtime_include_base.empty()) { 342 format("#include <google/protobuf/$1$>", path); 343 } else { 344 format("#include \"$1$google/protobuf/$2$\"", 345 options_.runtime_include_base, path); 346 } 347 } else { 348 format("#include \"$1$\"", google3_name); 349 } 350 351 if (do_export) { 352 format(" // IWYU pragma: export"); 353 } 354 355 format("\n"); 356} 357 358std::string FileGenerator::CreateHeaderInclude(const std::string& basename, 359 const FileDescriptor* file) { 360 bool use_system_include = false; 361 std::string name = basename; 362 363 if (options_.opensource_runtime) { 364 if (IsWellKnownMessage(file)) { 365 if (options_.runtime_include_base.empty()) { 366 use_system_include = true; 367 } else { 368 name = options_.runtime_include_base + basename; 369 } 370 } 371 } 372 373 std::string left = "\""; 374 std::string right = "\""; 375 if (use_system_include) { 376 left = "<"; 377 right = ">"; 378 } 379 return left + name + right; 380} 381 382void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { 383 Formatter format(printer, variables_); 384 std::string target_basename = StripProto(file_->name()); 385 if (!options_.opensource_runtime) { 386 GetBootstrapBasename(options_, target_basename, &target_basename); 387 } 388 target_basename += options_.proto_h ? ".proto.h" : ".pb.h"; 389 format( 390 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" 391 "// source: $filename$\n" 392 "\n" 393 "#include $1$\n" 394 "\n" 395 "#include <algorithm>\n" // for swap() 396 "\n", 397 CreateHeaderInclude(target_basename, file_)); 398 399 IncludeFile("net/proto2/io/public/coded_stream.h", printer); 400 // TODO(gerbens) This is to include parse_context.h, we need a better way 401 IncludeFile("net/proto2/public/extension_set.h", printer); 402 IncludeFile("net/proto2/public/wire_format_lite.h", printer); 403 404 // Unknown fields implementation in lite mode uses StringOutputStream 405 if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { 406 IncludeFile("net/proto2/io/public/zero_copy_stream_impl_lite.h", printer); 407 } 408 409 if (HasDescriptorMethods(file_, options_)) { 410 IncludeFile("net/proto2/public/descriptor.h", printer); 411 IncludeFile("net/proto2/public/generated_message_reflection.h", printer); 412 IncludeFile("net/proto2/public/reflection_ops.h", printer); 413 IncludeFile("net/proto2/public/wire_format.h", printer); 414 } 415 416 if (options_.proto_h) { 417 // Use the smaller .proto.h files. 418 for (int i = 0; i < file_->dependency_count(); i++) { 419 const FileDescriptor* dep = file_->dependency(i); 420 // Do not import weak deps. 421 if (!options_.opensource_runtime && IsDepWeak(dep)) continue; 422 std::string basename = StripProto(dep->name()); 423 if (IsBootstrapProto(options_, file_)) { 424 GetBootstrapBasename(options_, basename, &basename); 425 } 426 format("#include \"$1$.proto.h\"\n", basename); 427 } 428 } 429 430 format("// @@protoc_insertion_point(includes)\n"); 431 IncludeFile("net/proto2/public/port_def.inc", printer); 432} 433 434void FileGenerator::GenerateSourceDefaultInstance(int idx, 435 io::Printer* printer) { 436 Formatter format(printer, variables_); 437 MessageGenerator* generator = message_generators_[idx].get(); 438 format( 439 "class $1$ {\n" 440 " public:\n" 441 " ::$proto_ns$::internal::ExplicitlyConstructed<$2$> _instance;\n", 442 DefaultInstanceType(generator->descriptor_, options_), 443 generator->classname_); 444 format.Indent(); 445 generator->GenerateExtraDefaultFields(printer); 446 format.Outdent(); 447 format("} $1$;\n", DefaultInstanceName(generator->descriptor_, options_)); 448 if (options_.lite_implicit_weak_fields) { 449 format("$1$DefaultTypeInternal* $2$ = &$3$;\n", generator->classname_, 450 DefaultInstancePtr(generator->descriptor_, options_), 451 DefaultInstanceName(generator->descriptor_, options_)); 452 } 453} 454 455// A list of things defined in one .pb.cc file that we need to reference from 456// another .pb.cc file. 457struct FileGenerator::CrossFileReferences { 458 // Populated if we are referencing from messages or files. 459 std::unordered_set<const SCC*> strong_sccs; 460 std::unordered_set<const SCC*> weak_sccs; 461 std::unordered_set<const Descriptor*> weak_default_instances; 462 463 // Only if we are referencing from files. 464 std::unordered_set<const FileDescriptor*> strong_reflection_files; 465 std::unordered_set<const FileDescriptor*> weak_reflection_files; 466}; 467 468void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field, 469 CrossFileReferences* refs) { 470 const Descriptor* msg = field->message_type(); 471 if (msg == nullptr) return; 472 const SCC* scc = GetSCC(msg); 473 474 if (IsImplicitWeakField(field, options_, &scc_analyzer_) || 475 IsWeak(field, options_)) { 476 refs->weak_sccs.insert(scc); 477 refs->weak_default_instances.insert(msg); 478 } else { 479 refs->strong_sccs.insert(scc); 480 // We don't need to declare default instances, because it is declared in the 481 // .proto.h file we imported. 482 } 483} 484 485void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file, 486 CrossFileReferences* refs) { 487 ForEachField(file, [this, refs](const FieldDescriptor* field) { 488 GetCrossFileReferencesForField(field, refs); 489 }); 490 491 if (!HasDescriptorMethods(file, options_)) return; 492 493 for (int i = 0; i < file->dependency_count(); i++) { 494 const FileDescriptor* dep = file->dependency(i); 495 if (IsDepWeak(dep)) { 496 refs->weak_reflection_files.insert(dep); 497 } else { 498 refs->strong_reflection_files.insert(dep); 499 } 500 } 501} 502 503// Generates references to variables defined in other files. 504void FileGenerator::GenerateInternalForwardDeclarations( 505 const CrossFileReferences& refs, io::Printer* printer) { 506 Formatter format(printer, variables_); 507 508 for (auto scc : Sorted(refs.strong_sccs)) { 509 format("extern $1$ ::$proto_ns$::internal::SCCInfo<$2$> $3$;\n", 510 FileDllExport(scc->GetFile(), options_), scc->children.size(), 511 SccInfoSymbol(scc, options_)); 512 } 513 514 for (auto scc : Sorted(refs.weak_sccs)) { 515 // We do things a little bit differently for proto1-style weak fields versus 516 // lite implicit weak fields, even though they are trying to accomplish 517 // similar things. We need to support implicit weak fields on iOS, and the 518 // Apple linker only supports weak definitions, not weak declarations. For 519 // that reason we need a pointer type which we can weakly define to be null. 520 // However, code size considerations prevent us from using the same approach 521 // for proto1-style weak fields. 522 if (options_.lite_implicit_weak_fields) { 523 format("extern ::$proto_ns$::internal::SCCInfo<$1$> $2$;\n", 524 scc->children.size(), SccInfoSymbol(scc, options_)); 525 format( 526 "__attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$>*\n" 527 " $2$ = nullptr;\n", 528 scc->children.size(), SccInfoPtrSymbol(scc, options_)); 529 } else { 530 format( 531 "extern __attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$> " 532 "$2$;\n", 533 scc->children.size(), SccInfoSymbol(scc, options_)); 534 } 535 } 536 537 { 538 NamespaceOpener ns(format); 539 for (auto instance : Sorted(refs.weak_default_instances)) { 540 ns.ChangeTo(Namespace(instance, options_)); 541 if (options_.lite_implicit_weak_fields) { 542 format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_), 543 DefaultInstanceName(instance, options_)); 544 format("__attribute__((weak)) $1$* $2$ = nullptr;\n", 545 DefaultInstanceType(instance, options_), 546 DefaultInstancePtr(instance, options_)); 547 } else { 548 format("extern __attribute__((weak)) $1$ $2$;\n", 549 DefaultInstanceType(instance, options_), 550 DefaultInstanceName(instance, options_)); 551 } 552 } 553 } 554 555 for (auto file : Sorted(refs.weak_reflection_files)) { 556 format( 557 "extern __attribute__((weak)) const " 558 "::$proto_ns$::internal::DescriptorTable $1$;\n", 559 DescriptorTableName(file, options_)); 560 } 561} 562 563void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { 564 Formatter format(printer, variables_); 565 GenerateSourceIncludes(printer); 566 567 // Generate weak declarations. We do this for the whole strongly-connected 568 // component (SCC), because we have a single InitDefaults* function for the 569 // SCC. 570 CrossFileReferences refs; 571 for (const Descriptor* message : 572 scc_analyzer_.GetSCC(message_generators_[idx]->descriptor_) 573 ->descriptors) { 574 ForEachField(message, [this, &refs](const FieldDescriptor* field) { 575 GetCrossFileReferencesForField(field, &refs); 576 }); 577 } 578 GenerateInternalForwardDeclarations(refs, printer); 579 580 if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { 581 GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), refs, 582 printer); 583 } 584 585 { // package namespace 586 NamespaceOpener ns(Namespace(file_, options_), format); 587 588 // Define default instances 589 GenerateSourceDefaultInstance(idx, printer); 590 591 // Generate classes. 592 format("\n"); 593 message_generators_[idx]->GenerateClassMethods(printer); 594 595 format( 596 "\n" 597 "// @@protoc_insertion_point(namespace_scope)\n"); 598 } // end package namespace 599 600 { 601 NamespaceOpener proto_ns(ProtobufNamespace(options_), format); 602 message_generators_[idx]->GenerateSourceInProto2Namespace(printer); 603 } 604 605 format( 606 "\n" 607 "// @@protoc_insertion_point(global_scope)\n"); 608} 609 610void FileGenerator::GenerateGlobalSource(io::Printer* printer) { 611 Formatter format(printer, variables_); 612 GenerateSourceIncludes(printer); 613 614 { 615 GenerateTables(printer); 616 617 // Define the code to initialize reflection. This code uses a global 618 // constructor to register reflection data with the runtime pre-main. 619 if (HasDescriptorMethods(file_, options_)) { 620 GenerateReflectionInitializationCode(printer); 621 } 622 } 623 624 NamespaceOpener ns(Namespace(file_, options_), format); 625 626 // Generate enums. 627 for (int i = 0; i < enum_generators_.size(); i++) { 628 enum_generators_[i]->GenerateMethods(i, printer); 629 } 630 631 // Define extensions. 632 for (int i = 0; i < extension_generators_.size(); i++) { 633 extension_generators_[i]->GenerateDefinition(printer); 634 } 635 636 if (HasGenericServices(file_, options_)) { 637 // Generate services. 638 for (int i = 0; i < service_generators_.size(); i++) { 639 if (i == 0) format("\n"); 640 format(kThickSeparator); 641 format("\n"); 642 service_generators_[i]->GenerateImplementation(printer); 643 } 644 } 645} 646 647void FileGenerator::GenerateSource(io::Printer* printer) { 648 Formatter format(printer, variables_); 649 GenerateSourceIncludes(printer); 650 CrossFileReferences refs; 651 GetCrossFileReferencesForFile(file_, &refs); 652 GenerateInternalForwardDeclarations(refs, printer); 653 654 { 655 NamespaceOpener ns(Namespace(file_, options_), format); 656 657 // Define default instances 658 for (int i = 0; i < message_generators_.size(); i++) { 659 GenerateSourceDefaultInstance(i, printer); 660 } 661 } 662 663 { 664 GenerateTables(printer); 665 666 // Now generate the InitDefaults for each SCC. 667 for (auto scc : sccs_) { 668 GenerateInitForSCC(scc, refs, printer); 669 } 670 671 if (HasDescriptorMethods(file_, options_)) { 672 // Define the code to initialize reflection. This code uses a global 673 // constructor to register reflection data with the runtime pre-main. 674 GenerateReflectionInitializationCode(printer); 675 } 676 } 677 678 { 679 NamespaceOpener ns(Namespace(file_, options_), format); 680 681 // Actually implement the protos 682 683 // Generate enums. 684 for (int i = 0; i < enum_generators_.size(); i++) { 685 enum_generators_[i]->GenerateMethods(i, printer); 686 } 687 688 // Generate classes. 689 for (int i = 0; i < message_generators_.size(); i++) { 690 format("\n"); 691 format(kThickSeparator); 692 format("\n"); 693 message_generators_[i]->GenerateClassMethods(printer); 694 } 695 696 if (HasGenericServices(file_, options_)) { 697 // Generate services. 698 for (int i = 0; i < service_generators_.size(); i++) { 699 if (i == 0) format("\n"); 700 format(kThickSeparator); 701 format("\n"); 702 service_generators_[i]->GenerateImplementation(printer); 703 } 704 } 705 706 // Define extensions. 707 for (int i = 0; i < extension_generators_.size(); i++) { 708 extension_generators_[i]->GenerateDefinition(printer); 709 } 710 711 format( 712 "\n" 713 "// @@protoc_insertion_point(namespace_scope)\n"); 714 } 715 716 { 717 NamespaceOpener proto_ns(ProtobufNamespace(options_), format); 718 for (int i = 0; i < message_generators_.size(); i++) { 719 message_generators_[i]->GenerateSourceInProto2Namespace(printer); 720 } 721 } 722 723 format( 724 "\n" 725 "// @@protoc_insertion_point(global_scope)\n"); 726 727 IncludeFile("net/proto2/public/port_undef.inc", printer); 728} 729 730void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { 731 Formatter format(printer, variables_); 732 733 if (!message_generators_.empty()) { 734 format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n", 735 message_generators_.size()); 736 } else { 737 format( 738 "static " 739 "constexpr ::$proto_ns$::Metadata* $file_level_metadata$ = nullptr;\n"); 740 } 741 if (!enum_generators_.empty()) { 742 format( 743 "static " 744 "const ::$proto_ns$::EnumDescriptor* " 745 "$file_level_enum_descriptors$[$1$];\n", 746 enum_generators_.size()); 747 } else { 748 format( 749 "static " 750 "constexpr ::$proto_ns$::EnumDescriptor const** " 751 "$file_level_enum_descriptors$ = nullptr;\n"); 752 } 753 if (HasGenericServices(file_, options_) && file_->service_count() > 0) { 754 format( 755 "static " 756 "const ::$proto_ns$::ServiceDescriptor* " 757 "$file_level_service_descriptors$[$1$];\n", 758 file_->service_count()); 759 } else { 760 format( 761 "static " 762 "constexpr ::$proto_ns$::ServiceDescriptor const** " 763 "$file_level_service_descriptors$ = nullptr;\n"); 764 } 765 766 if (!message_generators_.empty()) { 767 format( 768 "\n" 769 "const $uint32$ $tablename$::offsets[] " 770 "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); 771 format.Indent(); 772 std::vector<std::pair<size_t, size_t> > pairs; 773 pairs.reserve(message_generators_.size()); 774 for (int i = 0; i < message_generators_.size(); i++) { 775 pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); 776 } 777 format.Outdent(); 778 format( 779 "};\n" 780 "static const ::$proto_ns$::internal::MigrationSchema schemas[] " 781 "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); 782 format.Indent(); 783 { 784 int offset = 0; 785 for (int i = 0; i < message_generators_.size(); i++) { 786 message_generators_[i]->GenerateSchema(printer, offset, 787 pairs[i].second); 788 offset += pairs[i].first; 789 } 790 } 791 format.Outdent(); 792 format( 793 "};\n" 794 "\nstatic " 795 "::$proto_ns$::Message const * const file_default_instances[] = {\n"); 796 format.Indent(); 797 for (int i = 0; i < message_generators_.size(); i++) { 798 const Descriptor* descriptor = message_generators_[i]->descriptor_; 799 format( 800 "reinterpret_cast<const " 801 "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n", 802 Namespace(descriptor, options_), // 1 803 ClassName(descriptor)); // 2 804 } 805 format.Outdent(); 806 format( 807 "};\n" 808 "\n"); 809 } else { 810 // we still need these symbols to exist 811 format( 812 // MSVC doesn't like empty arrays, so we add a dummy. 813 "const $uint32$ $tablename$::offsets[1] = {};\n" 814 "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = " 815 "nullptr;" 816 "\n" 817 "static constexpr ::$proto_ns$::Message* const* " 818 "file_default_instances = nullptr;\n" 819 "\n"); 820 } 821 822 // --------------------------------------------------------------- 823 824 // Embed the descriptor. We simply serialize the entire 825 // FileDescriptorProto/ and embed it as a string literal, which is parsed and 826 // built into real descriptors at initialization time. 827 const std::string protodef_name = 828 UniqueName("descriptor_table_protodef", file_, options_); 829 format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n", 830 protodef_name); 831 format.Indent(); 832 FileDescriptorProto file_proto; 833 file_->CopyTo(&file_proto); 834 std::string file_data; 835 file_proto.SerializeToString(&file_data); 836 837 { 838 if (file_data.size() > 65535) { 839 // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 840 // 65535 bytes in length". Declare a static array of chars rather than 841 // use a string literal. Only write 25 bytes per line. 842 static const int kBytesPerLine = 25; 843 format("{ "); 844 for (int i = 0; i < file_data.size();) { 845 for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { 846 format("'$1$', ", CEscape(file_data.substr(i, 1))); 847 } 848 format("\n"); 849 } 850 format("'\\0' }"); // null-terminate 851 } else { 852 // Only write 40 bytes per line. 853 static const int kBytesPerLine = 40; 854 for (int i = 0; i < file_data.size(); i += kBytesPerLine) { 855 format( 856 "\"$1$\"\n", 857 EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); 858 } 859 } 860 format(";\n"); 861 } 862 format.Outdent(); 863 864 CrossFileReferences refs; 865 GetCrossFileReferencesForFile(file_, &refs); 866 int num_deps = 867 refs.strong_reflection_files.size() + refs.weak_reflection_files.size(); 868 869 // Build array of DescriptorTable deps. 870 format( 871 "static const ::$proto_ns$::internal::DescriptorTable*const " 872 "$desc_table$_deps[$1$] = {\n", 873 std::max(num_deps, 1)); 874 875 for (auto dep : Sorted(refs.strong_reflection_files)) { 876 format(" &::$1$,\n", DescriptorTableName(dep, options_)); 877 } 878 for (auto dep : Sorted(refs.weak_reflection_files)) { 879 format(" &::$1$,\n", DescriptorTableName(dep, options_)); 880 } 881 882 format("};\n"); 883 884 // Build array of SCCs from this file. 885 format( 886 "static ::$proto_ns$::internal::SCCInfoBase*const " 887 "$desc_table$_sccs[$1$] = {\n", 888 std::max<int>(sccs_.size(), 1)); 889 890 for (auto scc : sccs_) { 891 format(" &$1$.base,\n", SccInfoSymbol(scc, options_)); 892 } 893 894 format("};\n"); 895 896 // The DescriptorTable itself. 897 // Should be "bool eager = NeedsEagerDescriptorAssignment(file_, options_);" 898 // however this might cause a tsan failure in superroot b/148382879, 899 // so disable for now. 900 bool eager = false; 901 format( 902 "static ::$proto_ns$::internal::once_flag $desc_table$_once;\n" 903 "const ::$proto_ns$::internal::DescriptorTable $desc_table$ = {\n" 904 " false, $1$, $2$, \"$filename$\", $3$,\n" 905 " &$desc_table$_once, $desc_table$_sccs, $desc_table$_deps, $4$, $5$,\n" 906 " schemas, file_default_instances, $tablename$::offsets,\n" 907 " $file_level_metadata$, $6$, $file_level_enum_descriptors$, " 908 "$file_level_service_descriptors$,\n" 909 "};\n\n", 910 eager ? "true" : "false", protodef_name, file_data.size(), sccs_.size(), 911 num_deps, message_generators_.size()); 912 913 // For descriptor.proto we want to avoid doing any dynamic initialization, 914 // because in some situations that would otherwise pull in a lot of 915 // unnecessary code that can't be stripped by --gc-sections. Descriptor 916 // initialization will still be performed lazily when it's needed. 917 if (file_->name() != "net/proto2/proto/descriptor.proto") { 918 format( 919 "// Force running AddDescriptors() at dynamic initialization time.\n" 920 "static bool $1$ = (static_cast<void>(" 921 "::$proto_ns$::internal::AddDescriptors(&$desc_table$)), true);\n", 922 UniqueName("dynamic_init_dummy", file_, options_)); 923 } 924} 925 926void FileGenerator::GenerateInitForSCC(const SCC* scc, 927 const CrossFileReferences& refs, 928 io::Printer* printer) { 929 Formatter format(printer, variables_); 930 // We use static and not anonymous namespace because symbol names are 931 // substantially shorter. 932 format("static void InitDefaults$1$() {\n", SccInfoSymbol(scc, options_)); 933 934 if (options_.opensource_runtime) { 935 format(" GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n"); 936 } 937 938 format.Indent(); 939 940 // First construct all the necessary default instances. 941 for (int i = 0; i < message_generators_.size(); i++) { 942 if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { 943 continue; 944 } 945 // TODO(gerbens) This requires this function to be friend. Remove 946 // the need for this. 947 message_generators_[i]->GenerateFieldDefaultInstances(printer); 948 format( 949 "{\n" 950 " void* ptr = &$1$;\n" 951 " new (ptr) $2$();\n", 952 QualifiedDefaultInstanceName(message_generators_[i]->descriptor_, 953 options_), 954 QualifiedClassName(message_generators_[i]->descriptor_, options_)); 955 if (options_.opensource_runtime && 956 !IsMapEntryMessage(message_generators_[i]->descriptor_)) { 957 format( 958 " " 959 "::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr);" 960 "\n"); 961 } 962 format("}\n"); 963 } 964 965 // TODO(gerbens) make default instances be the same as normal instances. 966 // Default instances differ from normal instances because they have cross 967 // linked message fields. 968 for (int i = 0; i < message_generators_.size(); i++) { 969 if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { 970 continue; 971 } 972 format("$1$::InitAsDefaultInstance();\n", 973 QualifiedClassName(message_generators_[i]->descriptor_, options_)); 974 } 975 format.Outdent(); 976 format("}\n\n"); 977 978 // If we are using lite implicit weak fields then we need to distinguish 979 // between regular SCC dependencies and ones that we need to reference weakly 980 // through an extra pointer indirection. 981 std::vector<const SCC*> regular_sccs; 982 std::vector<const SCC*> implicit_weak_sccs; 983 for (const SCC* child : scc->children) { 984 if (options_.lite_implicit_weak_fields && 985 refs.weak_sccs.find(child) != refs.weak_sccs.end()) { 986 implicit_weak_sccs.push_back(child); 987 } else { 988 regular_sccs.push_back(child); 989 } 990 } 991 992 format( 993 "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$> $2$ =\n" 994 " " 995 "{{ATOMIC_VAR_INIT(::$proto_ns$::internal::SCCInfoBase::kUninitialized), " 996 "$3$, $4$, InitDefaults$2$}, {", 997 scc->children.size(), // 1 998 SccInfoSymbol(scc, options_), regular_sccs.size(), 999 implicit_weak_sccs.size()); 1000 for (const SCC* child : regular_sccs) { 1001 format("\n &$1$.base,", SccInfoSymbol(child, options_)); 1002 } 1003 for (const SCC* child : implicit_weak_sccs) { 1004 format( 1005 "\n reinterpret_cast<::$proto_ns$::internal::SCCInfoBase**>(" 1006 "\n &$1$),", 1007 SccInfoPtrSymbol(child, options_)); 1008 } 1009 format("}};\n\n"); 1010 1011 if (options_.lite_implicit_weak_fields) { 1012 format( 1013 "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$>*\n" 1014 " $2$ = &$3$;\n\n", 1015 scc->children.size(), SccInfoPtrSymbol(scc, options_), 1016 SccInfoSymbol(scc, options_)); 1017 } 1018} 1019 1020void FileGenerator::GenerateTables(io::Printer* printer) { 1021 Formatter format(printer, variables_); 1022 if (options_.table_driven_parsing) { 1023 // TODO(ckennelly): Gate this with the same options flag to enable 1024 // table-driven parsing. 1025 format( 1026 "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n" 1027 " const $tablename$::entries[] " 1028 "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); 1029 format.Indent(); 1030 1031 std::vector<size_t> entries; 1032 size_t count = 0; 1033 for (int i = 0; i < message_generators_.size(); i++) { 1034 size_t value = message_generators_[i]->GenerateParseOffsets(printer); 1035 entries.push_back(value); 1036 count += value; 1037 } 1038 1039 // We need these arrays to exist, and MSVC does not like empty arrays. 1040 if (count == 0) { 1041 format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); 1042 } 1043 1044 format.Outdent(); 1045 format( 1046 "};\n" 1047 "\n" 1048 "PROTOBUF_CONSTEXPR_VAR " 1049 "::$proto_ns$::internal::AuxiliaryParseTableField\n" 1050 " const $tablename$::aux[] " 1051 "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); 1052 format.Indent(); 1053 1054 std::vector<size_t> aux_entries; 1055 count = 0; 1056 for (int i = 0; i < message_generators_.size(); i++) { 1057 size_t value = message_generators_[i]->GenerateParseAuxTable(printer); 1058 aux_entries.push_back(value); 1059 count += value; 1060 } 1061 1062 if (count == 0) { 1063 format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); 1064 } 1065 1066 format.Outdent(); 1067 format( 1068 "};\n" 1069 "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n" 1070 " $tablename$::schema[] " 1071 "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); 1072 format.Indent(); 1073 1074 size_t offset = 0; 1075 size_t aux_offset = 0; 1076 for (int i = 0; i < message_generators_.size(); i++) { 1077 message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); 1078 offset += entries[i]; 1079 aux_offset += aux_entries[i]; 1080 } 1081 1082 if (message_generators_.empty()) { 1083 format("{ nullptr, nullptr, 0, -1, -1, false },\n"); 1084 } 1085 1086 format.Outdent(); 1087 format( 1088 "};\n" 1089 "\n"); 1090 } 1091 1092 if (!message_generators_.empty() && options_.table_driven_serialization) { 1093 format( 1094 "const ::$proto_ns$::internal::FieldMetadata " 1095 "$tablename$::field_metadata[] " 1096 "= {\n"); 1097 format.Indent(); 1098 std::vector<int> field_metadata_offsets; 1099 int idx = 0; 1100 for (int i = 0; i < message_generators_.size(); i++) { 1101 field_metadata_offsets.push_back(idx); 1102 idx += message_generators_[i]->GenerateFieldMetadata(printer); 1103 } 1104 field_metadata_offsets.push_back(idx); 1105 format.Outdent(); 1106 format( 1107 "};\n" 1108 "const ::$proto_ns$::internal::SerializationTable " 1109 "$tablename$::serialization_table[] = {\n"); 1110 format.Indent(); 1111 // We rely on the order we layout the tables to match the order we 1112 // calculate them with FlattenMessagesInFile, so we check here that 1113 // these match exactly. 1114 std::vector<const Descriptor*> calculated_order = 1115 FlattenMessagesInFile(file_); 1116 GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); 1117 for (int i = 0; i < message_generators_.size(); i++) { 1118 GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); 1119 format("{$1$, $tablename$::field_metadata + $2$},\n", 1120 field_metadata_offsets[i + 1] - field_metadata_offsets[i], // 1 1121 field_metadata_offsets[i]); // 2 1122 } 1123 format.Outdent(); 1124 format( 1125 "};\n" 1126 "\n"); 1127 } 1128} 1129 1130class FileGenerator::ForwardDeclarations { 1131 public: 1132 void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; } 1133 void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; } 1134 1135 void Print(const Formatter& format, const Options& options) const { 1136 for (const auto& p : enums_) { 1137 const std::string& enumname = p.first; 1138 const EnumDescriptor* enum_desc = p.second; 1139 format( 1140 "enum ${1$$2$$}$ : int;\n" 1141 "bool $2$_IsValid(int value);\n", 1142 enum_desc, enumname); 1143 } 1144 for (const auto& p : classes_) { 1145 const std::string& classname = p.first; 1146 const Descriptor* class_desc = p.second; 1147 format( 1148 "class ${1$$2$$}$;\n" 1149 "class $3$;\n" 1150 "$dllexport_decl $extern $3$ $4$;\n", 1151 class_desc, classname, DefaultInstanceType(class_desc, options), 1152 DefaultInstanceName(class_desc, options)); 1153 } 1154 } 1155 1156 void PrintTopLevelDecl(const Formatter& format, 1157 const Options& options) const { 1158 for (const auto& pair : classes_) { 1159 format( 1160 "template<> $dllexport_decl $" 1161 "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n", 1162 QualifiedClassName(pair.second, options)); 1163 } 1164 } 1165 1166 private: 1167 std::map<std::string, const Descriptor*> classes_; 1168 std::map<std::string, const EnumDescriptor*> enums_; 1169}; 1170 1171static void PublicImportDFS(const FileDescriptor* fd, 1172 std::unordered_set<const FileDescriptor*>* fd_set) { 1173 for (int i = 0; i < fd->public_dependency_count(); i++) { 1174 const FileDescriptor* dep = fd->public_dependency(i); 1175 if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set); 1176 } 1177} 1178 1179void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { 1180 Formatter format(printer, variables_); 1181 std::vector<const Descriptor*> classes; 1182 std::vector<const EnumDescriptor*> enums; 1183 1184 FlattenMessagesInFile(file_, &classes); // All messages need forward decls. 1185 1186 if (options_.proto_h) { // proto.h needs extra forward declarations. 1187 // All classes / enums referred to as field members 1188 std::vector<const FieldDescriptor*> fields; 1189 ListAllFields(file_, &fields); 1190 for (int i = 0; i < fields.size(); i++) { 1191 classes.push_back(fields[i]->containing_type()); 1192 classes.push_back(fields[i]->message_type()); 1193 enums.push_back(fields[i]->enum_type()); 1194 } 1195 ListAllTypesForServices(file_, &classes); 1196 } 1197 1198 // Calculate the set of files whose definitions we get through include. 1199 // No need to forward declare types that are defined in these. 1200 std::unordered_set<const FileDescriptor*> public_set; 1201 PublicImportDFS(file_, &public_set); 1202 1203 std::map<std::string, ForwardDeclarations> decls; 1204 for (int i = 0; i < classes.size(); i++) { 1205 const Descriptor* d = classes[i]; 1206 if (d && !public_set.count(d->file())) 1207 decls[Namespace(d, options_)].AddMessage(d); 1208 } 1209 for (int i = 0; i < enums.size(); i++) { 1210 const EnumDescriptor* d = enums[i]; 1211 if (d && !public_set.count(d->file())) 1212 decls[Namespace(d, options_)].AddEnum(d); 1213 } 1214 1215 1216 { 1217 NamespaceOpener ns(format); 1218 for (const auto& pair : decls) { 1219 ns.ChangeTo(pair.first); 1220 pair.second.Print(format, options_); 1221 } 1222 } 1223 format("PROTOBUF_NAMESPACE_OPEN\n"); 1224 for (const auto& pair : decls) { 1225 pair.second.PrintTopLevelDecl(format, options_); 1226 } 1227 format("PROTOBUF_NAMESPACE_CLOSE\n"); 1228} 1229 1230void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, bool pb_h) { 1231 Formatter format(printer, variables_); 1232 // Generate top of header. 1233 format( 1234 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" 1235 "// source: $filename$\n" 1236 "\n" 1237 "#ifndef $1$\n" 1238 "#define $1$\n" 1239 "\n" 1240 "#include <limits>\n" 1241 "#include <string>\n", 1242 IncludeGuard(file_, pb_h, options_)); 1243 if (!options_.opensource_runtime && !enum_generators_.empty()) { 1244 // Add header to provide std::is_integral for safe Enum_Name() function. 1245 format("#include <type_traits>\n"); 1246 } 1247 format("\n"); 1248} 1249 1250void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h) { 1251 Formatter format(printer, variables_); 1252 format("#endif // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n", 1253 IncludeGuard(file_, pb_h, options_)); 1254} 1255 1256void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { 1257 Formatter format(printer, variables_); 1258 if (UsingImplicitWeakFields(file_, options_)) { 1259 IncludeFile("net/proto2/public/implicit_weak_message.h", printer); 1260 } 1261 if (HasWeakFields(file_, options_)) { 1262 GOOGLE_CHECK(!options_.opensource_runtime); 1263 IncludeFile("net/proto2/public/weak_field_map.h", printer); 1264 } 1265 if (HasLazyFields(file_, options_)) { 1266 GOOGLE_CHECK(!options_.opensource_runtime); 1267 IncludeFile("net/proto2/public/lazy_field.h", printer); 1268 } 1269 1270 if (options_.opensource_runtime) { 1271 // Verify the protobuf library header version is compatible with the protoc 1272 // version before going any further. 1273 IncludeFile("net/proto2/public/port_def.inc", printer); 1274 format( 1275 "#if PROTOBUF_VERSION < $1$\n" 1276 "#error This file was generated by a newer version of protoc which is\n" 1277 "#error incompatible with your Protocol Buffer headers. Please update\n" 1278 "#error your headers.\n" 1279 "#endif\n" 1280 "#if $2$ < PROTOBUF_MIN_PROTOC_VERSION\n" 1281 "#error This file was generated by an older version of protoc which " 1282 "is\n" 1283 "#error incompatible with your Protocol Buffer headers. Please\n" 1284 "#error regenerate this file with a newer version of protoc.\n" 1285 "#endif\n" 1286 "\n", 1287 PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC, // 1 1288 PROTOBUF_VERSION); // 2 1289 IncludeFile("net/proto2/public/port_undef.inc", printer); 1290 } 1291 1292 // OK, it's now safe to #include other files. 1293 IncludeFile("net/proto2/io/public/coded_stream.h", printer); 1294 IncludeFile("net/proto2/public/arena.h", printer); 1295 IncludeFile("net/proto2/public/arenastring.h", printer); 1296 IncludeFile("net/proto2/public/generated_message_table_driven.h", printer); 1297 IncludeFile("net/proto2/public/generated_message_util.h", printer); 1298 IncludeFile("net/proto2/public/inlined_string_field.h", printer); 1299 IncludeFile("net/proto2/public/metadata_lite.h", printer); 1300 1301 if (HasDescriptorMethods(file_, options_)) { 1302 IncludeFile("net/proto2/public/generated_message_reflection.h", printer); 1303 } 1304 1305 if (!message_generators_.empty()) { 1306 if (HasDescriptorMethods(file_, options_)) { 1307 IncludeFile("net/proto2/public/message.h", printer); 1308 } else { 1309 IncludeFile("net/proto2/public/message_lite.h", printer); 1310 } 1311 } 1312 if (options_.opensource_runtime) { 1313 // Open-source relies on unconditional includes of these. 1314 IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); 1315 IncludeFileAndExport("net/proto2/public/extension_set.h", printer); 1316 } else { 1317 // Google3 includes these files only when they are necessary. 1318 if (HasExtensionsOrExtendableMessage(file_)) { 1319 IncludeFileAndExport("net/proto2/public/extension_set.h", printer); 1320 } 1321 if (HasRepeatedFields(file_)) { 1322 IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); 1323 } 1324 if (HasStringPieceFields(file_, options_)) { 1325 IncludeFile("net/proto2/public/string_piece_field_support.h", printer); 1326 } 1327 if (HasCordFields(file_, options_)) { 1328 format("#include \"third_party/absl/strings/cord.h\"\n"); 1329 } 1330 } 1331 if (HasMapFields(file_)) { 1332 IncludeFileAndExport("net/proto2/public/map.h", printer); 1333 if (HasDescriptorMethods(file_, options_)) { 1334 IncludeFile("net/proto2/public/map_entry.h", printer); 1335 IncludeFile("net/proto2/public/map_field_inl.h", printer); 1336 } else { 1337 IncludeFile("net/proto2/public/map_entry_lite.h", printer); 1338 IncludeFile("net/proto2/public/map_field_lite.h", printer); 1339 } 1340 } 1341 1342 if (HasEnumDefinitions(file_)) { 1343 if (HasDescriptorMethods(file_, options_)) { 1344 IncludeFile("net/proto2/public/generated_enum_reflection.h", printer); 1345 } else { 1346 IncludeFile("net/proto2/public/generated_enum_util.h", printer); 1347 } 1348 } 1349 1350 if (HasGenericServices(file_, options_)) { 1351 IncludeFile("net/proto2/public/service.h", printer); 1352 } 1353 1354 if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { 1355 IncludeFile("net/proto2/public/unknown_field_set.h", printer); 1356 } 1357} 1358 1359void FileGenerator::GenerateMetadataPragma(io::Printer* printer, 1360 const std::string& info_path) { 1361 Formatter format(printer, variables_); 1362 if (!info_path.empty() && !options_.annotation_pragma_name.empty() && 1363 !options_.annotation_guard_name.empty()) { 1364 format.Set("guard", options_.annotation_guard_name); 1365 format.Set("pragma", options_.annotation_pragma_name); 1366 format.Set("info_path", info_path); 1367 format( 1368 "#ifdef $guard$\n" 1369 "#pragma $pragma$ \"$info_path$\"\n" 1370 "#endif // $guard$\n"); 1371 } 1372} 1373 1374void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { 1375 Formatter format(printer, variables_); 1376 for (int i = 0; i < file_->dependency_count(); i++) { 1377 std::string basename = StripProto(file_->dependency(i)->name()); 1378 1379 // Do not import weak deps. 1380 if (IsDepWeak(file_->dependency(i))) continue; 1381 1382 if (IsBootstrapProto(options_, file_)) { 1383 GetBootstrapBasename(options_, basename, &basename); 1384 } 1385 1386 format("#include $1$\n", 1387 CreateHeaderInclude(basename + ".pb.h", file_->dependency(i))); 1388 } 1389} 1390 1391void FileGenerator::GenerateGlobalStateFunctionDeclarations( 1392 io::Printer* printer) { 1393 Formatter format(printer, variables_); 1394 // Forward-declare the DescriptorTable because this is referenced by .pb.cc 1395 // files depending on this file. 1396 // 1397 // The TableStruct is also outputted in weak_message_field.cc, because the 1398 // weak fields must refer to table struct but cannot include the header. 1399 // Also it annotates extra weak attributes. 1400 // TODO(gerbens) make sure this situation is handled better. 1401 format( 1402 "\n" 1403 "// Internal implementation detail -- do not use these members.\n" 1404 "struct $dllexport_decl $$tablename$ {\n" 1405 // These tables describe how to serialize and parse messages. Used 1406 // for table driven code. 1407 " static const ::$proto_ns$::internal::ParseTableField entries[]\n" 1408 " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" 1409 " static const ::$proto_ns$::internal::AuxiliaryParseTableField aux[]\n" 1410 " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" 1411 " static const ::$proto_ns$::internal::ParseTable schema[$1$]\n" 1412 " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" 1413 " static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n" 1414 " static const ::$proto_ns$::internal::SerializationTable " 1415 "serialization_table[];\n" 1416 " static const $uint32$ offsets[];\n" 1417 "};\n", 1418 std::max(size_t(1), message_generators_.size())); 1419 if (HasDescriptorMethods(file_, options_)) { 1420 format( 1421 "extern $dllexport_decl $const ::$proto_ns$::internal::DescriptorTable " 1422 "$desc_table$;\n"); 1423 } 1424} 1425 1426void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { 1427 Formatter format(printer, variables_); 1428 // Generate class definitions. 1429 for (int i = 0; i < message_generators_.size(); i++) { 1430 if (i > 0) { 1431 format("\n"); 1432 format(kThinSeparator); 1433 format("\n"); 1434 } 1435 message_generators_[i]->GenerateClassDefinition(printer); 1436 } 1437} 1438 1439void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { 1440 // Generate enum definitions. 1441 for (int i = 0; i < enum_generators_.size(); i++) { 1442 enum_generators_[i]->GenerateDefinition(printer); 1443 } 1444} 1445 1446void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { 1447 Formatter format(printer, variables_); 1448 if (HasGenericServices(file_, options_)) { 1449 // Generate service definitions. 1450 for (int i = 0; i < service_generators_.size(); i++) { 1451 if (i > 0) { 1452 format("\n"); 1453 format(kThinSeparator); 1454 format("\n"); 1455 } 1456 service_generators_[i]->GenerateDeclarations(printer); 1457 } 1458 1459 format("\n"); 1460 format(kThickSeparator); 1461 format("\n"); 1462 } 1463} 1464 1465void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { 1466 // Declare extension identifiers. These are in global scope and so only 1467 // the global scope extensions. 1468 for (auto& extension_generator : extension_generators_) { 1469 if (extension_generator->IsScoped()) continue; 1470 extension_generator->GenerateDeclaration(printer); 1471 } 1472} 1473 1474void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { 1475 Formatter format(printer, variables_); 1476 // TODO(gerbens) remove pragmas when gcc is no longer used. Current version 1477 // of gcc fires a bogus error when compiled with strict-aliasing. 1478 format( 1479 "#ifdef __GNUC__\n" 1480 " #pragma GCC diagnostic push\n" 1481 " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" 1482 "#endif // __GNUC__\n"); 1483 // Generate class inline methods. 1484 for (int i = 0; i < message_generators_.size(); i++) { 1485 if (i > 0) { 1486 format(kThinSeparator); 1487 format("\n"); 1488 } 1489 message_generators_[i]->GenerateInlineMethods(printer); 1490 } 1491 format( 1492 "#ifdef __GNUC__\n" 1493 " #pragma GCC diagnostic pop\n" 1494 "#endif // __GNUC__\n"); 1495 1496 for (int i = 0; i < message_generators_.size(); i++) { 1497 if (i > 0) { 1498 format(kThinSeparator); 1499 format("\n"); 1500 } 1501 } 1502} 1503 1504void FileGenerator::GenerateProto2NamespaceEnumSpecializations( 1505 io::Printer* printer) { 1506 Formatter format(printer, variables_); 1507 // Emit GetEnumDescriptor specializations into google::protobuf namespace: 1508 if (HasEnumDefinitions(file_)) { 1509 format("\n"); 1510 { 1511 NamespaceOpener proto_ns(ProtobufNamespace(options_), format); 1512 format("\n"); 1513 for (int i = 0; i < enum_generators_.size(); i++) { 1514 enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); 1515 } 1516 format("\n"); 1517 } 1518 } 1519} 1520 1521} // namespace cpp 1522} // namespace compiler 1523} // namespace protobuf 1524} // namespace google 1525