diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_file.cc')
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_file.cc | 505 |
1 files changed, 301 insertions, 204 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index a98c7d92..b997a51a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -94,113 +94,10 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} void FileGenerator::GenerateHeader(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); - - // Generate top of header. - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" - "#define PROTOBUF_$filename_identifier$__INCLUDED\n" - "\n" - "#include <string>\n" - "\n", - "filename", file_->name(), - "filename_identifier", filename_identifier); - - - printer->Print( - "#include <google/protobuf/stubs/common.h>\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 <google/protobuf/arena.h>\n" - "#include <google/protobuf/arenastring.h>\n" - "#include <google/protobuf/generated_message_util.h>\n"); - if (UseUnknownFieldSet(file_)) { - printer->Print( - "#include <google/protobuf/metadata.h>\n"); - } - if (file_->message_type_count() > 0) { - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include <google/protobuf/message.h>\n"); - } else { - printer->Print( - "#include <google/protobuf/message_lite.h>\n"); - } - } - printer->Print( - "#include <google/protobuf/repeated_field.h>\n" - "#include <google/protobuf/extension_set.h>\n"); - if (HasMapFields(file_)) { - printer->Print( - "#include <google/protobuf/map.h>\n"); - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include <google/protobuf/map_field_inl.h>\n"); - } else { - printer->Print( - "#include <google/protobuf/map_field_lite.h>\n"); - } - } - - if (HasEnumDefinitions(file_)) { - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include <google/protobuf/generated_enum_reflection.h>\n"); - } else { - printer->Print( - "#include <google/protobuf/generated_enum_util.h>\n"); - } - } - - if (HasGenericServices(file_)) { - printer->Print( - "#include <google/protobuf/service.h>\n"); - } - - if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { - printer->Print( - "#include <google/protobuf/unknown_field_set.h>\n"); - } - - - set<string> 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 string& name = file_->dependency(i)->name(); - bool public_import = (public_import_names.count(name) != 0); + GenerateTopHeaderGuard(printer); - - printer->Print( - "#include \"$dependency$.pb.h\"$iwyu$\n", - "dependency", StripProto(name), - "iwyu", (public_import) ? " // IWYU pragma: export" : ""); - } + GenerateLibraryIncludes(printer); + GenerateDependencyIncludes(printer); printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -210,132 +107,44 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Open namespace. GenerateNamespaceOpeners(printer); - // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile - // functions, so that we can declare them to be friends of each class. - printer->Print( - "\n" - "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$$adddescriptorsname$();\n", - "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - - printer->Print( - // Note that we don't put dllexport_decl on these because they are only - // called by the .pb.cc file in which they are defined. - "void $assigndescriptorsname$();\n" - "void $shutdownfilename$();\n" - "\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), - "shutdownfilename", GlobalShutdownFileName(file_->name())); - - // Generate forward declarations of classes. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateForwardDeclaration(printer); - } + GenerateGlobalStateFunctionDeclarations(printer); + GenerateMessageForwardDeclarations(printer); printer->Print("\n"); - // Generate enum definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateEnumDefinitions(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { - enum_generators_[i]->GenerateDefinition(printer); - } + GenerateEnumDefinitions(printer); printer->Print(kThickSeparator); printer->Print("\n"); - // Generate class definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - if (i > 0) { - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - message_generators_[i]->GenerateClassDefinition(printer); - } + GenerateMessageDefinitions(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); - if (HasGenericServices(file_)) { - // Generate service definitions. - for (int i = 0; i < file_->service_count(); 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"); - } + GenerateServiceDefinitions(printer); - // Declare extension identifiers. - for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_[i]->GenerateDeclaration(printer); - } + GenerateExtensionIdentifiers(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); - printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - // Generate class inline methods. - for (int i = 0; i < file_->message_type_count(); i++) { - if (i > 0) { - printer->Print(kThinSeparator); - printer->Print("\n"); - } - message_generators_[i]->GenerateInlineMethods(printer, - /* is_inline = */ true); - } - printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateInlineFunctionDefinitions(printer); // Close up namespace. GenerateNamespaceClosers(printer); - // Emit GetEnumDescriptor specializations into google::protobuf namespace: - if (HasEnumDefinitions(file_)) { - // The SWIG conditional is to avoid a null-pointer dereference - // (bug 1984964) in swig-1.3.21 resulting from the following syntax: - // namespace X { void Y<Z::W>(); } - // which appears in GetEnumDescriptor() specializations. - printer->Print( - "\n" - "#ifndef SWIG\n" - "namespace google {\nnamespace protobuf {\n" - "\n"); - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { - enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - printer->Print( - "\n" - "} // namespace protobuf\n} // namespace google\n" - "#endif // SWIG\n"); - } + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n" "\n"); - printer->Print( - "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", - "filename_identifier", filename_identifier); + GenerateBottomHeaderGuard(printer); } void FileGenerator::GenerateSource(io::Printer* printer) { @@ -707,6 +516,294 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { } } +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { + string filename_identifier = FilenameIdentifier(file_->name()); + // Generate top of header. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" + "#define PROTOBUF_$filename_identifier$__INCLUDED\n" + "\n" + "#include <string>\n" + "\n", + "filename", file_->name(), + "filename_identifier", filename_identifier); +} + +void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) { + string filename_identifier = FilenameIdentifier(file_->name()); + printer->Print( + "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", + "filename_identifier", filename_identifier); +} + +void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { + + printer->Print( + "#include <google/protobuf/stubs/common.h>\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 <google/protobuf/arena.h>\n" + "#include <google/protobuf/arenastring.h>\n" + "#include <google/protobuf/generated_message_util.h>\n"); + if (UseUnknownFieldSet(file_)) { + printer->Print( + "#include <google/protobuf/metadata.h>\n"); + } + if (file_->message_type_count() > 0) { + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include <google/protobuf/message.h>\n"); + } else { + printer->Print( + "#include <google/protobuf/message_lite.h>\n"); + } + } + printer->Print( + "#include <google/protobuf/repeated_field.h>\n" + "#include <google/protobuf/extension_set.h>\n"); + if (HasMapFields(file_)) { + printer->Print( + "#include <google/protobuf/map.h>\n"); + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include <google/protobuf/map_field_inl.h>\n"); + } else { + printer->Print( + "#include <google/protobuf/map_field_lite.h>\n"); + } + } + + if (HasEnumDefinitions(file_)) { + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include <google/protobuf/generated_enum_reflection.h>\n"); + } else { + printer->Print( + "#include <google/protobuf/generated_enum_util.h>\n"); + } + } + + if (HasGenericServices(file_)) { + printer->Print( + "#include <google/protobuf/service.h>\n"); + } + + if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + printer->Print( + "#include <google/protobuf/unknown_field_set.h>\n"); + } + + + if (IsAnyMessage(file_)) { + printer->Print( + "#include \"google/protobuf/any.h\"\n"); + } +} + +void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { + set<string> 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 string& name = file_->dependency(i)->name(); + bool public_import = (public_import_names.count(name) != 0); + + + printer->Print( + "#include \"$dependency$.pb.h\"$iwyu$\n", + "dependency", StripProto(name), + "iwyu", (public_import) ? " // IWYU pragma: export" : ""); + } +} + +void FileGenerator::GenerateGlobalStateFunctionDeclarations( + io::Printer* printer) { + // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile + // functions, so that we can declare them to be friends of each class. + printer->Print( + "\n" + "// Internal implementation detail -- do not call these.\n" + "void $dllexport_decl$$adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + + printer->Print( + // Note that we don't put dllexport_decl on these because they are only + // called by the .pb.cc file in which they are defined. + "void $assigndescriptorsname$();\n" + "void $shutdownfilename$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), + "shutdownfilename", GlobalShutdownFileName(file_->name())); +} + +void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateMessageForwardDeclaration(printer); + } +} + +void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { + // Generate class definitions. + for (int i = 0; i < file_->message_type_count(); 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 < file_->message_type_count(); i++) { + message_generators_[i]->GenerateEnumDefinitions(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDefinition(printer); + } +} + +void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { + if (HasGenericServices(file_)) { + // Generate service definitions. + for (int i = 0; i < file_->service_count(); 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. + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateDeclaration(printer); + } +} + +void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { + // An aside about inline functions in .proto.h mode: + // + // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally + // moving much of the inline functions to the .pb.cc file, which can be a + // significant performance benefit for compilation time, at the expense + // of non-inline function calls. + // + // However, in .proto.h mode, the definition of the internal dependent + // base class must remain in the header, and can never be out-lined. The + // dependent base class also needs access to has-bit manipuation + // functions, so the has-bit functions must be unconditionally inlined in + // proto_h mode. + // + // This gives us three flavors of functions: + // + // 1. Functions on the message not used by the internal dependent base + // class: in .proto.h mode, only some functions are defined on the + // message class; others are defined on the dependent base class. + // These are guarded and can be out-lined. These are generated by + // GenerateInlineMethods, and include has_* bit functions in + // non-proto_h mode. + // + // 2. Functions on the internal dependent base class: these functions + // are dependent on a template parameter, so they always need to + // remain in the header. + // + // 3. Functions on the message that are used by the dependent base: the + // dependent base class down casts itself to the message + // implementation class to access these functions (the has_* bit + // manipulation functions). Unlike #1, these functions must + // unconditionally remain in the header. These are emitted by + // GenerateDependentInlineMethods, even though they are not actually + // dependent. + + printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + // Generate class inline methods. + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print(kThinSeparator); + printer->Print("\n"); + } + message_generators_[i]->GenerateInlineMethods(printer, + /* is_inline = */ true); + } + printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print(kThinSeparator); + printer->Print("\n"); + } + // Methods of the dependent base class must always be inline in the header. + message_generators_[i]->GenerateDependentInlineMethods(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); +} + +void FileGenerator::GenerateProto2NamespaceEnumSpecializations( + io::Printer* printer) { + // Emit GetEnumDescriptor specializations into google::protobuf namespace: + if (HasEnumDefinitions(file_)) { + // The SWIG conditional is to avoid a null-pointer dereference + // (bug 1984964) in swig-1.3.21 resulting from the following syntax: + // namespace X { void Y<Z::W>(); } + // which appears in GetEnumDescriptor() specializations. + printer->Print( + "\n" + "#ifndef SWIG\n" + "namespace google {\nnamespace protobuf {\n" + "\n"); + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + printer->Print( + "\n" + "} // namespace protobuf\n} // namespace google\n" + "#endif // SWIG\n"); + } +} + } // namespace cpp } // namespace compiler } // namespace protobuf |