diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
27 files changed, 1836 insertions, 730 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 48788197..13ed0b64 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -98,7 +98,8 @@ class MockGeneratorContext : public GeneratorContext { &actual_contents, true)); EXPECT_TRUE(actual_contents == *expected_contents) << physical_filename << " needs to be regenerated. Please run " - "generate_descriptor_proto.sh and add this file " + "google/protobuf/compiler/release_compiler.sh and " + "generate_descriptor_proto.sh. Then add this file " "to your CL."; } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 3ce1f120..70d3a600 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -47,7 +47,7 @@ namespace cpp { namespace { // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value -// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the +// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the // generation of the GOOGLE_ARRAYSIZE constant. bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { int32 max_value = descriptor->value(0)->number(); @@ -56,7 +56,7 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { max_value = descriptor->value(i)->number(); } } - return max_value != kint32max; + return max_value != ::google::protobuf::kint32max; } } // namespace @@ -70,19 +70,30 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} +void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) { + if (!options_.proto_h) { + return; + } + map<string, string> vars; + vars["classname"] = classname_; + printer->Print(vars, "enum $classname$ : int;\n"); + printer->Print(vars, "bool $classname$_IsValid(int value);\n"); +} + void EnumGenerator::GenerateDefinition(io::Printer* printer) { map<string, string> vars; vars["classname"] = classname_; vars["short_name"] = descriptor_->name(); + vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); - printer->Print(vars, "enum $classname$ {\n"); + printer->Print(vars, "enum $enumbase$ {\n"); printer->Indent(); const EnumValueDescriptor* min_value = descriptor_->value(0); const EnumValueDescriptor* max_value = descriptor_->value(0); for (int i = 0; i < descriptor_->value_count(); i++) { - vars["name"] = descriptor_->value(i)->name(); + vars["name"] = EnumValueName(descriptor_->value(i)); // In C++, an value of -2147483648 gets interpreted as the negative of // 2147483648, and since 2147483648 can't fit in an integer, this produces a // compiler warning. This works around that issue. @@ -113,8 +124,8 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { printer->Outdent(); printer->Print("\n};\n"); - vars["min_name"] = min_value->name(); - vars["max_name"] = max_value->name(); + vars["min_name"] = EnumValueName(min_value); + vars["max_name"] = EnumValueName(max_value); if (options_.dllexport_decl.empty()) { vars["dllexport"] = ""; @@ -153,9 +164,12 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { void EnumGenerator:: GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { + printer->Print( + "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type " + "{};\n", + "classname", ClassName(descriptor_, true)); if (HasDescriptorMethods(descriptor_->file())) { printer->Print( - "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type {};\n" "template <>\n" "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" " return $classname$_descriptor();\n" @@ -171,7 +185,7 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { printer->Print(vars, "typedef $classname$ $nested_name$;\n"); for (int j = 0; j < descriptor_->value_count(); j++) { - vars["tag"] = descriptor_->value(j)->name(); + vars["tag"] = EnumValueName(descriptor_->value(j)); printer->Print(vars, "static const $nested_name$ $tag$ = $classname$_$tag$;\n"); } @@ -275,7 +289,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { vars["parent"] = ClassName(descriptor_->containing_type(), false); vars["nested_name"] = descriptor_->name(); for (int i = 0; i < descriptor_->value_count(); i++) { - vars["value"] = descriptor_->value(i)->name(); + vars["value"] = EnumValueName(descriptor_->value(i)); printer->Print(vars, "const $classname$ $parent$::$value$;\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 1ebd7cf7..3e930856 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -60,6 +60,12 @@ class EnumGenerator { // Header stuff. + // Generate header code to forward-declare the enum. This is for use when + // generating other .proto.h files. This code should be placed within the + // enum's package namespace, but NOT within any class, even for nested + // enums. + void GenerateForwardDeclaration(io::Printer* printer); + // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for // nested enums. diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 17926135..965327b1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -76,23 +76,26 @@ GeneratePrivateMembers(io::Printer* printer) const { void EnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline $type$ $name$() const$deprecation$;\n" - "inline void set_$name$($type$ value)$deprecation$;\n"); + "$type$ $name$() const$deprecation$;\n" + "void set_$name$($type$ value)$deprecation$;\n"); } void EnumFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_);\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n"); + "$inline$ void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, + printer->Print(variables, " assert($type$_IsValid(value));\n"); } - printer->Print(variables_, + printer->Print(variables, " $set_hasbit$\n" " $name$_ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" @@ -181,21 +184,24 @@ EnumOneofFieldGenerator(const FieldDescriptor* descriptor, EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {} void EnumOneofFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return static_cast< $type$ >($oneof_prefix$$name$_);\n" " }\n" " return static_cast< $type$ >($default$);\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n"); + "$inline$ void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, + printer->Print(variables, " assert($type$_IsValid(value));\n"); } - printer->Print(variables_, + printer->Print(variables, " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -236,7 +242,7 @@ void RepeatedEnumFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField<int> $name$_;\n"); - if (descriptor_->options().packed() + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); @@ -246,46 +252,49 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline $type$ $name$(int index) const$deprecation$;\n" - "inline void set_$name$(int index, $type$ value)$deprecation$;\n" - "inline void add_$name$($type$ value)$deprecation$;\n"); + "$type$ $name$(int index) const$deprecation$;\n" + "void set_$name$(int index, $type$ value)$deprecation$;\n" + "void add_$name$($type$ value)$deprecation$;\n"); printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"); + "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" + "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"); } void RepeatedEnumFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$(int index) const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n"); + "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, + printer->Print(variables, " assert($type$_IsValid(value));\n"); } - printer->Print(variables_, + printer->Print(variables, " $name$_.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::add_$name$($type$ value) {\n"); + "$inline$ void $classname$::add_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, + printer->Print(variables, " assert($type$_IsValid(value));\n"); } - printer->Print(variables_, + printer->Print(variables, " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n"); - printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField<int>&\n" + printer->Print(variables, + "$inline$ const ::google::protobuf::RepeatedField<int>&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "inline ::google::protobuf::RepeatedField<int>*\n" + "$inline$ ::google::protobuf::RepeatedField<int>*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -343,21 +352,35 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { - if (!descriptor_->options().packed()) { - // We use a non-inlined implementation in this case, since this path will - // rarely be executed. - printer->Print(variables_, - "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" - " input,\n"); + if (!descriptor_->is_packed()) { + // This path is rarely executed, so we use a non-inlined implementation. if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables_, - " NULL,\n"); + "DO_((::google::protobuf::internal::" + "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " NULL,\n" + " NULL,\n" + " this->mutable_$name$())));\n"); + } else if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " $type$_IsValid,\n" + " mutable_unknown_fields(),\n" + " this->mutable_$name$())));\n"); } else { printer->Print(variables_, - " &$type$_IsValid,\n"); + "DO_((::google::protobuf::internal::" + "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " $type$_IsValid,\n" + " &unknown_fields_stream,\n" + " this->mutable_$name$())));\n"); } - printer->Print(variables_, - " this->mutable_$name$())));\n"); } else { printer->Print(variables_, "::google::protobuf::uint32 length;\n" @@ -376,6 +399,16 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { printer->Print(variables_, " if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" + " } else {\n"); + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(variables_, + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } else { + printer->Print(variables_, + " unknown_fields_stream.WriteVarint32(tag);\n" + " unknown_fields_stream.WriteVarint32(value);\n"); + } + printer->Print( " }\n"); } printer->Print(variables_, @@ -386,7 +419,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -399,7 +432,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" " this->$name$(i), output);\n"); @@ -413,7 +446,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -427,7 +460,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" " this->$name$(i), target);\n"); @@ -451,7 +484,7 @@ GenerateByteSize(io::Printer* printer) const { " this->$name$(i));\n" "}\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index def2b232..5b1d01ea 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -53,7 +53,8 @@ class EnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; @@ -78,7 +79,8 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator { ~EnumOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; @@ -96,7 +98,8 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index c37fe0be..1d7f8233 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -82,14 +82,40 @@ class FieldGenerator { // implementation is empty. virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {} + // Generate prototypes for accessors that will manipulate imported + // messages inline. These are for .proto.h headers. + // + // In .proto.h mode, the headers of imports are not #included. However, + // functions that manipulate the imported message types need access to + // the class definition of the imported message, meaning that the headers + // must be #included. To get around this, functions that manipulate + // imported message objects are defined as dependent functions in a base + // template class. By making them dependent template functions, the + // function templates will not be instantiated until they are called, so + // we can defer to those translation units to #include the necessary + // generated headers. + // + // See: + // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation + // + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateDependentAccessorDeclarations( + io::Printer* printer) const {} + // Generate prototypes for all of the accessor functions related to this // field. These are placed inside the class definition. virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; + // Generate inline definitions of depenent accessor functions for this field. + // These are placed inside the header after all class definitions. + virtual void GenerateDependentInlineAccessorDefinitions( + io::Printer* printer) const {} + // Generate inline definitions of accessor functions for this field. // These are placed inside the header after all class definitions. + // In non-.proto.h mode, this generates dependent accessor functions as well. virtual void GenerateInlineAccessorDefinitions( - io::Printer* printer) const = 0; + io::Printer* printer, bool is_inline) const = 0; // Generate definitions of accessors that aren't inlined. These are // placed somewhere in the .cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index fae4df40..1f0a8205 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -94,99 +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" - "#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" - "#include <google/protobuf/map_field_inl.h>\n"); - } - - if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) { - printer->Print( - "#include <google/protobuf/generated_enum_reflection.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"); @@ -196,130 +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); - } + GenerateServiceDefinitions(printer); - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); - } - - // 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"); - - // 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); - } - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateInlineFunctionDefinitions(printer); // Close up namespace. GenerateNamespaceClosers(printer); - // Emit GetEnumDescriptor specializations into google::protobuf namespace: - if (HasDescriptorMethods(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) { @@ -417,6 +242,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print(kThickSeparator); printer->Print("\n"); message_generators_[i]->GenerateClassMethods(printer); + + printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + // Generate class inline methods. + message_generators_[i]->GenerateInlineMethods(printer, + /* is_inline = */ false); + printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n"); } if (HasGenericServices(file_)) { @@ -603,20 +434,52 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); - printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); - - // Only write 40 bytes per line. - static const int kBytesPerLine = 40; - for (int i = 0; i < file_data.size(); i += kBytesPerLine) { - printer->Print("\n \"$data$\"", - "data", - EscapeTrigraphs( - CEscape(file_data.substr(i, kBytesPerLine)))); + // 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. + if (file_data.size() > 65535) { + printer->Print( + "static const char descriptor[] = {\n"); + printer->Indent(); + + // 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", SimpleItoa(file_data[i])); + } + printer->Print( + "\n"); + } + + printer->Outdent(); + printer->Print( + "};\n"); + + printer->Print( + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", + "size", SimpleItoa(file_data.size())); + + } else { + + printer->Print( + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); + + // Only write 40 bytes per line. + static const int kBytesPerLine = 40; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + printer->Print("\n \"$data$\"", + "data", + EscapeTrigraphs( + CEscape(file_data.substr(i, kBytesPerLine)))); + } + printer->Print( + ", $size$);\n", + "size", SimpleItoa(file_data.size())); + } - printer->Print( - ", $size$);\n", - "size", SimpleItoa(file_data.size())); // Call MessageFactory::InternalRegisterGeneratedFile(). printer->Print( @@ -685,6 +548,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 diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 0e06547d..e68f67bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -80,6 +80,35 @@ class FileGenerator { void GenerateNamespaceOpeners(io::Printer* printer); void GenerateNamespaceClosers(io::Printer* printer); + // Generates top or bottom of a header file. + void GenerateTopHeaderGuard(io::Printer* printer); + void GenerateBottomHeaderGuard(io::Printer* printer); + + // Generates #include directives. + void GenerateLibraryIncludes(io::Printer* printer); + void GenerateDependencyIncludes(io::Printer* printer); + + // Generates a couple of different pieces before definitions: + void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); + + // Generates types for classes. + void GenerateMessageForwardDeclarations(io::Printer* printer); + void GenerateMessageDefinitions(io::Printer* printer); + + // Generates enum definitions. + void GenerateEnumDefinitions(io::Printer* printer); + + // Generates generic service definitions. + void GenerateServiceDefinitions(io::Printer* printer); + + // Generates extension identifiers. + void GenerateExtensionIdentifiers(io::Printer* printer); + + // Generates inline function defintions. + void GenerateInlineFunctionDefinitions(io::Printer* printer); + + void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); + const FileDescriptor* file_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index c999b93f..99416372 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -82,6 +82,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, // } // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or // __declspec(dllimport) depending on what is being compiled. + // Options file_options; for (int i = 0; i < options.size(); i++) { diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 28c4dd54..0f3688d0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -51,6 +51,9 @@ namespace cpp { namespace { +static const char kAnyMessageName[] = "Any"; +static const char kAnyProtoFile[] = "google/protobuf/any.proto"; + string DotsToUnderscores(const string& name) { return StringReplace(name, ".", "_", true); } @@ -162,6 +165,10 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } +string DependentBaseClassTemplateName(const Descriptor* descriptor) { + return ClassName(descriptor, false) + "_InternalBase"; +} + string SuperClassName(const Descriptor* descriptor) { return HasDescriptorMethods(descriptor->file()) ? "::google::protobuf::Message" : "::google::protobuf::MessageLite"; @@ -176,6 +183,14 @@ string FieldName(const FieldDescriptor* field) { return result; } +string EnumValueName(const EnumValueDescriptor* enum_value) { + string result = enum_value->name(); + if (kKeywords.count(result) > 0) { + result.append("_"); + } + return result; +} + string FieldConstantName(const FieldDescriptor *field) { string field_name = UnderscoresToCamelCase(field->name(), true); string result = "k" + field_name + "FieldNumber"; @@ -192,6 +207,47 @@ string FieldConstantName(const FieldDescriptor *field) { return result; } +bool IsFieldDependent(const FieldDescriptor* field) { + if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + return false; + } + if (field->containing_oneof() != NULL) { + // Oneof fields will always be dependent. + // + // This is a unique case for field codegen. Field generators are + // responsible for generating all the field-specific accessor + // functions, except for the clear_*() function; instead, field + // generators produce inline clearing code. + // + // For non-oneof fields, the Message class uses the inline clearing + // code to define the field's clear_*() function, as well as in the + // destructor. For oneof fields, the Message class generates a much + // more complicated clear_*() function, which clears only the oneof + // member that is set, in addition to clearing methods for each of the + // oneof members individually. + // + // Since oneofs do not have their own generator class, the Message code + // generation logic would be significantly complicated in order to + // split dependent and non-dependent manipulation logic based on + // whether the oneof truly needs to be dependent; so, for oneof fields, + // we just assume it (and its constituents) should be manipulated by a + // dependent base class function. + // + // This is less precise than how dependent message-typed fields are + // handled, but the cost is limited to only the generated code for the + // oneof field, which seems like an acceptable tradeoff. + return true; + } + if (field->file() == field->message_type()->file()) { + return false; + } + return true; +} + +string DependentTypeName(const FieldDescriptor* field) { + return "InternalBase_" + field->name() + "_T"; +} + string FieldMessageTypeName(const FieldDescriptor* field) { // Note: The Google-internal version of Protocol Buffers uses this function // as a hook point for hacks to support legacy code. @@ -352,9 +408,7 @@ string FilenameIdentifier(const string& filename) { } else { // Not alphanumeric. To avoid any possibility of name conflicts we // use the hex code for the character. - result.push_back('_'); - char buffer[kFastToBufferSize]; - result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer)); + StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i]))); } } return result; @@ -508,6 +562,22 @@ bool IsStringOrMessage(const FieldDescriptor* field) { return false; } +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) { + GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); + // Open-source protobuf release only supports STRING ctype. + return FieldOptions::STRING; + +} + +bool IsAnyMessage(const FileDescriptor* descriptor) { + return descriptor->name() == kAnyProtoFile; +} + +bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->name() == kAnyMessageName && + descriptor->file()->name() == kAnyProtoFile; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index e60fa7c2..4bbf8303 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -66,6 +66,10 @@ extern const char kThinSeparator[]; string ClassName(const Descriptor* descriptor, bool qualified); string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +// Name of the CRTP class template (for use with proto_h). +// This is a class name, like "ProtoName_InternalBase". +string DependentBaseClassTemplateName(const Descriptor* descriptor); + string SuperClassName(const Descriptor* descriptor); // Get the (unqualified) name that should be used for this field in C++ code. @@ -74,6 +78,9 @@ string SuperClassName(const Descriptor* descriptor); // anyway, so normally this just returns field->name(). string FieldName(const FieldDescriptor* field); +// Get the sanitized name that should be used for the given enum in C++ code. +string EnumValueName(const EnumValueDescriptor* enum_value); + // Get the unqualified name that should be used for a field's field // number constant. string FieldConstantName(const FieldDescriptor *field); @@ -85,6 +92,20 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { field->extension_scope() : field->containing_type(); } +// Returns true if the given 'field_descriptor' has a message type that is +// a dependency of the file where the field is defined (i.e., the field +// type is defined in a different file than the message holding the field). +// +// This only applies to Message-typed fields. Enum-typed fields may refer +// to an enum in a dependency; however, enums are specified and +// forward-declared with an enum-base, so the definition is not required to +// manipulate the field value. +bool IsFieldDependent(const FieldDescriptor* field_descriptor); + +// Returns the name that should be used for forcing dependent lookup from a +// dependent base class. +string DependentTypeName(const FieldDescriptor* field); + // Returns the fully-qualified type name field->message_type(). Usually this // is just ClassName(field->message_type(), true); string FieldMessageTypeName(const FieldDescriptor* field); @@ -211,6 +232,10 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) { // Returns true if the field's CPPTYPE is string or message. bool IsStringOrMessage(const FieldDescriptor* field); +// For a string field, returns the effective ctype. If the actual ctype is +// not supported, returns the default of STRING. +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field); + string UnderscoresToCamelCase(const string& input, bool cap_next_letter); inline bool HasFieldPresence(const FileDescriptor* file) { @@ -235,6 +260,9 @@ inline bool SupportsArenas(const FieldDescriptor* field) { return SupportsArenas(field->file()); } +bool IsAnyMessage(const FileDescriptor* descriptor); +bool IsAnyMessage(const Descriptor* descriptor); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0154eeb8..0ff0d27c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -31,6 +31,7 @@ #include <google/protobuf/compiler/cpp/cpp_map_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -72,14 +73,21 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type()); (*variables)["wrapper"] = "EntryWrapper"; } - (*variables)["key_type"] = - "::google::protobuf::FieldDescriptor::TYPE_" + + (*variables)["key_wire_type"] = + "::google::protobuf::internal::WireFormatLite::TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); - (*variables)["val_type"] = - "::google::protobuf::FieldDescriptor::TYPE_" + + (*variables)["val_wire_type"] = + "::google::protobuf::internal::WireFormatLite::TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); (*variables)["map_classname"] = ClassName(descriptor->message_type(), false); - (*variables)["number"] = Int32ToString(descriptor->number()); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + + if (HasDescriptorMethods(descriptor->file())) { + (*variables)["lite"] = ""; + } else { + (*variables)["lite"] = "Lite"; + } if (!IsProto3Field(descriptor) && val->type() == FieldDescriptor::TYPE_ENUM) { @@ -102,33 +110,40 @@ MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, - "typedef ::google::protobuf::internal::MapEntry<\n" + "typedef ::google::protobuf::internal::MapEntryLite<\n" " $key_cpp$, $val_cpp$,\n" - " $key_type$,\n" - " $val_type$, $default_enum_value$>\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" + " $default_enum_value$ >\n" " $map_classname$;\n" - "::google::protobuf::internal::MapField< $key_cpp$, $val_cpp$," - "$key_type$, $val_type$, $default_enum_value$ > $name$_;\n"); + "::google::protobuf::internal::MapField$lite$<\n" + " $key_cpp$, $val_cpp$,\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" + " $default_enum_value$ > $name$_;\n"); } void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" + "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" " $name$() const$deprecation$;\n" - "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" + "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" " mutable_$name$()$deprecation$;\n"); } void MapFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_map:$full_name$)\n" " return $name$_.GetMap();\n" "}\n" - "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" + "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n" " return $name$_.MutableMap();\n" @@ -198,11 +213,29 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" " (*mutable_$name$())[entry->key()] =\n" " static_cast<$val_cpp$>(*entry->mutable_value());\n" - " } else {\n" - " mutable_unknown_fields()->AddLengthDelimited($number$, data);\n" + " } else {\n"); + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print(variables_, + " mutable_unknown_fields()" + "->AddLengthDelimited($number$, data);\n"); + } else { + printer->Print(variables_, + " unknown_fields_stream.WriteVarint32($tag$);\n" + " unknown_fields_stream.WriteVarint32(data.size());\n" + " unknown_fields_stream.WriteString(data);\n"); + } + + + printer->Print(variables_, " }\n" "}\n"); } + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "if (entry->GetArena() != NULL) entry.release();\n"); + } } void MapFieldGenerator:: @@ -211,12 +244,32 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n" + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print(variables_, " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, *entry, output);\n" - " }\n" - "}\n"); + " }\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print("}\n"); } void MapFieldGenerator:: @@ -225,13 +278,33 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n" + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print(variables_, " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" " target = ::google::protobuf::internal::WireFormatLite::\n" " Write$declared_type$NoVirtualToArray(\n" " $number$, *entry, target);\n" - " }\n" - "}\n"); + " }\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print("}\n"); } void MapFieldGenerator:: @@ -241,12 +314,32 @@ GenerateByteSize(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n" + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print(variables_, " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" " total_size += ::google::protobuf::internal::WireFormatLite::\n" " $declared_type$SizeNoVirtual(*entry);\n" - " }\n" - "}\n"); + " }\n"); + + // If entry is allocated by arena, its desctructor should be avoided. + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" + " entry.release();\n" + " }\n"); + } + + printer->Print("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 0ff032fd..d27d4851 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -50,7 +50,8 @@ class MapFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index e71d35fa..b0e38755 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -64,10 +64,15 @@ using internal::WireFormatLite; namespace { -void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { - // Print the field's proto-syntax definition as a comment. We don't want to - // print group bodies so we cut off after the first line. - string def = field->DebugString(); +template <class T> +void PrintFieldComment(io::Printer* printer, const T* field) { + // Print the field's (or oneof's) proto-syntax definition as a comment. + // We don't want to print group bodies so we cut off after the first + // line. + DebugStringOptions options; + options.elide_group_body = true; + options.elide_oneof_body = true; + string def = field->DebugStringWithOptions(options); printer->Print("// $def$\n", "def", def.substr(0, def.find_first_of('\n'))); } @@ -87,8 +92,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); i++) { fields[i] = descriptor->field(i); } - sort(fields, fields + descriptor->field_count(), - FieldOrderingByNumber()); + std::sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); return fields; } @@ -253,7 +258,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) { // Sort by preferred location to keep fields as close to their original // location as possible. Using stable_sort ensures that the output is // consistent across runs. - stable_sort(aligned_to_4.begin(), aligned_to_4.end()); + std::stable_sort(aligned_to_4.begin(), aligned_to_4.end()); // Now group fields aligned to 4 bytes (or the 4-field groups created above) // into pairs, and treat those like a single field aligned to 8 bytes. @@ -269,7 +274,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) { aligned_to_8.push_back(field_group); } // Sort by preferred location. - stable_sort(aligned_to_8.begin(), aligned_to_8.end()); + std::stable_sort(aligned_to_8.begin(), aligned_to_8.end()); // Now pull out all the FieldDescriptors in order. fields->clear(); @@ -351,11 +356,11 @@ void CollectMapInfo(const Descriptor* descriptor, default: (*variables)["val"] = PrimitiveTypeName(val->cpp_type()); } - (*variables)["key_type"] = - "::google::protobuf::FieldDescriptor::TYPE_" + + (*variables)["key_wire_type"] = + "::google::protobuf::internal::WireFormatLite::TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); - (*variables)["val_type"] = - "::google::protobuf::FieldDescriptor::TYPE_" + + (*variables)["val_wire_type"] = + "::google::protobuf::internal::WireFormatLite::TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); } @@ -383,7 +388,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, enum_generators_( new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]), extension_generators_(new google::protobuf::scoped_ptr< - ExtensionGenerator>[descriptor->extension_count()]) { + ExtensionGenerator>[descriptor->extension_count()]), + use_dependent_base_(false) { for (int i = 0; i < descriptor->nested_type_count(); i++) { nested_generators_[i].reset( @@ -405,13 +411,16 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, if (descriptor->field(i)->is_required()) { ++num_required_fields_; } + if (options.proto_h && IsFieldDependent(descriptor->field(i))) { + use_dependent_base_ = true; + } } } MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -GenerateForwardDeclaration(io::Printer* printer) { +GenerateMessageForwardDeclaration(io::Printer* printer) { printer->Print("class $classname$;\n", "classname", classname_); @@ -420,7 +429,17 @@ GenerateForwardDeclaration(io::Printer* printer) { // message cannot be a top level class, we just need to avoid calling // GenerateForwardDeclaration here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateForwardDeclaration(printer); + nested_generators_[i]->GenerateMessageForwardDeclaration(printer); + } +} + +void MessageGenerator:: +GenerateEnumForwardDeclaration(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateEnumForwardDeclaration(printer); + } + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateForwardDeclaration(printer); } } @@ -446,6 +465,35 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { } void MessageGenerator:: +GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + map<string, string> vars; + SetCommonFieldVariables(field, &vars, options_); + + if (use_dependent_base_ && IsFieldDependent(field)) { + // If the message is dependent, the inline clear_*() method will need + // to delete the message type, so it must be in the dependent base + // class. (See also GenerateFieldAccessorDeclarations.) + printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + } + // Generate type-specific accessor declarations. + field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); + printer->Print("\n"); + } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + PrintFieldComment(printer, oneof); + printer->Print( + "void clear_$oneof_name$();\n", + "oneof_name", oneof->name()); + } +} + +void MessageGenerator:: GenerateFieldAccessorDeclarations(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); @@ -456,18 +504,35 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); + bool dependent_field = use_dependent_base_ && IsFieldDependent(field); + if (dependent_field) { + // If this field is dependent, the dependent base class determines + // the message type from the derived class (which is a template + // parameter). This typedef is for that: + printer->Print( + "private:\n" + "typedef $field_type$ $dependent_type$;\n" + "public:\n", + "field_type", FieldMessageTypeName(field), + "dependent_type", DependentTypeName(field)); + } + if (field->is_repeated()) { - printer->Print(vars, "inline int $name$_size() const$deprecation$;\n"); + printer->Print(vars, "int $name$_size() const$deprecation$;\n"); } else if (HasHasMethod(field)) { - printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n"); + printer->Print(vars, "bool has_$name$() const$deprecation$;\n"); } else if (HasPrivateHasMethod(field)) { printer->Print(vars, "private:\n" - "inline bool has_$name$() const$deprecation$;\n" + "bool has_$name$() const$deprecation$;\n" "public:\n"); } - printer->Print(vars, "inline void clear_$name$()$deprecation$;\n"); + if (!dependent_field) { + // If this field is dependent, then its clear_() method is in the + // depenent base class. (See also GenerateDependentAccessorDeclarations.) + printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + } printer->Print(vars, "static const int $constant_name$ = $number$;\n"); // Generate type-specific accessor declarations. @@ -486,7 +551,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( - "inline $camel_oneof_name$Case $oneof_name$_case() const;\n", + "$camel_oneof_name$Case $oneof_name$_case() const;\n", "camel_oneof_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true), "oneof_name", descriptor_->oneof_decl(i)->name()); @@ -494,7 +559,189 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } void MessageGenerator:: -GenerateFieldAccessorDefinitions(io::Printer* printer) { +GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { + if (!use_dependent_base_) return; + + printer->Print("// $classname$\n\n", "classname", + DependentBaseClassTemplateName(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + // These functions are not really dependent: they are part of the + // (non-dependent) derived class. However, they need to live outside + // any #ifdef guards, so we treat them as if they were dependent. + // + // See the comment in FileGenerator::GenerateInlineFunctionDefinitions + // for a more complete explanation. + if (use_dependent_base_ && IsFieldDependent(field)) { + map<string, string> vars; + SetCommonFieldVariables(field, &vars, options_); + vars["inline"] = "inline "; + if (field->containing_oneof()) { + vars["field_name"] = UnderscoresToCamelCase(field->name(), true); + vars["oneof_name"] = field->containing_oneof()->name(); + vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); + GenerateOneofMemberHasBits(field, vars, printer); + } else if (!field->is_repeated()) { + // There will be no header guard, so this always has to be inline. + GenerateSingularFieldHasBits(field, vars, printer); + } + // vars needed for clear_(), which is in the dependent base: + // (See also GenerateDependentFieldAccessorDeclarations.) + vars["tmpl"] = "template<class T>\n"; + vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + "<T>"; + vars["this_message"] = "reinterpret_cast<T*>(this)->"; + vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + GenerateFieldClear(field, vars, printer); + } + + // Generate type-specific accessors. + field_generators_.get(field) + .GenerateDependentInlineAccessorDefinitions(printer); + + printer->Print("\n"); + } + + // Generate has_$name$() and clear_has_$name$() functions for oneofs + // Similar to other has-bits, these must always be in the header if we + // are using a dependent base class. + GenerateOneofHasBits(printer, true /* is_inline */); +} + +void MessageGenerator:: +GenerateSingularFieldHasBits(const FieldDescriptor* field, + map<string, string> vars, + io::Printer* printer) { + if (HasFieldPresence(descriptor_->file())) { + // N.B.: without field presence, we do not use has-bits or generate + // has_$name$() methods. + vars["has_array_index"] = SimpleItoa(field->index() / 32); + vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32), + strings::ZERO_PAD_8)); + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" + "}\n" + "$inline$" + "void $classname$::set_has_$name$() {\n" + " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" + "}\n" + "$inline$" + "void $classname$::clear_has_$name$() {\n" + " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" + "}\n"); + } else { + // Message fields have a has_$name$() method. + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + bool is_lazy = false; + if (is_lazy) { + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return !$name$_.IsCleared();\n" + "}\n"); + } else { + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return !_is_default_instance_ && $name$_ != NULL;\n" + "}\n"); + } + } + } +} + +void MessageGenerator:: +GenerateOneofHasBits(io::Printer* printer, bool is_inline) { + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + map<string, string> vars; + vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + vars["cap_oneof_name"] = + ToUpper(descriptor_->oneof_decl(i)->name()); + vars["classname"] = classname_; + vars["inline"] = (is_inline ? "inline " : ""); + printer->Print( + vars, + "$inline$" + "bool $classname$::has_$oneof_name$() const {\n" + " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" + "}\n" + "$inline$" + "void $classname$::clear_has_$oneof_name$() {\n" + " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" + "}\n"); + } +} + +void MessageGenerator:: +GenerateOneofMemberHasBits(const FieldDescriptor* field, + const map<string, string>& vars, + io::Printer* printer) { + // Singular field in a oneof + // N.B.: Without field presence, we do not use has-bits or generate + // has_$name$() methods, but oneofs still have set_has_$name$(). + // Oneofs also have has_$name$() but only as a private helper + // method, so that generated code is slightly cleaner (vs. comparing + // _oneof_case_[index] against a constant everywhere). + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return $oneof_name$_case() == k$field_name$;\n" + "}\n"); + printer->Print(vars, + "$inline$" + "void $classname$::set_has_$name$() {\n" + " _oneof_case_[$oneof_index$] = k$field_name$;\n" + "}\n"); +} + +void MessageGenerator:: +GenerateFieldClear(const FieldDescriptor* field, + const map<string, string>& vars, + io::Printer* printer) { + // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and + // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is + // set by the Generate*Definitions functions.) + printer->Print(vars, + "$tmpl$" + "$inline$" + "void $dependent_classname$::clear_$name$() {\n"); + + printer->Indent(); + + if (field->containing_oneof()) { + // Clear this field only if it is the active field in this oneof, + // otherwise ignore + printer->Print(vars, + "if ($this_message$has_$name$()) {\n"); + printer->Indent(); + field_generators_.get(field).GenerateClearingCode(printer); + printer->Print(vars, + "$this_message$clear_has_$oneof_name$();\n"); + printer->Outdent(); + printer->Print("}\n"); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + if (HasFieldPresence(descriptor_->file())) { + if (!field->is_repeated()) { + printer->Print(vars, + "$this_message$clear_has_$name$();\n"); + } + } + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { printer->Print("// $classname$\n\n", "classname", classname_); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -504,122 +751,49 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); + vars["inline"] = is_inline ? "inline " : ""; // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { printer->Print(vars, - "inline int $classname$::$name$_size() const {\n" + "$inline$" + "int $classname$::$name$_size() const {\n" " return $name$_.size();\n" "}\n"); } else if (field->containing_oneof()) { - // Singular field in a oneof - // N.B.: Without field presence, we do not use has-bits or generate - // has_$name$() methods, but oneofs still have set_has_$name$(). - // Oneofs also have has_$name$() but only as a private helper - // method, so that generated code is slightly cleaner (vs. comparing - // _oneof_case_[index] against a constant everywhere). vars["field_name"] = UnderscoresToCamelCase(field->name(), true); vars["oneof_name"] = field->containing_oneof()->name(); vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return $oneof_name$_case() == k$field_name$;\n" - "}\n"); - printer->Print(vars, - "inline void $classname$::set_has_$name$() {\n" - " _oneof_case_[$oneof_index$] = k$field_name$;\n" - "}\n"); + if (!use_dependent_base_ || !IsFieldDependent(field)) { + GenerateOneofMemberHasBits(field, vars, printer); + } } else { // Singular field. - if (HasFieldPresence(descriptor_->file())) { - // N.B.: without field presence, we do not use has-bits or generate - // has_$name$() methods. - char buffer[kFastToBufferSize]; - vars["has_array_index"] = SimpleItoa(field->index() / 32); - vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), - buffer); - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" - "}\n" - "inline void $classname$::set_has_$name$() {\n" - " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" - "}\n" - "inline void $classname$::clear_has_$name$() {\n" - " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" - "}\n" - ); - } else { - // Message fields have a has_$name$() method. - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - bool is_lazy = false; - if (is_lazy) { - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return !$name$_.IsCleared();\n" - "}\n"); - } else { - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return !_is_default_instance_ && $name$_ != NULL;\n" - "}\n"); - } - } + if (!use_dependent_base_ || !IsFieldDependent(field)) { + GenerateSingularFieldHasBits(field, vars, printer); } } - // Generate clear_$name$() - printer->Print(vars, - "inline void $classname$::clear_$name$() {\n"); - - printer->Indent(); - - if (field->containing_oneof()) { - // Clear this field only if it is the active field in this oneof, - // otherwise ignore - printer->Print(vars, - "if (has_$name$()) {\n"); - printer->Indent(); - field_generators_.get(field).GenerateClearingCode(printer); - printer->Print(vars, - "clear_has_$oneof_name$();\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - field_generators_.get(field).GenerateClearingCode(printer); - if (HasFieldPresence(descriptor_->file())) { - if (!field->is_repeated()) { - printer->Print(vars, - "clear_has_$name$();\n"); - } - } + if (!use_dependent_base_ || !IsFieldDependent(field)) { + vars["tmpl"] = ""; + vars["dependent_classname"] = vars["classname"]; + vars["this_message"] = ""; + vars["this_const_message"] = ""; + GenerateFieldClear(field, vars, printer); } - printer->Outdent(); - printer->Print("}\n"); - // Generate type-specific accessors. - field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); + field_generators_.get(field).GenerateInlineAccessorDefinitions(printer, + is_inline); printer->Print("\n"); } - // Generate has_$name$() and clear_has_$name$() functions for oneofs - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - map<string, string> vars; - vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); - vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); - vars["cap_oneof_name"] = - ToUpper(descriptor_->oneof_decl(i)->name()); - vars["classname"] = classname_; - printer->Print( - vars, - "inline bool $classname$::has_$oneof_name$() const {\n" - " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" - "}\n" - "inline void $classname$::clear_has_$oneof_name$() {\n" - " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" - "}\n"); + if (!use_dependent_base_) { + // Generate has_$name$() and clear_has_$name$() functions for oneofs + // If we aren't using a dependent base, they can be with the other functions + // that are #ifdef-guarded. + GenerateOneofHasBits(printer, is_inline); } } @@ -649,6 +823,34 @@ static bool CanClearByZeroing(const FieldDescriptor* field) { } void MessageGenerator:: +GenerateDependentBaseClassDefinition(io::Printer* printer) { + if (!use_dependent_base_) { + return; + } + + map<string, string> vars; + vars["classname"] = DependentBaseClassTemplateName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_); + + printer->Print(vars, + "template <class T>\n" + "class $classname$ : public $superclass$ {\n" + " public:\n"); + printer->Indent(); + + printer->Print(vars, + "$classname$() {}\n" + "virtual ~$classname$() {}\n" + "\n"); + + // Generate dependent accessor methods for all fields. + GenerateDependentFieldAccessorDeclarations(printer); + + printer->Outdent(); + printer->Print("};\n"); +} + +void MessageGenerator:: GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need class definition. Since map entry message @@ -661,6 +863,11 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print("\n"); } + if (use_dependent_base_) { + GenerateDependentBaseClassDefinition(printer); + printer->Print("\n"); + } + map<string, string> vars; vars["classname"] = classname_; vars["field_count"] = SimpleItoa(descriptor_->field_count()); @@ -670,11 +877,18 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = options_.dllexport_decl + " "; } - vars["superclass"] = SuperClassName(descriptor_); - + if (use_dependent_base_) { + vars["superclass"] = + DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; + } else { + vars["superclass"] = SuperClassName(descriptor_); + } printer->Print(vars, - "class $dllexport$$classname$ : public $superclass$ {\n" - " public:\n"); + "class $dllexport$$classname$ : public $superclass$ {\n"); + if (use_dependent_base_) { + printer->Print(vars, " friend class $superclass$;\n"); + } + printer->Print(" public:\n"); printer->Indent(); printer->Print(vars, @@ -783,6 +997,19 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(vars, "void UnsafeArenaSwap($classname$* other);\n"); } + + if (IsAnyMessage(descriptor_)) { + printer->Print(vars, + "// implements Any -----------------------------------------------\n" + "\n" + "void PackFrom(const ::google::protobuf::Message& message);\n" + "bool UnpackTo(::google::protobuf::Message* message) const;\n" + "template<typename T> bool Is() const {\n" + " return _any_metadata_.Is<T>();\n" + "}\n" + "\n"); + } + printer->Print(vars, "void Swap($classname$* other);\n" "\n" @@ -974,11 +1201,18 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + if (use_dependent_base_) { + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); + } else { + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "void clear_$oneof_name$();\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); + } } if (HasGeneratedMethods(descriptor_->file()) && @@ -1140,6 +1374,12 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } + // Generate _any_metadata_ for the Any type. + if (IsAnyMessage(descriptor_)) { + printer->Print(vars, + "::google::protobuf::internal::AnyMetadata _any_metadata_;\n"); + } + // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as // friends so that they can access private static variables like // default_instance_ and reflection_. @@ -1173,18 +1413,33 @@ GenerateClassDefinition(io::Printer* printer) { } void MessageGenerator:: -GenerateInlineMethods(io::Printer* printer) { +GenerateDependentInlineMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // map entry message doesn't need inline methods. Since map entry message + // cannot be a top level class, we just need to avoid calling + // GenerateInlineMethods here. + if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; + nested_generators_[i]->GenerateDependentInlineMethods(printer); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + + GenerateDependentFieldAccessorDefinitions(printer); +} + +void MessageGenerator:: +GenerateInlineMethods(io::Printer* printer, bool is_inline) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need inline methods. Since map entry message // cannot be a top level class, we just need to avoid calling // GenerateInlineMethods here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateInlineMethods(printer); + nested_generators_[i]->GenerateInlineMethods(printer, is_inline); printer->Print(kThinSeparator); printer->Print("\n"); } - GenerateFieldAccessorDefinitions(printer); + GenerateFieldAccessorDefinitions(printer, is_inline); // Generate oneof_case() functions. for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { @@ -1194,9 +1449,11 @@ GenerateInlineMethods(io::Printer* printer) { descriptor_->oneof_decl(i)->name(), true); vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + vars["inline"] = is_inline ? "inline " : ""; printer->Print( vars, - "inline $class_name$::$camel_oneof_name$Case $class_name$::" + "$inline$" + "$class_name$::$camel_oneof_name$Case $class_name$::" "$oneof_name$_case() const {\n" " return $class_name$::$camel_oneof_name$Case(" "_oneof_case_[$oneof_index$]);\n" @@ -1226,7 +1483,9 @@ GenerateDescriptorDeclarations(io::Printer* printer) { for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print(" "); - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field) != FieldOptions::STRING)) { printer->Print("const "); } field_generators_.get(field).GeneratePrivateMembers(printer); @@ -1395,8 +1654,8 @@ GenerateTypeRegistrations(io::Printer* printer) { " ::google::protobuf::internal::MapEntry<\n" " $key$,\n" " $val$,\n" - " $key_type$,\n" - " $val_type$,\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" " $default_enum_value$>::CreateDefaultInstance(\n" " $classname$_descriptor_));\n"); } @@ -1492,6 +1751,19 @@ GenerateShutdownCode(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + if (IsAnyMessage(descriptor_)) { + printer->Print( + "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" + " _any_metadata_.PackFrom(message);\n" + "}\n" + "\n" + "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" + " return _any_metadata_.UnpackTo(message);\n" + "}\n" + "\n", + "classname", classname_); + } + for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators_[i]->GenerateMethods(printer); } @@ -1765,7 +2037,7 @@ GenerateArenaDestructorCode(io::Printer* printer) { if (need_registration) { printer->Print( "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" - " if (arena != NULL) {" + " if (arena != NULL) {\n" " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" " }\n" "}\n", @@ -1780,18 +2052,23 @@ GenerateArenaDestructorCode(io::Printer* printer) { void MessageGenerator:: GenerateStructors(io::Printer* printer) { - string superclass = SuperClassName(descriptor_); - string initializer_with_arena; - if (UseUnknownFieldSet(descriptor_->file())) { - initializer_with_arena = "_internal_metadata_(arena)"; + string superclass; + if (use_dependent_base_) { + superclass = + DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - initializer_with_arena = "_arena_ptr_(arena)"; + superclass = SuperClassName(descriptor_); } + string initializer_with_arena = superclass + "()"; + if (descriptor_->extension_range_count() > 0) { - initializer_with_arena = string("\n _extensions_(arena)") + - (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena; + initializer_with_arena += ",\n _extensions_(arena)"; + } + + if (UseUnknownFieldSet(descriptor_->file())) { + initializer_with_arena += ",\n _internal_metadata_(arena)"; } else { - initializer_with_arena = "\n " + initializer_with_arena; + initializer_with_arena += ",\n _arena_ptr_(arena)"; } // Initialize member variables with arena constructor. @@ -1802,16 +2079,21 @@ GenerateStructors(io::Printer* printer) { FieldName(descriptor_->field(i)) + string("_(arena)"); } } - initializer_with_arena = superclass + "()" + - (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena; + + if (IsAnyMessage(descriptor_)) { + initializer_with_arena += ",\n _any_metadata_(&type_url, &value_)"; + } string initializer_null; initializer_null = (UseUnknownFieldSet(descriptor_->file()) ? - ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)"); + ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)"); + if (IsAnyMessage(descriptor_)) { + initializer_null += ", _any_metadata_(&type_url_, &value_)"; + } printer->Print( "$classname$::$classname$()\n" - " : $superclass$() $initializer$ {\n" + " : $superclass$()$initializer$ {\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", @@ -1892,10 +2174,14 @@ GenerateStructors(io::Printer* printer) { "full_name", descriptor_->full_name()); if (UseUnknownFieldSet(descriptor_->file())) { printer->Print( - ",\n _internal_metadata_(NULL) {\n"); + ",\n _internal_metadata_(NULL)"); } else if (!UseUnknownFieldSet(descriptor_->file())) { - printer->Print(",\n _arena_ptr_(NULL) {\n"); + printer->Print(",\n _arena_ptr_(NULL)"); + } + if (IsAnyMessage(descriptor_)) { + printer->Print(",\n _any_metadata_(&type_url_, &value_)"); } + printer->Print(" {\n"); printer->Print( " SharedCtor();\n" " MergeFrom(from);\n" @@ -2038,17 +2324,16 @@ GenerateClear(io::Printer* printer) { // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0. // The generated code uses two macros to help it clear runs of fields: - // OFFSET_OF_FIELD_ computes the offset (in bytes) of a field in the Message. + // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the + // positions of two fields in the Message. // ZR_ zeroes a non-empty range of fields via memset. const char* macros = - "#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \\\n" - " &reinterpret_cast<$classname$*>(16)->f) - \\\n" - " reinterpret_cast<char*>(16))\n\n" - "#define ZR_(first, last) do { \\\n" - " size_t f = OFFSET_OF_FIELD_(first); \\\n" - " size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \\\n" - " ::memset(&first, 0, n); \\\n" - " } while (0)\n\n"; + "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n" + " &reinterpret_cast<$classname$*>(16)->f)\n\n" + "#define ZR_(first, last) do {\\\n" + " ::memset(&first, 0,\\\n" + " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n" + "} while (0)\n\n"; for (int i = 0; i < runs_of_fields_.size(); i++) { const vector<string>& run = runs_of_fields_[i]; if (run.size() < 2) continue; @@ -2095,7 +2380,7 @@ GenerateClear(io::Printer* printer) { } else { if (HasFieldPresence(descriptor_->file())) { printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$) {\n", + "if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index", SimpleItoa(i / 8 * 8), "mask", SimpleItoa(mask)); printer->Indent(); @@ -2123,7 +2408,11 @@ GenerateClear(io::Printer* printer) { have_enclosing_if = true; } - field_generators_.get(field).GenerateClearingCode(printer); + if (use_dependent_base_ && IsFieldDependent(field)) { + printer->Print("clear_$name$();\n", "name", fieldname); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + } if (have_enclosing_if) { printer->Outdent(); @@ -2137,7 +2426,7 @@ GenerateClear(io::Printer* printer) { } if (macros_are_needed) { printer->Outdent(); - printer->Print("\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n"); + printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n"); printer->Indent(); } @@ -2146,7 +2435,11 @@ GenerateClear(io::Printer* printer) { const FieldDescriptor* field = descriptor_->field(i); if (field->is_repeated()) { - field_generators_.get(field).GenerateClearingCode(printer); + if (use_dependent_base_ && IsFieldDependent(field)) { + printer->Print("clear_$name$();\n", "name", FieldName(field)); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + } } } @@ -2183,19 +2476,38 @@ void MessageGenerator:: GenerateOneofClear(io::Printer* printer) { // Generated function clears the active field and union case (e.g. foo_case_). for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "void $classname$::clear_$oneofname$() {\n", - "classname", classname_, - "oneofname", descriptor_->oneof_decl(i)->name()); + map<string, string> oneof_vars; + oneof_vars["classname"] = classname_; + oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); + string message_class; + + if (use_dependent_base_) { + oneof_vars["tmpl"] = "template<class T>\n"; + oneof_vars["inline"] = "inline "; + oneof_vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + "<T>"; + oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->"; + message_class = "T::"; + } else { + oneof_vars["tmpl"] = ""; + oneof_vars["inline"] = ""; + oneof_vars["dependent_classname"] = classname_; + oneof_vars["this_message"] = ""; + } + + printer->Print(oneof_vars, + "$tmpl$" + "$inline$" + "void $dependent_classname$::clear_$oneofname$() {\n"); printer->Indent(); - printer->Print( - "switch($oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); + printer->Print(oneof_vars, + "switch($this_message$$oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "case k$field_name$: {\n", + "case $message_class$k$field_name$: {\n", + "message_class", message_class, "field_name", UnderscoresToCamelCase(field->name(), true)); printer->Indent(); // We clear only allocated objects in oneofs @@ -2212,16 +2524,20 @@ GenerateOneofClear(io::Printer* printer) { "}\n"); } printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + "case $message_class$$cap_oneof_name$_NOT_SET: {\n" " break;\n" "}\n", + "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n" - "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", + "$this_message$_oneof_case_[$oneof_index$] = " + "$message_class$$cap_oneof_name$_NOT_SET;\n", + "this_message", oneof_vars["this_message"], "oneof_index", SimpleItoa(i), + "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); @@ -2332,9 +2648,9 @@ GenerateMergeFrom(io::Printer* printer) { // system, as the GOOGLE_CHECK above ensured that we have the same descriptor // for each message. printer->Print( - "const $classname$* source =\n" - " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n" - " &from);\n" + "const $classname$* source = \n" + " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n" + " &from);\n" "if (source == NULL) {\n" " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" "} else {\n" @@ -2584,8 +2900,24 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Indent(); + // Find repeated messages and groups now, to simplify what follows. + hash_set<int> fields_with_parse_loop; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = ordered_fields[i]; + if (field->is_repeated() && + (field->type() == FieldDescriptor::TYPE_MESSAGE || + field->type() == FieldDescriptor::TYPE_GROUP)) { + fields_with_parse_loop.insert(i); + } + } + + // need_label is true if we generated "goto parse_$name$" while handling the + // previous field. + bool need_label = false; for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = ordered_fields[i]; + const bool loops = fields_with_parse_loop.count(i) > 0; + const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0; PrintFieldComment(printer, field); @@ -2599,14 +2931,21 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("if (tag == $commontag$) {\n", "commontag", SimpleItoa(WireFormat::MakeTag(field))); - if (i > 0 || (field->is_repeated() && !field->options().packed())) { + if (need_label || + (field->is_repeated() && !field->is_packed() && !loops)) { printer->Print( - " parse_$name$:\n", + " parse_$name$:\n", + "name", field->name()); + } + if (loops) { + printer->Print( + " DO_(input->IncrementRecursionDepth());\n" + " parse_loop_$name$:\n", "name", field->name()); } printer->Indent(); - if (field->options().packed()) { + if (field->is_packed()) { field_generator.GenerateMergeFromCodedStreamWithPacking(printer); } else { field_generator.GenerateMergeFromCodedStream(printer); @@ -2614,7 +2953,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Outdent(); // Emit code to parse unexpectedly packed or unpacked values. - if (field->is_packable() && field->options().packed()) { + if (field->is_packed()) { internal::WireFormatLite::WireType wiretype = WireFormat::WireTypeForFieldType(field->type()); printer->Print("} else if (tag == $uncommontag$) {\n", @@ -2624,7 +2963,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Indent(); field_generator.GenerateMergeFromCodedStream(printer); printer->Outdent(); - } else if (field->is_packable() && !field->options().packed()) { + } else if (field->is_packable() && !field->is_packed()) { internal::WireFormatLite::WireType wiretype = internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED; printer->Print("} else if (tag == $uncommontag$) {\n", @@ -2643,26 +2982,53 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. - if (field->is_repeated() && !field->options().packed()) { - // Expect repeats of this field. + // For non-packed repeated fields, expect the same tag again. + if (loops) { + printer->Print( + "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n", + "tag", SimpleItoa(WireFormat::MakeTag(field)), + "name", field->name()); + } else if (field->is_repeated() && !field->is_packed()) { printer->Print( "if (input->ExpectTag($tag$)) goto parse_$name$;\n", "tag", SimpleItoa(WireFormat::MakeTag(field)), "name", field->name()); } - if (i + 1 < descriptor_->field_count()) { - // Expect the next field in order. - const FieldDescriptor* next_field = ordered_fields[i + 1]; - printer->Print( - "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", - "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), - "next_name", next_field->name()); - } else { - // Expect EOF. - // TODO(kenton): Expect group end-tag? + // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet? + bool emitted_goto_next_tag = false; + + // For repeated messages/groups, we need to decrement recursion depth, + // unless the next tag is also for a repeated message/group. + if (loops) { + if (next_field_loops) { + const FieldDescriptor* next_field = ordered_fields[i + 1]; + printer->Print( + "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n", + "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), + "next_name", next_field->name()); + emitted_goto_next_tag = true; + } printer->Print( - "if (input->ExpectAtEnd()) goto success;\n"); + "input->UnsafeDecrementRecursionDepth();\n"); + } + + // If there are more fields, expect the next one. + need_label = false; + if (!emitted_goto_next_tag) { + if (i + 1 == descriptor_->field_count()) { + // Expect EOF. + // TODO(kenton): Expect group end-tag? + printer->Print( + "if (input->ExpectAtEnd()) goto success;\n"); + } else { + const FieldDescriptor* next_field = ordered_fields[i + 1]; + printer->Print( + "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", + "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), + "next_name", next_field->name()); + need_label = true; + } } printer->Print( @@ -2923,8 +3289,8 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { for (int i = 0; i < descriptor_->extension_range_count(); ++i) { sorted_extensions.push_back(descriptor_->extension_range(i)); } - sort(sorted_extensions.begin(), sorted_extensions.end(), - ExtensionRangeSorter()); + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); // Merge the fields and the extension ranges, both sorted by field number. int i, j; @@ -2998,9 +3364,7 @@ static string ConditionalToCheckBitmasks(const vector<uint32>& masks) { vector<string> parts; for (int i = 0; i < masks.size(); i++) { if (masks[i] == 0) continue; - char buffer[kFastToBufferSize]; - FastHex32ToBuffer(masks[i], buffer); - string m = StrCat("0x", buffer); + string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8)); // Each xor evaluates to 0 if the expected bits are present. parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")")); } @@ -3146,7 +3510,7 @@ GenerateByteSize(io::Printer* printer) { } else { if (HasFieldPresence(descriptor_->file())) { printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$) {\n", + "if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index", SimpleItoa(i), "mask", SimpleItoa(mask)); printer->Indent(); @@ -3292,11 +3656,10 @@ GenerateIsInitialized(io::Printer* printer) { } if (mask != 0) { - char buffer[kFastToBufferSize]; printer->Print( "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", "i", SimpleItoa(i), - "mask", FastHex32ToBuffer(mask, buffer)); + "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8))); } } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index dfbc9af5..23dad10c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -67,7 +67,8 @@ class MessageGenerator { // Header stuff. // Generate foward declarations for this class and all its nested types. - void GenerateForwardDeclaration(io::Printer* printer); + void GenerateMessageForwardDeclaration(io::Printer* printer); + void GenerateEnumForwardDeclaration(io::Printer* printer); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). @@ -82,7 +83,10 @@ class MessageGenerator { // Generate definitions of inline methods (placed at the end of the header // file). - void GenerateInlineMethods(io::Printer* printer); + void GenerateInlineMethods(io::Printer* printer, bool is_inline); + + // Dependent methods are always inline. + void GenerateDependentInlineMethods(io::Printer* printer); // Source file stuff. @@ -115,8 +119,11 @@ class MessageGenerator { private: // Generate declarations and definitions of accessors for fields. + void GenerateDependentBaseClassDefinition(io::Printer* printer); + void GenerateDependentFieldAccessorDeclarations(io::Printer* printer); void GenerateFieldAccessorDeclarations(io::Printer* printer); - void GenerateFieldAccessorDefinitions(io::Printer* printer); + void GenerateDependentFieldAccessorDefinitions(io::Printer* printer); + void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline); // Generate the field offsets array. void GenerateOffsets(io::Printer* printer); @@ -158,6 +165,21 @@ class MessageGenerator { bool unbounded); + // Generates has_foo() functions and variables for singular field has-bits. + void GenerateSingularFieldHasBits(const FieldDescriptor* field, + map<string, string> vars, + io::Printer* printer); + // Generates has_foo() functions and variables for oneof field has-bits. + void GenerateOneofHasBits(io::Printer* printer, bool is_inline); + // Generates has_foo_bar() functions for oneof members. + void GenerateOneofMemberHasBits(const FieldDescriptor* field, + const map<string, string>& vars, + io::Printer* printer); + // Generates the clear_foo() method for a field. + void GenerateFieldClear(const FieldDescriptor* field, + const map<string, string>& vars, + io::Printer* printer); + const Descriptor* descriptor_; string classname_; Options options_; @@ -168,6 +190,7 @@ class MessageGenerator { google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_; int num_required_fields_; bool uses_string_; + bool use_dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index b3cd0ba1..ba318d10 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -72,7 +72,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MessageFieldGenerator:: MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -84,77 +85,152 @@ GeneratePrivateMembers(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { +} + +void MessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "private:\n" + "void _slow_mutable_$name$()$deprecation$;\n"); + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + "void _slow_set_allocated_$name$(\n" + " ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n"); + } + printer->Print(variables_, + "$type$* _slow_$release_name$()$deprecation$;\n" + "public:\n"); + } printer->Print(variables_, - "inline const $type$& $name$() const$deprecation$;\n" - "inline $type$* mutable_$name$()$deprecation$;\n" - "inline $type$* $release_name$()$deprecation$;\n" - "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + "const $type$& $name$() const$deprecation$;\n" + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "inline $type$* unsafe_arena_release_$name$()$deprecation$;\n" - "inline void unsafe_arena_set_allocated_$name$(\n" + "$type$* unsafe_arena_release_$name$()$deprecation$;\n" + "void unsafe_arena_set_allocated_$name$(\n" " $type$* $name$)$deprecation$;\n"); } } +void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const { + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "void $classname$::_slow_mutable_$name$() {\n"); + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } + printer->Print(variables_, + "}\n" + "$type$* $classname$::_slow_$release_name$() {\n" + " if ($name$_ == NULL) {\n" + " return NULL;\n" + " } else {\n" + " $type$* temp = new $type$;\n" + " temp->MergeFrom(*$name$_);\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + "}\n" + "$type$* $classname$::unsafe_arena_release_$name$() {\n" + " $clear_hasbit$\n" + " $type$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n"); + if (SupportsArenas(descriptor_->message_type())) { + // NOTE: the same logic is mirrored in weak_message_field.cc. Any + // arena-related semantics changes should be made in both places. + printer->Print(variables_, + "void $classname$::_slow_set_allocated_$name$(\n" + " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n" + " if (message_arena != NULL && \n" + " ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n" + " message_arena->Own(*$name$);\n" + " } else if (message_arena !=\n" + " ::google::protobuf::Arena::GetArena(*$name$)) {\n" + " $type$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " message_arena);\n" + " new_$name$->CopyFrom(**$name$);\n" + " *$name$ = new_$name$;\n" + " }\n" + "}\n"); + } + printer->Print(variables_, + "void $classname$::unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$) {\n" + // If we're not on an arena, free whatever we were holding before. + // (If we are on arena, we can just forget the earlier pointer.) + " if (GetArenaNoVirtual() == NULL) {\n" + " delete $name$_;\n" + " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" + ":$full_name$)\n" + "}\n"); + } +} + void MessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\n" +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + +void MessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( - variables_, descriptor_->file(), printer, + variables, descriptor_->file(), printer, // With static initializers. " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", // Without. " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); if (SupportsArenas(descriptor_)) { - printer->Print(variables_, + printer->Print(variables, "}\n" - "inline $type$* $classname$::mutable_$name$() {\n" + "$inline$ $type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" - " if ($name$_ == NULL) {\n"); - if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); - } else { - printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); - } - printer->Print(variables_, " }\n" + " if ($name$_ == NULL) {\n" + " _slow_mutable_$name$();" + " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "inline $type$* $classname$::$release_name$() {\n" + "$inline$ $type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" - " if ($name$_ == NULL) {\n" - " return NULL;\n" - " } else {\n" - " $type$* temp = new $type$;\n" - " temp->MergeFrom(*$name$_);\n" - " $name$_ = NULL;\n" - " return temp;\n" - " }\n" + " return _slow_$release_name$();\n" " } else {\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" " }\n" "}\n" - "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" - " $clear_hasbit$\n" - " $type$* temp = $name$_;\n" - " $name$_ = NULL;\n" - " return temp;\n" - "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" - " if (GetArenaNoVirtual() == NULL) {\n" + "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n" + " if (message_arena == NULL) {\n" " delete $name$_;\n" " }\n" " if ($name$ != NULL) {\n"); @@ -164,26 +240,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { // so we might as well defer it. Otherwise, if incoming message is on a // different ownership domain (specific arena, or the heap) than we are, // copy to our arena (or heap, as the case may be). - printer->Print(variables_, - " if (GetArenaNoVirtual() != NULL && \n" - " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" - " } else if (GetArenaNoVirtual() !=\n" - " ::google::protobuf::Arena::GetArena($name$)) {\n" - " $type$* new_$name$ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n" - " new_$name$->CopyFrom(*$name$);\n" - " $name$ = new_$name$;\n" - " }\n"); + printer->Print(variables, + " _slow_set_allocated_$name$(message_arena, &$name$);\n"); } else { - printer->Print(variables_, - " if (GetArenaNoVirtual() != NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" + printer->Print(variables, + " if (message_arena != NULL) {\n" + " message_arena->Own($name$);\n" " }\n"); } - - printer->Print(variables_, + printer->Print(variables, " }\n" " $name$_ = $name$;\n" " if ($name$) {\n" @@ -192,27 +257,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $clear_hasbit$\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" - " $type$* $name$) {\n" - // If we're not on an arena, free whatever we were holding before. - // (If we are on arena, we can just forget the earlier pointer.) - " if (GetArenaNoVirtual() == NULL) {\n" - " delete $name$_;\n" - " }\n" - " $name$_ = $name$;\n" - " if ($name$) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" - ":$full_name$)\n" "}\n"); } else { - printer->Print(variables_, + printer->Print(variables, "}\n" - "inline $type$* $classname$::mutable_$name$() {\n" + "$inline$ $type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " $name$_ = new $type$;\n" @@ -220,17 +269,17 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "inline $type$* $classname$::$release_name$() {\n" + "$inline$ $type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" " delete $name$_;\n"); if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, + printer->Print(variables, " if ($name$ != NULL && $name$->GetArena() != NULL) {\n" " $type$* new_$name$ = new $type$;\n" " new_$name$->CopyFrom(*$name$);\n" @@ -238,7 +287,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " }\n"); } - printer->Print(variables_, + printer->Print(variables, " $name$_ = $name$;\n" " if ($name$) {\n" " $set_hasbit$\n" @@ -256,7 +305,7 @@ GenerateClearingCode(io::Printer* printer) const { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. printer->Print(variables_, - "if ($name$_ != NULL) delete $name$_;\n" + "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n" "$name$_ = NULL;\n"); } else { printer->Print(variables_, @@ -328,35 +377,42 @@ MessageOneofFieldGenerator(const FieldDescriptor* descriptor, MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} void MessageOneofFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + +void MessageOneofFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return has_$name$() ? *$oneof_prefix$$name$_\n" " : $type$::default_instance();\n" "}\n" - "inline $type$* $classname$::mutable_$name$() {\n" + "$inline$ $type$* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, + printer->Print(variables, " $oneof_prefix$$name$_ = \n" " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" " GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, + printer->Print(variables, " $oneof_prefix$$name$_ = \n" " ::google::protobuf::Arena::Create< $type$ >(\n" " GetArenaNoVirtual());\n"); } - printer->Print(variables_, + printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $oneof_prefix$$name$_;\n" "}\n" - "inline $type$* $classname$::$release_name$() {\n" + "$inline$ $type$* $classname$::$release_name$() {\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " if (GetArenaNoVirtual() != NULL) {\n" @@ -375,7 +431,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" + "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $oneof_prefix$$name$_;\n" @@ -385,12 +441,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" " clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, + printer->Print(variables, // If incoming message is on the heap and we are on an arena, just Own() // it (see above). If it's on a different arena than we are or one of us // is on the heap, we make a copy to our arena/heap. @@ -406,19 +462,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $name$ = new_$name$;\n" " }\n"); } else { - printer->Print(variables_, + printer->Print(variables, " if (GetArenaNoVirtual() != NULL) {\n" " GetArenaNoVirtual()->Own($name$);\n" " }\n"); } - printer->Print(variables_, + printer->Print(variables, " set_has_$name$();\n" " $oneof_prefix$$name$_ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" "$type$* $name$) {\n" // We rely on the oneof clear method to free the earlier contents of this // oneof. We can directly use the pointer we're given to set the new @@ -432,13 +488,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "$full_name$)\n" "}\n"); } else { - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return has_$name$() ? *$oneof_prefix$$name$_\n" " : $type$::default_instance();\n" "}\n" - "inline $type$* $classname$::mutable_$name$() {\n" + "$inline$ $type$* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -447,7 +503,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $oneof_prefix$$name$_;\n" "}\n" - "inline $type$* $classname$::$release_name$() {\n" + "$inline$ $type$* $classname$::$release_name$() {\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $oneof_prefix$$name$_;\n" @@ -457,18 +513,18 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" " clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, + printer->Print(variables, " if ($name$->GetArena() != NULL) {\n" " $type$* new_$name$ = new $type$;\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } - printer->Print(variables_, + printer->Print(variables, " set_has_$name$();\n" " $oneof_prefix$$name$_ = $name$;\n" " }\n" @@ -519,40 +575,51 @@ GeneratePrivateMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { +} + +void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const $type$& $name$(int index) const$deprecation$;\n" - "inline $type$* mutable_$name$(int index)$deprecation$;\n" - "inline $type$* add_$name$()$deprecation$;\n"); + "const $type$& $name$(int index) const$deprecation$;\n" + "$type$* mutable_$name$(int index)$deprecation$;\n" + "$type$* add_$name$()$deprecation$;\n"); printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" " $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "::google::protobuf::RepeatedPtrField< $type$ >*\n" " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const $type$& $classname$::$name$(int index) const {\n" +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + +void RepeatedMessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ const $type$& $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.$cppget$(index);\n" "}\n" - "inline $type$* $classname$::mutable_$name$(int index) {\n" + "$inline$ $type$* $classname$::mutable_$name$(int index) {\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable(index);\n" "}\n" - "inline $type$* $classname$::add_$name$() {\n" + "$inline$ $type$* $classname$::add_$name$() {\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" " return $name$_.Add();\n" "}\n"); - printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + printer->Print(variables, + "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -583,11 +650,13 @@ void RepeatedMessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadMessageNoVirtualNoRecursionDepth(\n" " input, add_$name$()));\n"); } else { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadGroupNoVirtualNoRecursionDepth(\n" " $number$, input, add_$name$()));\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 2dff3144..9ddf9643 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -52,8 +52,12 @@ class MessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; @@ -65,6 +69,7 @@ class MessageFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; + const bool dependent_field_; map<string, string> variables_; private: @@ -78,7 +83,10 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {} void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; @@ -95,8 +103,11 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 0c99cff1..4463f200 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -41,12 +41,13 @@ namespace protobuf { namespace compiler { namespace cpp { -// Generator options: +// Generator options (see generator.cc for a description of each): struct Options { - Options() : safe_boundary_check(false) { + Options() : safe_boundary_check(false), proto_h(false) { } string dllexport_decl; bool safe_boundary_check; + bool proto_h; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 9a2c930e..9f929d37 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -117,18 +117,20 @@ GeneratePrivateMembers(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline $type$ $name$() const$deprecation$;\n" - "inline void set_$name$($type$ value)$deprecation$;\n"); + "$type$ $name$() const$deprecation$;\n" + "void set_$name$($type$ value)$deprecation$;\n"); } void PrimitiveFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_;\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" + "$inline$ void $classname$::set_$name$($type$ value) {\n" " $set_hasbit$\n" " $name$_ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" @@ -204,16 +206,18 @@ PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} void PrimitiveOneofFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_;\n" " }\n" " return $default$;\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" + "$inline$ void $classname$::set_$name$($type$ value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -258,7 +262,7 @@ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); - if (descriptor->options().packed()) { + if (descriptor->is_packed()) { variables_["packed_reader"] = "ReadPackedPrimitive"; variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; } else { @@ -273,7 +277,7 @@ void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); - if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -282,38 +286,40 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline $type$ $name$(int index) const$deprecation$;\n" - "inline void set_$name$(int index, $type$ value)$deprecation$;\n" - "inline void add_$name$($type$ value)$deprecation$;\n"); + "$type$ $name$(int index) const$deprecation$;\n" + "void set_$name$(int index, $type$ value)$deprecation$;\n" + "void add_$name$($type$ value)$deprecation$;\n"); printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + "const ::google::protobuf::RepeatedField< $type$ >&\n" " $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedField< $type$ >*\n" + "::google::protobuf::RepeatedField< $type$ >*\n" " mutable_$name$()$deprecation$;\n"); } void RepeatedPrimitiveFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$(int index) const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ $type$ $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.Get(index);\n" "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n" + "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n" " $name$_.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::add_$name$($type$ value) {\n" + "$inline$ void $classname$::add_$name$($type$ value) {\n" " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n"); - printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + printer->Print(variables, + "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "inline ::google::protobuf::RepeatedField< $type$ >*\n" + "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -358,7 +364,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -371,7 +377,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" " this->$name$(i), output);\n"); @@ -385,7 +391,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -399,7 +405,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::\n" " Write$declared_type$NoTagToArray(this->$name$(i), target);\n"); @@ -429,7 +435,7 @@ GenerateByteSize(io::Printer* printer) const { "data_size = $fixed_size$ * this->$name$_size();\n"); } - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 97b5e867..fcd7d684 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -53,7 +53,8 @@ class PrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; @@ -78,7 +79,8 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { ~PrimitiveOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; @@ -97,7 +99,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index a8f303da..226c2aa0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -301,7 +301,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, printer->Print(vars_, " default:\n" " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" - " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n" + " return *static_cast< ::google::protobuf::Message*>(NULL);\n" " }\n" "}\n" "\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 04ed08c9..1a3896a1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -127,7 +127,11 @@ GenerateAccessorDeclarations(io::Printer* printer) const { // files that applied the ctype. The field can still be accessed via the // reflection interface since the reflection interface is independent of // the string's underlying representation. - if (descriptor_->options().ctype() != FieldOptions::STRING) { + + bool unknown_ctype = + descriptor_->options().ctype() != EffectiveStringCType(descriptor_); + + if (unknown_ctype) { printer->Outdent(); printer->Print( " private:\n" @@ -136,23 +140,23 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "inline const ::std::string& $name$() const$deprecation$;\n" - "inline void set_$name$(const ::std::string& value)$deprecation$;\n" - "inline void set_$name$(const char* value)$deprecation$;\n" - "inline void set_$name$(const $pointer_type$* value, size_t size)" + "const ::std::string& $name$() const$deprecation$;\n" + "void set_$name$(const ::std::string& value)$deprecation$;\n" + "void set_$name$(const char* value)$deprecation$;\n" + "void set_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n" - "inline ::std::string* mutable_$name$()$deprecation$;\n" - "inline ::std::string* $release_name$()$deprecation$;\n" - "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); + "::std::string* mutable_$name$()$deprecation$;\n" + "::std::string* $release_name$()$deprecation$;\n" + "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "inline ::std::string* unsafe_arena_release_$name$()$deprecation$;\n" - "inline void unsafe_arena_set_allocated_$name$(\n" + "::std::string* unsafe_arena_release_$name$()$deprecation$;\n" + "void unsafe_arena_set_allocated_$name$(\n" " ::std::string* $name$)$deprecation$;\n"); } - if (descriptor_->options().ctype() != FieldOptions::STRING) { + if (unknown_ctype) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -160,25 +164,28 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } void StringFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.Get($default_variable$);\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" " $set_hasbit$\n" " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" + "$inline$ void $classname$::set_$name$(const char* value) {\n" " $set_hasbit$\n" " $name$_.Set($default_variable$, $string_piece$(value),\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "inline " + "$inline$ " "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" " $set_hasbit$\n" @@ -186,22 +193,22 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "$inline$ ::std::string* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "$inline$ ::std::string* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" "}\n" - "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " $clear_hasbit$\n" " return $name$_.UnsafeArenaRelease($default_variable$,\n" " GetArenaNoVirtual());\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -211,7 +218,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n" " ::std::string* $name$) {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if ($name$ != NULL) {\n" @@ -219,29 +226,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " } else {\n" " $clear_hasbit$\n" " }\n" - " $set_hasbit$\n" " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" " $name$, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); } else { // No-arena case. - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.GetNoArena($default_variable$);\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" + "$inline$ void $classname$::set_$name$(const char* value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "inline " + "$inline$ " "void $classname$::set_$name$(const $pointer_type$* value, " "size_t size) {\n" " $set_hasbit$\n" @@ -249,16 +255,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $string_piece$(reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "$inline$ ::std::string* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.MutableNoArena($default_variable$);\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "$inline$ ::std::string* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " return $name$_.ReleaseNoArena($default_variable$);\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -422,17 +428,20 @@ StringOneofFieldGenerator(const FieldDescriptor* descriptor, StringOneofFieldGenerator::~StringOneofFieldGenerator() {} void StringOneofFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_.Get($default_variable$);\n" " }\n" " return *$default_variable$;\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -442,7 +451,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" + "$inline$ void $classname$::set_$name$(const char* value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -452,7 +461,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $string_piece$(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "inline " + "$inline$ " "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" " if (!has_$name$()) {\n" @@ -465,7 +474,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "$inline$ ::std::string* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -475,7 +484,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "$inline$ ::std::string* $classname$::$release_name$() {\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.Release($default_variable$,\n" @@ -484,7 +493,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -494,7 +503,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" @@ -506,7 +515,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" "::std::string* $name$) {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (!has_$name$()) {\n" @@ -522,15 +531,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n"); } else { // No-arena case. - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + printer->Print(variables, + "$inline$ const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n" " }\n" " return *$default_variable$;\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -540,7 +549,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" + "$inline$ void $classname$::set_$name$(const char* value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -550,7 +559,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "inline " + "$inline$ " "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -561,7 +570,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "$inline$ ::std::string* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -570,7 +579,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "$inline$ ::std::string* $classname$::$release_name$() {\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" @@ -578,7 +587,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" @@ -670,7 +679,10 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { // See comment above about unknown ctypes. - if (descriptor_->options().ctype() != FieldOptions::STRING) { + bool unknown_ctype = + descriptor_->options().ctype() != EffectiveStringCType(descriptor_); + + if (unknown_ctype) { printer->Outdent(); printer->Print( " private:\n" @@ -679,26 +691,26 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "inline const ::std::string& $name$(int index) const$deprecation$;\n" - "inline ::std::string* mutable_$name$(int index)$deprecation$;\n" - "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n" - "inline void set_$name$(int index, const char* value)$deprecation$;\n" - "inline " + "const ::std::string& $name$(int index) const$deprecation$;\n" + "::std::string* mutable_$name$(int index)$deprecation$;\n" + "void set_$name$(int index, const ::std::string& value)$deprecation$;\n" + "void set_$name$(int index, const char* value)$deprecation$;\n" + "" "void set_$name$(int index, const $pointer_type$* value, size_t size)" "$deprecation$;\n" - "inline ::std::string* add_$name$()$deprecation$;\n" - "inline void add_$name$(const ::std::string& value)$deprecation$;\n" - "inline void add_$name$(const char* value)$deprecation$;\n" - "inline void add_$name$(const $pointer_type$* value, size_t size)" + "::std::string* add_$name$()$deprecation$;\n" + "void add_$name$(const ::std::string& value)$deprecation$;\n" + "void add_$name$(const char* value)$deprecation$;\n" + "void add_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n"); printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" + "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" "$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" "$deprecation$;\n"); - if (descriptor_->options().ctype() != FieldOptions::STRING) { + if (unknown_ctype) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -706,54 +718,57 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$(int index) const {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline" : ""; + printer->Print(variables, + "$inline$ const ::std::string& $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.$cppget$(index);\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$(int index) {\n" + "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable(index);\n" "}\n" - "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n" + "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " $name$_.Mutable(index)->assign(value);\n" "}\n" - "inline void $classname$::set_$name$(int index, const char* value) {\n" + "$inline$ void $classname$::set_$name$(int index, const char* value) {\n" " $name$_.Mutable(index)->assign(value);\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "inline void " + "$inline$ void " "$classname$::set_$name$" "(int index, const $pointer_type$* value, size_t size) {\n" " $name$_.Mutable(index)->assign(\n" " reinterpret_cast<const char*>(value), size);\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::add_$name$() {\n" + "$inline$ ::std::string* $classname$::add_$name$() {\n" " return $name$_.Add();\n" "}\n" - "inline void $classname$::add_$name$(const ::std::string& value) {\n" + "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n" " $name$_.Add()->assign(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n" - "inline void $classname$::add_$name$(const char* value) {\n" + "$inline$ void $classname$::add_$name$(const char* value) {\n" " $name$_.Add()->assign(value);\n" " // @@protoc_insertion_point(field_add_char:$full_name$)\n" "}\n" - "inline void " + "$inline$ void " "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" "}\n"); - printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" + printer->Print(variables, + "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" + "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 0a5ca440..d1f19cd9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -54,7 +54,8 @@ class StringFieldGenerator : public FieldGenerator { void GeneratePrivateMembers(io::Printer* printer) const; void GenerateStaticMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; @@ -83,7 +84,8 @@ class StringOneofFieldGenerator : public StringFieldGenerator { ~StringOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; @@ -103,7 +105,8 @@ class RepeatedStringFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index 4fa3c144..4e25b2ea 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -131,6 +131,24 @@ message TestConflictingSymbolNamesExtension { // NO_PROTO3 } // NO_PROTO3 } // NO_PROTO3 +message TestConflictingEnumNames { // NO_PROTO3 + enum NestedConflictingEnum { // NO_PROTO3 + and = 1; // NO_PROTO3 + class = 2; // NO_PROTO3 + int = 3; // NO_PROTO3 + typedef = 4; // NO_PROTO3 + XOR = 5; // NO_PROTO3 + } // NO_PROTO3 + + optional NestedConflictingEnum conflicting_enum = 1; // NO_PROTO3 +} // NO_PROTO3 + +enum ConflictingEnum { // NO_PROTO3 + NOT_EQ = 1; // NO_PROTO3 + volatile = 2; // NO_PROTO3 + return = 3; // NO_PROTO3 +} // NO_PROTO3 + message DummyMessage {} service TestConflictingMethodNames { diff --git a/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto new file mode 100644 index 00000000..cb6ca1b1 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto @@ -0,0 +1,43 @@ +// 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. + +// Test that proto2 compiler can generate valid code when the enum value +// is INT_MAX. Note that this is a compile-only test and this proto is not +// referenced in any C++ code. +syntax = "proto2"; + +package protobuf_unittest; + +message TestLargeEnumValue { + enum EnumWithLargeValue { + VALUE_1 = 1; + VALUE_MAX = 0x7fffffff; + } +} diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 2a04b293..bd1c0fde 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -55,6 +55,7 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_optimize_for.pb.h> #include <google/protobuf/unittest_embed_optimize_for.pb.h> +#include <google/protobuf/unittest_enormous_descriptor.pb.h> #include <google/protobuf/unittest_no_generic_services.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> @@ -130,6 +131,17 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) { generated_decsriptor_proto.DebugString()); } +// Test that generated code has proper descriptors: +// Touch a descriptor generated from an enormous message to validate special +// handling for descriptors exceeding the C++ standard's recommended minimum +// limit for string literal size +TEST(GeneratedDescriptorTest, EnormousDescriptor) { + const Descriptor* generated_descriptor = + TestEnormousDescriptor::descriptor(); + + EXPECT_TRUE(generated_descriptor != NULL); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS // =================================================================== @@ -794,6 +806,21 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) { message.GetExtension(ExtensionMessage::repeated_int32_ext, 0)); } +TEST(GeneratedMessageTest, TestConflictingEnumNames) { + protobuf_unittest::TestConflictingEnumNames message; + message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_); + EXPECT_EQ(1, message.conflicting_enum()); + message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR); + EXPECT_EQ(5, message.conflicting_enum()); + + + protobuf_unittest::ConflictingEnum conflicting_enum; + conflicting_enum = protobuf_unittest::NOT_EQ; + EXPECT_EQ(1, conflicting_enum); + conflicting_enum = protobuf_unittest::return_; + EXPECT_EQ(3, conflicting_enum); +} + #ifndef PROTOBUF_TEST_NO_DESCRIPTORS TEST(GeneratedMessageTest, TestOptimizedForSize) { @@ -926,6 +953,22 @@ TEST(GeneratedMessageTest, ExtensionConstantValues) { EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51); } +TEST(GeneratedMessageTest, ParseFromTruncated) { + const string long_string = string(128, 'q'); + FileDescriptorProto p; + p.add_extension()->set_name(long_string); + const string msg = p.SerializeAsString(); + int successful_count = 0; + for (int i = 0; i <= msg.size(); i++) { + if (p.ParseFromArray(msg.c_str(), i)) { + ++successful_count; + } + } + // We don't really care about how often we succeeded. + // As long as we didn't crash, we're happy. + EXPECT_GE(successful_count, 1); +} + // =================================================================== TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) { @@ -1377,6 +1420,12 @@ class OneofTest : public testing::Test { case unittest::TestOneof2::kFooString: EXPECT_TRUE(message.has_foo_string()); break; + case unittest::TestOneof2::kFooCord: + EXPECT_TRUE(message.has_foo_cord()); + break; + case unittest::TestOneof2::kFooStringPiece: + EXPECT_TRUE(message.has_foo_string_piece()); + break; case unittest::TestOneof2::kFooBytes: EXPECT_TRUE(message.has_foo_bytes()); break; @@ -1389,6 +1438,9 @@ class OneofTest : public testing::Test { case unittest::TestOneof2::kFoogroup: EXPECT_TRUE(message.has_foogroup()); break; + case unittest::TestOneof2::kFooLazyMessage: + EXPECT_TRUE(message.has_foo_lazy_message()); + break; case unittest::TestOneof2::FOO_NOT_SET: break; } diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto new file mode 100644 index 00000000..cb6ca1b1 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto @@ -0,0 +1,43 @@ +// 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. + +// Test that proto2 compiler can generate valid code when the enum value +// is INT_MAX. Note that this is a compile-only test and this proto is not +// referenced in any C++ code. +syntax = "proto2"; + +package protobuf_unittest; + +message TestLargeEnumValue { + enum EnumWithLargeValue { + VALUE_1 = 1; + VALUE_MAX = 0x7fffffff; + } +} |