// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace compiler { namespace cpp { FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), options_(options), scc_analyzer_(options), enum_generators_owner_( new std::unique_ptr[file->enum_type_count()]), service_generators_owner_( new std::unique_ptr[file->service_count()]), extension_generators_owner_( new std::unique_ptr[file->extension_count()]) { std::vector msgs = FlattenMessagesInFile(file); for (int i = 0; i < msgs.size(); i++) { // Deleted in destructor MessageGenerator* msg_gen = new MessageGenerator(msgs[i], i, options, &scc_analyzer_); message_generators_.push_back(msg_gen); msg_gen->AddGenerators(&enum_generators_, &extension_generators_); } for (int i = 0; i < file->enum_type_count(); i++) { enum_generators_owner_[i].reset( new EnumGenerator(file->enum_type(i), options)); enum_generators_.push_back(enum_generators_owner_[i].get()); } for (int i = 0; i < file->service_count(); i++) { service_generators_owner_[i].reset( new ServiceGenerator(file->service(i), options)); service_generators_.push_back(service_generators_owner_[i].get()); } if (HasGenericServices(file_, options_)) { for (int i = 0; i < service_generators_.size(); i++) { service_generators_[i]->index_in_metadata_ = i; } } for (int i = 0; i < file->extension_count(); i++) { extension_generators_owner_[i].reset( new ExtensionGenerator(file->extension(i), options)); extension_generators_.push_back(extension_generators_owner_[i].get()); } package_parts_ = Split(file_->package(), ".", true); } FileGenerator::~FileGenerator() { for (int i = 0; i < message_generators_.size(); i++) { delete message_generators_[i]; } } void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { // Only do this for protobuf's own types. There are some google3 protos using // macros as field names and the generated code compiles after the macro // expansion. Undefing these macros actually breaks such code. if (file_->name() != "google/protobuf/compiler/plugin.proto") { return; } std::vector names_to_undef; std::vector fields; ListAllFields(file_, &fields); for (int i = 0; i < fields.size(); i++) { const string& name = fields[i]->name(); static const char* kMacroNames[] = {"major", "minor"}; for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) { if (name == kMacroNames[i]) { names_to_undef.push_back(name); break; } } } for (int i = 0; i < names_to_undef.size(); ++i) { printer->Print( "#ifdef $name$\n" "#undef $name$\n" "#endif\n", "name", names_to_undef[i]); } } void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "// @@protoc_insertion_point(includes)\n"); printer->Print("#define PROTOBUF_INTERNAL_EXPORT_$filename$ $export$\n", "filename", FileLevelNamespace(file_), "export", options_.dllexport_decl); GenerateMacroUndefs(printer); GenerateGlobalStateFunctionDeclarations(printer); GenerateForwardDeclarations(printer); { NamespaceOpener ns(Namespace(file_), printer); printer->Print("\n"); GenerateEnumDefinitions(printer); printer->Print(kThickSeparator); printer->Print("\n"); GenerateMessageDefinitions(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); GenerateServiceDefinitions(printer); GenerateExtensionIdentifiers(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); GenerateInlineFunctionDefinitions(printer); printer->Print( "\n" "// @@protoc_insertion_point(namespace_scope)\n" "\n"); } // We need to specialize some templates in the ::google::protobuf namespace: GenerateProto2NamespaceEnumSpecializations(printer); printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n" "\n"); } void FileGenerator::GenerateProtoHeader(io::Printer* printer, const string& info_path) { if (!options_.proto_h) { return; } string filename_identifier = FilenameIdentifier(file_->name()); GenerateTopHeaderGuard(printer, filename_identifier); GenerateLibraryIncludes(printer); for (int i = 0; i < file_->public_dependency_count(); i++) { const FileDescriptor* dep = file_->public_dependency(i); const char* extension = ".proto.h"; string dependency = StripProto(dep->name()) + extension; printer->Print( "#include \"$dependency$\" // IWYU pragma: export\n", "dependency", dependency); } GenerateMetadataPragma(printer, info_path); GenerateHeader(printer); GenerateBottomHeaderGuard(printer, filename_identifier); } void FileGenerator::GeneratePBHeader(io::Printer* printer, const string& info_path) { string filename_identifier = FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); GenerateTopHeaderGuard(printer, filename_identifier); if (options_.proto_h) { string target_basename = StripProto(file_->name()); printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", "basename", target_basename); } else { GenerateLibraryIncludes(printer); } GenerateDependencyIncludes(printer); GenerateMetadataPragma(printer, info_path); if (!options_.proto_h) { GenerateHeader(printer); } else { // This is unfortunately necessary for some plugins. I don't see why we // need two of the same insertion points. // TODO(gerbens) remove this. printer->Print( "// @@protoc_insertion_point(includes)\n"); { NamespaceOpener ns(Namespace(file_), printer); printer->Print( "\n" "// @@protoc_insertion_point(namespace_scope)\n"); } printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n" "\n"); } GenerateBottomHeaderGuard(printer, filename_identifier); } void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { string target_basename = StripProto(file_->name()); const bool use_system_include = IsWellKnownMessage(file_); string header = target_basename + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" "#include $left$$header$$right$\n" "\n" "#include \n" // for swap() "\n" "#include \n" "#include \n" "#include \n" "#include \n", "filename", file_->name(), "header", header, "left", use_system_include ? "<" : "\"", "right", use_system_include ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { printer->Print( "#include \n"); } if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n" "#include \n" "#include \n" "#include \n"); } if (options_.proto_h) { // Use the smaller .proto.h files. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dep = file_->dependency(i); const char* extension = ".proto.h"; string basename = StripProto(dep->name()); string dependency = basename + extension; printer->Print( "#include \"$dependency$\"\n", "dependency", dependency); } } // TODO(gerbens) Remove this when all code in google is using the same // proto library. This is a temporary hack to force build errors if // the proto library is compiled with GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS // and is also linking internal proto2. This is to prevent regressions while // we work cleaning up the code base. After this is completed and we have // one proto lib all code uses this should be removed. printer->Print( "// This is a temporary google only hack\n" "#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n" "#include \"third_party/protobuf/version.h\"\n" "#endif\n"); printer->Print( "// @@protoc_insertion_point(includes)\n"); } void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* printer) { printer->Print( "class $classname$DefaultTypeInternal {\n" " public:\n" " ::google::protobuf::internal::ExplicitlyConstructed<$classname$>\n" " _instance;\n", "classname", message_generators_[idx]->classname_); printer->Indent(); message_generators_[idx]->GenerateExtraDefaultFields(printer); printer->Outdent(); printer->Print("} _$classname$_default_instance_;\n", "classname", message_generators_[idx]->classname_); } namespace { // Generates weak symbol declarations for types that are to be considered weakly // referenced. void GenerateInternalForwardDeclarations( const std::vector& fields, const Options& options, SCCAnalyzer* scc_analyzer, io::Printer* printer) { // To ensure determinism and minimize the number of namespace statements, // we output the forward declarations sorted on namespace and type / function // name. std::set > messages; std::set > sccs; std::set > inits; for (int i = 0; i < fields.size(); ++i) { const FieldDescriptor* field = fields[i]; const Descriptor* msg = field->message_type(); if (msg == nullptr) continue; bool is_weak = IsImplicitWeakField(field, options, scc_analyzer); string flns = FileLevelNamespace(msg); auto scc = scc_analyzer->GetSCC(msg); string repr = ClassName(scc->GetRepresentative()); string weak_attr; if (is_weak) { inits.insert(std::make_pair(flns, "AddDescriptors")); messages.insert(std::make_pair(Namespace(msg), ClassName(msg))); weak_attr = " __attribute__((weak))"; } string dllexport = "PROTOBUF_INTERNAL_EXPORT_" + FileLevelNamespace(msg); sccs.insert(std::make_pair(flns, "extern " + dllexport + weak_attr + " ::google::protobuf::internal::SCCInfo<" + SimpleItoa(scc->children.size()) + "> scc_info_" + repr + ";\n")); } printer->Print("\n"); NamespaceOpener ns(printer); for (std::set >::const_iterator it = messages.begin(); it != messages.end(); ++it) { ns.ChangeTo(it->first); printer->Print( "extern __attribute__((weak)) $classname$DefaultTypeInternal " "_$classname$_default_instance_;\n", "classname", it->second); } for (std::set >::const_iterator it = inits.begin(); it != inits.end(); ++it) { ns.ChangeTo(it->first); printer->Print("void $name$() __attribute__((weak));\n", "name", it->second); } for (const auto& p : sccs) { ns.ChangeTo(p.first); printer->Print(p.second.c_str()); } } } // namespace void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { GenerateSourceIncludes(printer); // Generate weak declarations. We do this for the whole strongly-connected // component (SCC), because we have a single InitDefaults* function for the // SCC. std::vector fields; for (const Descriptor* message : scc_analyzer_.GetSCC(message_generators_[idx]->descriptor_) ->descriptors) { ListAllFields(message, &fields); } GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, printer); if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); } { // package namespace NamespaceOpener ns(Namespace(file_), printer); // Define default instances GenerateSourceDefaultInstance(idx, printer); if (options_.lite_implicit_weak_fields) { printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", message_generators_[idx]->classname_); } // Generate classes. printer->Print("\n"); message_generators_[idx]->GenerateClassMethods(printer); printer->Print( "\n" "// @@protoc_insertion_point(namespace_scope)\n"); } // end package namespace printer->Print( "namespace google {\nnamespace protobuf {\n"); message_generators_[idx]->GenerateSourceInProto2Namespace(printer); printer->Print( "} // namespace protobuf\n} // namespace google\n"); printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n"); } void FileGenerator::GenerateGlobalSource(io::Printer* printer) { GenerateSourceIncludes(printer); { NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateTables(printer); // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. if (HasDescriptorMethods(file_, options_)) { GenerateReflectionInitializationCode(printer); } } NamespaceOpener ns(Namespace(file_), printer); // Generate enums. for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateMethods(i, printer); } // Define extensions. for (int i = 0; i < extension_generators_.size(); i++) { extension_generators_[i]->GenerateDefinition(printer); } if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < service_generators_.size(); i++) { if (i == 0) printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); service_generators_[i]->GenerateImplementation(printer); } } } void FileGenerator::GenerateSource(io::Printer* printer) { GenerateSourceIncludes(printer); std::vector fields; ListAllFields(file_, &fields); GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, printer); { NamespaceOpener ns(Namespace(file_), printer); // Define default instances for (int i = 0; i < message_generators_.size(); i++) { GenerateSourceDefaultInstance(i, printer); if (options_.lite_implicit_weak_fields) { printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", message_generators_[i]->classname_); } } } { NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateTables(printer); // Now generate the InitDefaults for each SCC. for (int i = 0; i < message_generators_.size(); i++) { if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), printer); } } printer->Print("void InitDefaults() {\n"); for (int i = 0; i < message_generators_.size(); i++) { if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; string scc_name = ClassName(message_generators_[i]->descriptor_); printer->Print( " ::google::protobuf::internal::InitSCC(&scc_info_$scc_name$.base);\n", "scc_name", scc_name); } printer->Print("}\n\n"); // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. if (HasDescriptorMethods(file_, options_)) { GenerateReflectionInitializationCode(printer); } } { NamespaceOpener ns(Namespace(file_), printer); // Actually implement the protos // Generate enums. for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateMethods(i, printer); } // Generate classes. for (int i = 0; i < message_generators_.size(); i++) { printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); message_generators_[i]->GenerateClassMethods(printer); } if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < service_generators_.size(); i++) { if (i == 0) printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); service_generators_[i]->GenerateImplementation(printer); } } // Define extensions. for (int i = 0; i < extension_generators_.size(); i++) { extension_generators_[i]->GenerateDefinition(printer); } printer->Print( "\n" "// @@protoc_insertion_point(namespace_scope)\n"); } printer->Print( "namespace google {\nnamespace protobuf {\n"); for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateSourceInProto2Namespace(printer); } printer->Print( "} // namespace protobuf\n} // namespace google\n"); printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n"); } class FileGenerator::ForwardDeclarations { public: ~ForwardDeclarations() { for (std::map::iterator it = namespaces_.begin(), end = namespaces_.end(); it != end; ++it) { delete it->second; } namespaces_.clear(); } ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { ForwardDeclarations*& ns = namespaces_[ns_name]; if (ns == nullptr) { ns = new ForwardDeclarations; } return ns; } std::map& classes() { return classes_; } std::map& enums() { return enums_; } void PrintForwardDeclarations(io::Printer* printer, const Options& options) const { PrintNestedDeclarations(printer, options); PrintTopLevelDeclarations(printer, options); } private: void PrintNestedDeclarations(io::Printer* printer, const Options& options) const { PrintDeclarationsInsideNamespace(printer, options); for (std::map::const_iterator it = namespaces_.begin(), end = namespaces_.end(); it != end; ++it) { printer->Print("namespace $nsname$ {\n", "nsname", it->first); it->second->PrintNestedDeclarations(printer, options); printer->Print("} // namespace $nsname$\n", "nsname", it->first); } } void PrintTopLevelDeclarations(io::Printer* printer, const Options& options) const { PrintDeclarationsOutsideNamespace(printer, options); for (std::map::const_iterator it = namespaces_.begin(), end = namespaces_.end(); it != end; ++it) { it->second->PrintTopLevelDeclarations(printer, options); } } void PrintDeclarationsInsideNamespace(io::Printer* printer, const Options& options) const { for (std::map::const_iterator it = enums_.begin(), end = enums_.end(); it != end; ++it) { printer->Print("enum $enumname$ : int;\n", "enumname", it->first); printer->Annotate("enumname", it->second); printer->Print("bool $enumname$_IsValid(int value);\n", "enumname", it->first); } for (std::map::const_iterator it = classes_.begin(), end = classes_.end(); it != end; ++it) { printer->Print("class $classname$;\n", "classname", it->first); printer->Annotate("classname", it->second); printer->Print( "class $classname$DefaultTypeInternal;\n" "$dllexport_decl$" "extern $classname$DefaultTypeInternal " "_$classname$_default_instance_;\n", // NOLINT "dllexport_decl", options.dllexport_decl.empty() ? "" : options.dllexport_decl + " ", "classname", it->first); if (options.lite_implicit_weak_fields) { printer->Print("void $classname$_ReferenceStrong();\n", "classname", it->first); } } } void PrintDeclarationsOutsideNamespace(io::Printer* printer, const Options& options) const { if (classes_.size() == 0) return; printer->Print( "namespace google {\nnamespace protobuf {\n"); for (std::map::const_iterator it = classes_.begin(), end = classes_.end(); it != end; ++it) { const Descriptor* d = it->second; printer->Print( "template<> " "$dllexport_decl$" "$classname$* Arena::CreateMaybeMessage<$classname$>" "(Arena*);\n", "classname", QualifiedClassName(d), "dllexport_decl", options.dllexport_decl.empty() ? "" : options.dllexport_decl + " "); } printer->Print( "} // namespace protobuf\n} // namespace google\n"); } std::map namespaces_; std::map classes_; std::map enums_; }; void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for // generated files (DescriptorPool::generated_pool()). It ordinarily runs at // static initialization time, but is not used at all in LITE_RUNTIME mode. // // Its sibling, AssignDescriptors(), actually pulls the compiled // FileDescriptor from the DescriptorPool and uses it to populate all of // the global variables which store pointers to the descriptor objects. // It also constructs the reflection objects. It is called the first time // anyone calls descriptor() or GetReflection() on one of the types defined // in the file. if (!message_generators_.empty()) { printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", "size", SimpleItoa(message_generators_.size())); } if (!enum_generators_.empty()) { printer->Print( "const ::google::protobuf::EnumDescriptor* " "file_level_enum_descriptors[$size$];\n", "size", SimpleItoa(enum_generators_.size())); } if (HasGenericServices(file_, options_) && file_->service_count() > 0) { printer->Print( "const ::google::protobuf::ServiceDescriptor* " "file_level_service_descriptors[$size$];\n", "size", SimpleItoa(file_->service_count())); } if (!message_generators_.empty()) { printer->Print( "\n" "const ::google::protobuf::uint32 TableStruct::offsets[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector > pairs; pairs.reserve(message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); } printer->Outdent(); printer->Print( "};\n" "static const ::google::protobuf::internal::MigrationSchema schemas[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); { int offset = 0; for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateSchema(printer, offset, pairs[i].second); offset += pairs[i].first; } } printer->Outdent(); printer->Print( "};\n" "\nstatic " "::google::protobuf::Message const * const file_default_instances[] = {\n"); printer->Indent(); for (int i = 0; i < message_generators_.size(); i++) { const Descriptor* descriptor = message_generators_[i]->descriptor_; printer->Print( "reinterpret_cast(&$ns$::_$classname$_default_instance_),\n", "classname", ClassName(descriptor), "ns", Namespace(descriptor)); } printer->Outdent(); printer->Print( "};\n" "\n"); } else { // we still need these symbols to exist printer->Print( // MSVC doesn't like empty arrays, so we add a dummy. "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n" "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" "static const ::google::protobuf::Message* const* " "file_default_instances = NULL;\n" "\n"); } // --------------------------------------------------------------- // protobuf_AssignDescriptorsOnce(): The first time it is called, calls // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. printer->Print( "void protobuf_AssignDescriptors() {\n" // Make sure the file has found its way into the pool. If a descriptor // is requested *during* static init then AddDescriptors() may not have // been called yet, so we call it manually. Note that it's fine if // AddDescriptors() is called multiple times. " AddDescriptors();\n" " AssignDescriptors(\n" " \"$filename$\", schemas, file_default_instances, " "TableStruct::offsets,\n" " $metadata$, $enum_descriptors$, $service_descriptors$);\n", "filename", file_->name(), "metadata", !message_generators_.empty() ? "file_level_metadata" : "NULL", "enum_descriptors", !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL", "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" : "NULL"); printer->Print( "}\n" "\n" "void protobuf_AssignDescriptorsOnce() {\n" " static ::google::protobuf::internal::once_flag once;\n" " ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);\n" "}\n" "\n", "filename", file_->name(), "metadata", !message_generators_.empty() ? "file_level_metadata" : "NULL", "enum_descriptors", !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL", "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" : "NULL"); // Only here because of useless string reference that we don't want in // protobuf_AssignDescriptorsOnce, because that is called from all the // GetMetadata member methods. printer->Print( "void protobuf_RegisterTypes(const ::std::string&) " "GOOGLE_PROTOBUF_ATTRIBUTE_COLD;\n" "void protobuf_RegisterTypes(const ::std::string&) {\n" " protobuf_AssignDescriptorsOnce();\n"); printer->Indent(); // All normal messages can be done generically if (!message_generators_.empty()) { printer->Print( "::google::protobuf::internal::RegisterAllTypes(file_level_metadata, $size$);\n", "size", SimpleItoa(message_generators_.size())); } printer->Outdent(); printer->Print( "}\n" "\n"); // Now generate the AddDescriptors() function. printer->Print( "void AddDescriptorsImpl() {\n" " InitDefaults();\n"); printer->Indent(); // Embed the descriptor. We simply serialize the entire // FileDescriptorProto // and embed it as a string literal, which is parsed and built into real // descriptors at initialization time. FileDescriptorProto file_proto; file_->CopyTo(&file_proto); string file_data; file_proto.SerializeToString(&file_data); printer->Print("static const char descriptor[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) " "= {\n"); printer->Indent(); if (file_data.size() > 65535) { // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 // bytes in length". Declare a static array of characters rather than use // a string literal. Only write 25 bytes per line. static const int kBytesPerLine = 25; for (int i = 0; i < file_data.size();) { for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { printer->Print("'$char$', ", "char", CEscape(file_data.substr(i, 1))); } printer->Print("\n"); } } else { // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { printer->Print(" \"$data$\"\n", "data", EscapeTrigraphs(CEscape( file_data.substr(i, kBytesPerLine)))); } } printer->Outdent(); printer->Print("};\n"); printer->Print( "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(\n" " descriptor, $size$);\n", "size", SimpleItoa(file_data.size())); // Call MessageFactory::InternalRegisterGeneratedFile(). printer->Print( "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" " \"$filename$\", &protobuf_RegisterTypes);\n", "filename", file_->name()); // Call the AddDescriptors() methods for all of our dependencies, to make // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. string file_namespace = FileLevelNamespace(dependency); // Call its AddDescriptors function. printer->Print("::$file_namespace$::AddDescriptors();\n", "file_namespace", file_namespace); } printer->Outdent(); printer->Print( "}\n" "\n" "void AddDescriptors() {\n" " static ::google::protobuf::internal::once_flag once;\n" " ::google::protobuf::internal::call_once(once, AddDescriptorsImpl);\n" "}\n"); printer->Print( "// Force AddDescriptors() to be called at dynamic initialization " "time.\n" "struct StaticDescriptorInitializer {\n" " StaticDescriptorInitializer() {\n" " AddDescriptors();\n" " }\n" "} static_descriptor_initializer;\n"); } void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { const string scc_name = ClassName(scc->GetRepresentative()); // We use static and not anonymous namespace because symbol names are // substantially shorter. printer->Print( "static void InitDefaults$scc_name$() {\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" , // awkward comma due to macro "scc_name", scc_name); printer->Indent(); // First construct all the necessary default instances. for (int i = 0; i < message_generators_.size(); i++) { if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { continue; } // TODO(gerbens) This requires this function to be friend. Remove // the need for this. message_generators_[i]->GenerateFieldDefaultInstances(printer); printer->Print( "{\n" " void* ptr = &$ns$::_$classname$_default_instance_;\n" " new (ptr) $ns$::$classname$();\n", "ns", Namespace(message_generators_[i]->descriptor_), "classname", ClassName(message_generators_[i]->descriptor_)); if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) { printer->Print( " ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);\n"); } printer->Print("}\n"); } // TODO(gerbens) make default instances be the same as normal instances. // Default instances differ from normal instances because they have cross // linked message fields. for (int i = 0; i < message_generators_.size(); i++) { if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { continue; } printer->Print("$classname$::InitAsDefaultInstance();\n", "classname", QualifiedClassName(message_generators_[i]->descriptor_)); } printer->Outdent(); printer->Print("}\n\n"); printer->Print( "$dllexport_decl$::google::protobuf::internal::SCCInfo<$size$> " "scc_info_$scc_name$ =\n" " {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), " "$size$, InitDefaults$scc_name$}, {", "size", SimpleItoa(scc->children.size()), "scc_name", ClassName(scc->GetRepresentative()), "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); for (const SCC* child : scc->children) { auto repr = child->GetRepresentative(); printer->Print("\n &$ns$::scc_info_$child$.base,", "ns", FileLevelNamespace(repr), "child", ClassName(repr)); } printer->Print("}};\n\n"); } void FileGenerator::GenerateTables(io::Printer* printer) { if (options_.table_driven_parsing) { // TODO(ckennelly): Gate this with the same options flag to enable // table-driven parsing. printer->Print( "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n" " const TableStruct::entries[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector entries; size_t count = 0; for (int i = 0; i < message_generators_.size(); i++) { size_t value = message_generators_[i]->GenerateParseOffsets(printer); entries.push_back(value); count += value; } // We need these arrays to exist, and MSVC does not like empty arrays. if (count == 0) { printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n"); } printer->Outdent(); printer->Print( "};\n" "\n" "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n" " const TableStruct::aux[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector aux_entries; count = 0; for (int i = 0; i < message_generators_.size(); i++) { size_t value = message_generators_[i]->GenerateParseAuxTable(printer); aux_entries.push_back(value); count += value; } if (count == 0) { printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); } printer->Outdent(); printer->Print( "};\n" "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n" " TableStruct::schema[] " "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); size_t offset = 0; size_t aux_offset = 0; for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); offset += entries[i]; aux_offset += aux_entries[i]; } if (message_generators_.empty()) { printer->Print("{ NULL, NULL, 0, -1, -1, false },\n"); } printer->Outdent(); printer->Print( "};\n" "\n"); } if (!message_generators_.empty() && options_.table_driven_serialization) { printer->Print( "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] " "= {\n"); printer->Indent(); std::vector field_metadata_offsets; int idx = 0; for (int i = 0; i < message_generators_.size(); i++) { field_metadata_offsets.push_back(idx); idx += message_generators_[i]->GenerateFieldMetadata(printer); } field_metadata_offsets.push_back(idx); printer->Outdent(); printer->Print( "};\n" "const ::google::protobuf::internal::SerializationTable " "TableStruct::serialization_table[] = {\n"); printer->Indent(); // We rely on the order we layout the tables to match the order we // calculate them with FlattenMessagesInFile, so we check here that // these match exactly. std::vector calculated_order = FlattenMessagesInFile(file_); GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); printer->Print( "{$num_fields$, TableStruct::field_metadata + $index$},\n", "classname", message_generators_[i]->classname_, "num_fields", SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]), "index", SimpleItoa(field_metadata_offsets[i])); } printer->Outdent(); printer->Print( "};\n" "\n"); } } void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { ForwardDeclarations decls; FillForwardDeclarations(&decls); decls.PrintForwardDeclarations(printer, options_); } void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { for (int i = 0; i < package_parts_.size(); i++) { decls = decls->AddOrGetNamespace(package_parts_[i]); } // Generate enum definitions. for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->FillForwardDeclaration(&decls->enums()); } // Generate forward declarations of classes. for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->FillMessageForwardDeclarations( &decls->classes()); } } void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, const string& filename_identifier) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" "#ifndef PROTOBUF_INCLUDED_$filename_identifier$\n" "#define PROTOBUF_INCLUDED_$filename_identifier$\n" "\n" "#include \n", "filename", file_->name(), "filename_identifier", filename_identifier); printer->Print("\n"); } void FileGenerator::GenerateBottomHeaderGuard( io::Printer* printer, const string& filename_identifier) { printer->Print( "#endif // PROTOBUF_INCLUDED_$filename_identifier$\n", "filename_identifier", filename_identifier); } void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (UsingImplicitWeakFields(file_, options_)) { printer->Print("#include \n"); } printer->Print( "#include \n" "\n"); // Verify the protobuf library header version is compatible with the protoc // version before going any further. printer->Print( "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" "#error This file was generated by a newer version of protoc which is\n" "#error incompatible with your Protocol Buffer headers. Please update\n" "#error your headers.\n" "#endif\n" "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" "#error This file was generated by an older version of protoc which is\n" "#error incompatible with your Protocol Buffer headers. Please\n" "#error regenerate this file with a newer version of protoc.\n" "#endif\n" "\n", "min_header_version", SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); // OK, it's now safe to #include other files. printer->Print( "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n"); if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { printer->Print( "#include \n"); } if (!message_generators_.empty()) { if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { printer->Print( "#include \n"); } } printer->Print( "#include " " // IWYU pragma: export\n" "#include " " // IWYU pragma: export\n"); if (HasMapFields(file_)) { printer->Print( "#include " " // IWYU pragma: export\n"); if (HasDescriptorMethods(file_, options_)) { printer->Print("#include \n"); printer->Print("#include \n"); } else { printer->Print("#include \n"); printer->Print("#include \n"); } } if (HasEnumDefinitions(file_)) { if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { printer->Print( "#include \n"); } } if (HasGenericServices(file_, options_)) { printer->Print( "#include \n"); } if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { printer->Print( "#include \n"); } if (IsAnyMessage(file_)) { printer->Print( "#include \n"); } } void FileGenerator::GenerateMetadataPragma(io::Printer* printer, const string& info_path) { if (!info_path.empty() && !options_.annotation_pragma_name.empty() && !options_.annotation_guard_name.empty()) { printer->Print( "#ifdef $guard$\n" "#pragma $pragma$ \"$info_path$\"\n" "#endif // $guard$\n", "guard", options_.annotation_guard_name, "pragma", options_.annotation_pragma_name, "info_path", info_path); } } void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { std::set public_import_names; for (int i = 0; i < file_->public_dependency_count(); i++) { public_import_names.insert(file_->public_dependency(i)->name()); } for (int i = 0; i < file_->dependency_count(); i++) { const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); string basename = StripProto(name); printer->Print( "#include $left$$dependency$.pb.h$right$$iwyu$\n", "dependency", basename, "iwyu", (public_import) ? " // IWYU pragma: export" : "", "left", use_system_include ? "<" : "\"", "right", use_system_include ? ">" : "\""); } } void FileGenerator::GenerateGlobalStateFunctionDeclarations( io::Printer* printer) { // Forward-declare the AddDescriptors, InitDefaults because these are called // by .pb.cc files depending on this file. printer->Print( "\n" "namespace $file_namespace$ {\n" "// Internal implementation detail -- do not use these members.\n" "struct $dllexport_decl$TableStruct {\n" // These tables describe how to serialize and parse messages. Used // for table driven code. " static const ::google::protobuf::internal::ParseTableField entries[];\n" " static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n" " static const ::google::protobuf::internal::ParseTable schema[$num$];\n" " static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n" " static const ::google::protobuf::internal::SerializationTable " "serialization_table[];\n" " static const ::google::protobuf::uint32 offsets[];\n" "};\n", "file_namespace", FileLevelNamespace(file_), "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ", "num", SimpleItoa(std::max(size_t(1), message_generators_.size()))); if (HasDescriptorMethods(file_, options_)) { printer->Print( "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); } printer->Print( "} // namespace $file_namespace$\n", "file_namespace", FileLevelNamespace(file_)); } void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { // Generate class definitions. for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print("\n"); printer->Print(kThinSeparator); printer->Print("\n"); } message_generators_[i]->GenerateClassDefinition(printer); } } void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { // Generate enum definitions. for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateDefinition(printer); } } void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { if (HasGenericServices(file_, options_)) { // Generate service definitions. for (int i = 0; i < service_generators_.size(); i++) { if (i > 0) { printer->Print("\n"); printer->Print(kThinSeparator); printer->Print("\n"); } service_generators_[i]->GenerateDeclarations(printer); } printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); } } void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { // Declare extension identifiers. These are in global scope and so only // the global scope extensions. for (int i = 0; i < file_->extension_count(); i++) { extension_generators_owner_[i]->GenerateDeclaration(printer); } } void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { // TODO(gerbens) remove pragmas when gcc is no longer used. Current version // of gcc fires a bogus error when compiled with strict-aliasing. printer->Print( "#ifdef __GNUC__\n" " #pragma GCC diagnostic push\n" " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" "#endif // __GNUC__\n"); // Generate class inline methods. for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print(kThinSeparator); printer->Print("\n"); } message_generators_[i]->GenerateInlineMethods(printer); } printer->Print( "#ifdef __GNUC__\n" " #pragma GCC diagnostic pop\n" "#endif // __GNUC__\n"); for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print(kThinSeparator); printer->Print("\n"); } } } void FileGenerator::GenerateProto2NamespaceEnumSpecializations( io::Printer* printer) { // Emit GetEnumDescriptor specializations into google::protobuf namespace: if (HasEnumDefinitions(file_)) { printer->Print( "\n" "namespace google {\nnamespace protobuf {\n" "\n"); for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); } printer->Print( "\n" "} // namespace protobuf\n} // namespace google\n"); } } } // namespace cpp } // namespace compiler } // namespace protobuf } // namespace google