diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
27 files changed, 3693 insertions, 3867 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index f99159f5..4e150fe3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -44,6 +44,7 @@ #include <map> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/importer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -97,9 +98,10 @@ class MockGeneratorContext : public GeneratorContext { File::GetContents(TestSourceDir() + "/" + physical_filename, &actual_contents, true)); EXPECT_TRUE(actual_contents == *expected_contents) - << physical_filename << " needs to be regenerated. Please run " - "generate_descriptor_proto.sh. Then add this file " - "to your CL."; + << physical_filename + << " needs to be regenerated. Please run " + "generate_descriptor_proto.sh. " + "Then add this file to your CL."; } // implements GeneratorContext -------------------------------------- @@ -116,37 +118,50 @@ class MockGeneratorContext : public GeneratorContext { std::map<string, string*> files_; }; -TEST(BootstrapTest, GeneratedDescriptorMatches) { - MockErrorCollector error_collector; +const char kDescriptorParameter[] = "dllexport_decl=LIBPROTOBUF_EXPORT"; +const char kPluginParameter[] = "dllexport_decl=LIBPROTOC_EXPORT"; +const char kNormalParameter[] = ""; + +const char* test_protos[][2] = { + {"google/protobuf/descriptor", kDescriptorParameter}, + {"google/protobuf/compiler/plugin", kPluginParameter}, +}; + +TEST(BootstrapTest, GeneratedFilesMatch) { + // We need a mapping from the actual file to virtual and actual path + // of the data to compare to. + std::map<string, string> vpath_map; + std::map<string, string> rpath_map; + rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto2"] = + "net/proto2/z_generated_example/test_messages_proto2"; + rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto3"] = + "net/proto2/z_generated_example/test_messages_proto3"; + rpath_map["google/protobuf/proto2_weak"] = + "net/proto2/z_generated_example/proto2_weak"; + DiskSourceTree source_tree; source_tree.MapPath("", TestSourceDir()); - Importer importer(&source_tree, &error_collector); - const FileDescriptor* proto_file = - importer.Import("google/protobuf/descriptor.proto"); - const FileDescriptor* plugin_proto_file = - importer.Import("google/protobuf/compiler/plugin.proto"); - EXPECT_EQ("", error_collector.text_); - ASSERT_TRUE(proto_file != NULL); - ASSERT_TRUE(plugin_proto_file != NULL); - - CppGenerator generator; - MockGeneratorContext context; - string error; - string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; - ASSERT_TRUE(generator.Generate(proto_file, parameter, - &context, &error)); - parameter = "dllexport_decl=LIBPROTOC_EXPORT"; - ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, - &context, &error)); - - context.ExpectFileMatches("google/protobuf/descriptor.pb.h", - "google/protobuf/descriptor.pb.h"); - context.ExpectFileMatches("google/protobuf/descriptor.pb.cc", - "google/protobuf/descriptor.pb.cc"); - context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h", - "google/protobuf/compiler/plugin.pb.h"); - context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", - "google/protobuf/compiler/plugin.pb.cc"); + + for (auto file_parameter : test_protos) { + MockErrorCollector error_collector; + Importer importer(&source_tree, &error_collector); + const FileDescriptor* file = + importer.Import(file_parameter[0] + string(".proto")); + ASSERT_TRUE(file != nullptr) + << "Can't import file " << file_parameter[0] + string(".proto") << "\n"; + EXPECT_EQ("", error_collector.text_); + CppGenerator generator; + MockGeneratorContext context; + string error; + ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error)); + + string vpath = + FindWithDefault(vpath_map, file_parameter[0], file_parameter[0]); + string rpath = + FindWithDefault(rpath_map, file_parameter[0], file_parameter[0]); + context.ExpectFileMatches(vpath + ".pb.cc", rpath + ".pb.cc"); + context.ExpectFileMatches(vpath + ".pb.h", rpath + ".pb.h"); + } } } // namespace diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 8adee0f5..0d6a9e24 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -179,7 +179,7 @@ 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 " + "template <> struct is_proto_enum< $classname$> : ::std::true_type " "{};\n", "classname", ClassName(descriptor_, true)); if (HasDescriptorMethods(descriptor_->file(), options_)) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 3d5b5b8d..828d0be5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -128,7 +128,7 @@ GenerateCopyConstructorCode(io::Printer* printer) const { void EnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, - "int value;\n" + "int value = 0;\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" " input, &value)));\n"); @@ -195,7 +195,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "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" + " return static_cast< $type$ >($field_member$);\n" " }\n" " return static_cast< $type$ >($default$);\n" "}\n" @@ -209,14 +209,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " clear_$oneof_name$();\n" " set_has_$name$();\n" " }\n" - " $oneof_prefix$$name$_ = value;\n" + " $field_member$ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); } void EnumOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n"); + printer->Print(variables_, "$field_member$ = $default$;\n"); } void EnumOneofFieldGenerator:: @@ -334,7 +334,7 @@ void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { // Don't use ReadRepeatedPrimitive here so that the enum can be validated. printer->Print(variables_, - "int value;\n" + "int value = 0;\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" " input, &value)));\n"); @@ -399,7 +399,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { "::google::protobuf::io::CodedInputStream::Limit limit = " "input->PushLimit(static_cast<int>(length));\n" "while (input->BytesUntilLimit() > 0) {\n" - " int value;\n" + " int value = 0;\n" " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" " input, &value)));\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 0a4e0bb9..c416ba10 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -35,8 +35,8 @@ #include <google/protobuf/compiler/cpp/cpp_extension.h> #include <map> #include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> @@ -120,7 +120,6 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" " $name$;\n" ); - } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index f8e11855..0de20f84 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -34,21 +34,18 @@ #include <google/protobuf/compiler/cpp/cpp_field.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_primitive_field.h> #include <google/protobuf/compiler/cpp/cpp_string_field.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_enum_field.h> #include <google/protobuf/compiler/cpp/cpp_map_field.h> #include <google/protobuf/compiler/cpp/cpp_message_field.h> #include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/wire_format.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> +#include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -67,12 +64,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["classname"] = ClassName(FieldScope(descriptor), false); (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); - - // non_null_ptr_to_name is usable only if has_$name$ is true. It yields a - // pointer that will not be NULL. Subclasses of FieldGenerator may set - // (*variables)["non_null_ptr_to_name"] differently. - (*variables)["non_null_ptr_to_name"] = - StrCat("&this->", FieldName(descriptor), "()"); + (*variables)["field_member"] = FieldName(descriptor) + "_"; (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); @@ -81,8 +73,6 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["deprecated_attr"] = descriptor->options().deprecated() ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : ""; - (*variables)["cppget"] = "Get"; - if (HasFieldPresence(descriptor->file())) { (*variables)["set_hasbit"] = "set_has_" + FieldName(descriptor) + "();"; @@ -93,10 +83,6 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["clear_hasbit"] = ""; } - // By default, empty string, so that generic code used for both oneofs and - // singular fields can be written. - (*variables)["oneof_prefix"] = ""; - // These variables are placeholders to pick out the beginning and ends of // identifiers for annotations (when doing so with existing variables would // be ambiguous or impossible). They should never be set to anything but the @@ -108,10 +94,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables) { const string prefix = descriptor->containing_oneof()->name() + "_."; - (*variables)["oneof_prefix"] = prefix; (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); - (*variables)["non_null_ptr_to_name"] = - StrCat(prefix, (*variables)["name"], "_"); + (*variables)["field_member"] = StrCat(prefix, (*variables)["name"], "_"); } FieldGenerator::~FieldGenerator() {} @@ -129,26 +113,29 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { } FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, - const Options& options) + const Options& options, + SCCAnalyzer* scc_analyzer) : descriptor_(descriptor), options_(options), - field_generators_( - new google::protobuf::scoped_ptr<FieldGenerator>[descriptor->field_count()]) { + field_generators_(descriptor->field_count()) { // Construct all the FieldGenerators. for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(MakeGenerator(descriptor->field(i), options)); + field_generators_[i].reset( + MakeGenerator(descriptor->field(i), options, scc_analyzer)); } } FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, - const Options& options) { + const Options& options, + SCCAnalyzer* scc_analyzer) { if (field->is_repeated()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: if (field->is_map()) { return new MapFieldGenerator(field, options); } else { - return new RepeatedMessageFieldGenerator(field, options); + return new RepeatedMessageFieldGenerator(field, options, + scc_analyzer); } case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { @@ -164,7 +151,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, } else if (field->containing_oneof()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageOneofFieldGenerator(field, options); + return new MessageOneofFieldGenerator(field, options, scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // StringOneofFieldGenerator handles unknown ctypes. @@ -179,7 +166,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, } else { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field, options); + return new MessageFieldGenerator(field, options, scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // StringFieldGenerator handles unknown ctypes. diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 891e30f6..8cdbe886 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -37,13 +37,11 @@ #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> -#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/descriptor.h> namespace google { namespace protobuf { @@ -82,38 +80,12 @@ 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; @@ -184,6 +156,10 @@ class FieldGenerator { // message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; + // Returns true if this field's "MergeFromCodedStream" code needs the arena + // to be defined as a variable. + virtual bool MergeFromCodedStreamNeedsArena() const { return false; } + // Generate lines to decode this field from a packed value, which will be // placed inside the message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) @@ -203,6 +179,11 @@ class FieldGenerator { // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; + // Any tags about field layout decisions (such as inlining) to embed in the + // offset. + virtual uint32 CalculateFieldTag() const { return 0; } + virtual bool IsInlined() const { return false; } + protected: const Options& options_; @@ -213,7 +194,8 @@ class FieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - FieldGeneratorMap(const Descriptor* descriptor, const Options& options); + FieldGeneratorMap(const Descriptor* descriptor, const Options& options, + SCCAnalyzer* scc_analyzer); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; @@ -221,10 +203,11 @@ class FieldGeneratorMap { private: const Descriptor* descriptor_; const Options& options_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGenerator> > field_generators_; + std::vector<std::unique_ptr<FieldGenerator>> field_generators_; static FieldGenerator* MakeGenerator(const FieldDescriptor* field, - const Options& options); + const Options& options, + SCCAnalyzer* scc_analyzer); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 52a16835..02f360bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -35,20 +35,17 @@ #include <google/protobuf/compiler/cpp/cpp_file.h> #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <set> #include <vector> #include <google/protobuf/compiler/cpp/cpp_enum.h> -#include <google/protobuf/compiler/cpp/cpp_service.h> #include <google/protobuf/compiler/cpp/cpp_extension.h> +#include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_message.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/io/printer.h> +#include <google/protobuf/compiler/cpp/cpp_service.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -61,11 +58,11 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) options_(options), scc_analyzer_(options), enum_generators_owner_( - new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]), + new std::unique_ptr<EnumGenerator>[file->enum_type_count()]), service_generators_owner_( - new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]), + new std::unique_ptr<ServiceGenerator>[file->service_count()]), extension_generators_owner_( - new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) { + new std::unique_ptr<ExtensionGenerator>[file->extension_count()]) { std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); for (int i = 0; i < msgs.size(); i++) { // Deleted in destructor @@ -141,6 +138,9 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "// @@protoc_insertion_point(includes)\n"); + printer->Print("#define PROTOBUF_INTERNAL_EXPORT_$filename$ $export$\n", + "filename", FileLevelNamespace(file_), + "export", options_.dllexport_decl); GenerateMacroUndefs(printer); GenerateGlobalStateFunctionDeclarations(printer); @@ -223,8 +223,9 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, GenerateTopHeaderGuard(printer, filename_identifier); if (options_.proto_h) { + string target_basename = StripProto(file_->name()); printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", - "basename", StripProto(file_->name())); + "basename", target_basename); } else { GenerateLibraryIncludes(printer); } @@ -256,9 +257,10 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, } void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { + string target_basename = StripProto(file_->name()); const bool use_system_include = IsWellKnownMessage(file_); - string header = - StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); + + string header = target_basename + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" @@ -269,7 +271,6 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { "\n" "#include <google/protobuf/stubs/common.h>\n" "#include <google/protobuf/stubs/port.h>\n" - "#include <google/protobuf/stubs/once.h>\n" "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), @@ -296,7 +297,8 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dep = file_->dependency(i); const char* extension = ".proto.h"; - string dependency = StripProto(dep->name()) + extension; + string basename = StripProto(dep->name()); + string dependency = basename + extension; printer->Print( "#include \"$dependency$\"\n", "dependency", dependency); @@ -338,33 +340,34 @@ namespace { // Generates weak symbol declarations for types that are to be considered weakly // referenced. -void GenerateWeakDeclarations( - const FileDescriptor* file, const Options& options, - SCCAnalyzer* scc_analyzer, - io::Printer* printer) { - std::vector<const FieldDescriptor*> fields; - ListAllFields(file, &fields); - +void GenerateInternalForwardDeclarations( + const std::vector<const FieldDescriptor*>& fields, const Options& options, + SCCAnalyzer* scc_analyzer, io::Printer* printer) { // To ensure determinism and minimize the number of namespace statements, // we output the forward declarations sorted on namespace and type / function // name. std::set<std::pair<string, string> > messages; + std::set<std::pair<string, string> > sccs; std::set<std::pair<string, string> > inits; for (int i = 0; i < fields.size(); ++i) { const FieldDescriptor* field = fields[i]; - bool is_weak = IsImplicitWeakField(field, options); + const Descriptor* msg = field->message_type(); + if (msg == nullptr) continue; + bool is_weak = IsImplicitWeakField(field, options, scc_analyzer); + string flns = FileLevelNamespace(msg); + auto scc = scc_analyzer->GetSCC(msg); + string repr = ClassName(scc->GetRepresentative()); + string weak_attr; if (is_weak) { - const Descriptor* msg = field->message_type(); - string flns = FileLevelNamespace(msg); - string repr = ClassName(scc_analyzer->GetSCC(msg)->GetRepresentative()); - inits.insert(std::make_pair(flns, "InitDefaults" + repr)); inits.insert(std::make_pair(flns, "AddDescriptors")); messages.insert(std::make_pair(Namespace(msg), ClassName(msg))); + weak_attr = " __attribute__((weak))"; } - } - - if (messages.empty()) { - return; + string dllexport = "PROTOBUF_INTERNAL_EXPORT_" + FileLevelNamespace(msg); + sccs.insert(std::make_pair(flns, "extern " + dllexport + weak_attr + + " ::google::protobuf::internal::SCCInfo<" + + SimpleItoa(scc->children.size()) + + "> scc_info_" + repr + ";\n")); } printer->Print("\n"); @@ -384,20 +387,40 @@ void GenerateWeakDeclarations( printer->Print("void $name$() __attribute__((weak));\n", "name", it->second); } + for (const auto& p : sccs) { + ns.ChangeTo(p.first); + printer->Print(p.second.c_str()); + } } } // namespace void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + + // Generate weak declarations. We do this for the whole strongly-connected + // component (SCC), because we have a single InitDefaults* function for the + // SCC. + std::vector<const FieldDescriptor*> fields; + for (const Descriptor* message : + scc_analyzer_.GetSCC(message_generators_[idx]->descriptor_) + ->descriptors) { + ListAllFields(message, &fields); + } + GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, + printer); + + if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { + NamespaceOpener ns(FileLevelNamespace(file_), printer); + GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); + } { // package namespace NamespaceOpener ns(Namespace(file_), printer); // Define default instances GenerateSourceDefaultInstance(idx, printer); - if (UsingImplicitWeakFields(file_, options_)) { + if (options_.lite_implicit_weak_fields) { printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", message_generators_[idx]->classname_); } @@ -411,10 +434,11 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { "// @@protoc_insertion_point(namespace_scope)\n"); } // end package namespace - if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { - NamespaceOpener ns(FileLevelNamespace(file_), printer); - GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); - } + printer->Print( + "namespace google {\nnamespace protobuf {\n"); + message_generators_[idx]->GenerateSourceInProto2Namespace(printer); + printer->Print( + "} // namespace protobuf\n} // namespace google\n"); printer->Print( "\n" @@ -423,15 +447,16 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { void FileGenerator::GenerateGlobalSource(io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); - // TODO(gerbens) Generate tables here - - // Define the code to initialize reflection. This code uses a global - // constructor to register reflection data with the runtime pre-main. - if (HasDescriptorMethods(file_, options_)) { + { NamespaceOpener ns(FileLevelNamespace(file_), printer); - GenerateReflectionInitializationCode(printer); + GenerateTables(printer); + + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + if (HasDescriptorMethods(file_, options_)) { + GenerateReflectionInitializationCode(printer); + } } NamespaceOpener ns(Namespace(file_), printer); @@ -459,7 +484,10 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, + printer); { NamespaceOpener ns(Namespace(file_), printer); @@ -467,7 +495,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // Define default instances for (int i = 0; i < message_generators_.size(); i++) { GenerateSourceDefaultInstance(i, printer); - if (UsingImplicitWeakFields(file_, options_)) { + if (options_.lite_implicit_weak_fields) { printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", message_generators_[i]->classname_); } @@ -476,9 +504,25 @@ void FileGenerator::GenerateSource(io::Printer* printer) { { NamespaceOpener ns(FileLevelNamespace(file_), printer); - // Define the initialization code to initialize the default instances. - // This code doesn't use a global constructor. - GenerateInitializationCode(printer); + GenerateTables(printer); + + // Now generate the InitDefaults for each SCC. + for (int i = 0; i < message_generators_.size(); i++) { + if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { + GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), + printer); + } + } + + printer->Print("void InitDefaults() {\n"); + for (int i = 0; i < message_generators_.size(); i++) { + if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; + string scc_name = ClassName(message_generators_[i]->descriptor_); + printer->Print( + " ::google::protobuf::internal::InitSCC(&scc_info_$scc_name$.base);\n", + "scc_name", scc_name); + } + printer->Print("}\n\n"); // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. @@ -525,6 +569,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "\n" "// @@protoc_insertion_point(namespace_scope)\n"); } + + printer->Print( + "namespace google {\nnamespace protobuf {\n"); + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSourceInProto2Namespace(printer); + } + printer->Print( + "} // namespace protobuf\n} // namespace google\n"); + printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n"); @@ -544,7 +597,7 @@ class FileGenerator::ForwardDeclarations { ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { ForwardDeclarations*& ns = namespaces_[ns_name]; - if (ns == NULL) { + if (ns == nullptr) { ns = new ForwardDeclarations; } return ns; @@ -553,7 +606,42 @@ class FileGenerator::ForwardDeclarations { std::map<string, const Descriptor*>& classes() { return classes_; } std::map<string, const EnumDescriptor*>& enums() { return enums_; } - void Print(io::Printer* printer, const Options& options) const { + void PrintForwardDeclarations(io::Printer* printer, + const Options& options) const { + PrintNestedDeclarations(printer, options); + PrintTopLevelDeclarations(printer, options); + } + + + private: + void PrintNestedDeclarations(io::Printer* printer, + const Options& options) const { + PrintDeclarationsInsideNamespace(printer, options); + for (std::map<string, ForwardDeclarations *>::const_iterator + it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + printer->Print("namespace $nsname$ {\n", + "nsname", it->first); + it->second->PrintNestedDeclarations(printer, options); + printer->Print("} // namespace $nsname$\n", + "nsname", it->first); + } + } + + void PrintTopLevelDeclarations(io::Printer* printer, + const Options& options) const { + PrintDeclarationsOutsideNamespace(printer, options); + for (std::map<string, ForwardDeclarations *>::const_iterator + it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + it->second->PrintTopLevelDeclarations(printer, options); + } + } + + void PrintDeclarationsInsideNamespace(io::Printer* printer, + const Options& options) const { for (std::map<string, const EnumDescriptor *>::const_iterator it = enums_.begin(), end = enums_.end(); @@ -584,20 +672,31 @@ class FileGenerator::ForwardDeclarations { "classname", it->first); } } - for (std::map<string, ForwardDeclarations *>::const_iterator - it = namespaces_.begin(), - end = namespaces_.end(); + } + + void PrintDeclarationsOutsideNamespace(io::Printer* printer, + const Options& options) const { + if (classes_.size() == 0) return; + + printer->Print( + "namespace google {\nnamespace protobuf {\n"); + for (std::map<string, const Descriptor*>::const_iterator + it = classes_.begin(), + end = classes_.end(); it != end; ++it) { - printer->Print("namespace $nsname$ {\n", - "nsname", it->first); - it->second->Print(printer, options); - printer->Print("} // namespace $nsname$\n", - "nsname", it->first); + const Descriptor* d = it->second; + printer->Print( + "template<> " + "$dllexport_decl$" + "$classname$* Arena::CreateMaybeMessage<$classname$>" + "(Arena*);\n", + "classname", QualifiedClassName(d), "dllexport_decl", + options.dllexport_decl.empty() ? "" : options.dllexport_decl + " "); } + printer->Print( + "} // namespace protobuf\n} // namespace google\n"); } - - private: std::map<string, ForwardDeclarations*> namespaces_; std::map<string, const Descriptor*> classes_; std::map<string, const EnumDescriptor*> enums_; @@ -691,18 +790,16 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // protobuf_AssignDescriptorsOnce(): The first time it is called, calls // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. - string message_factory = "NULL"; printer->Print( - "void protobuf_AssignDescriptors() {\n" + "static void protobuf_AssignDescriptors() {\n" // Make sure the file has found its way into the pool. If a descriptor // is requested *during* static init then AddDescriptors() may not have // been called yet, so we call it manually. Note that it's fine if // AddDescriptors() is called multiple times. " AddDescriptors();\n" - " ::google::protobuf::MessageFactory* factory = $factory$;\n" " AssignDescriptors(\n" " \"$filename$\", schemas, file_default_instances, " - "TableStruct::offsets, factory,\n" + "TableStruct::offsets,\n" " $metadata$, $enum_descriptors$, $service_descriptors$);\n", "filename", file_->name(), "metadata", !message_generators_.empty() ? "file_level_metadata" : "NULL", @@ -711,14 +808,13 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" - : "NULL", - "factory", message_factory); + : "NULL"); printer->Print( "}\n" "\n" - "void protobuf_AssignDescriptorsOnce() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);\n" + "static void protobuf_AssignDescriptorsOnce() {\n" + " static ::google::protobuf::internal::once_flag once;\n" + " ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);\n" "}\n" "\n", "filename", file_->name(), "metadata", @@ -728,8 +824,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" - : "NULL", - "factory", message_factory); + : "NULL"); // Only here because of useless string reference that we don't want in // protobuf_AssignDescriptorsOnce, because that is called from all the @@ -755,7 +850,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // Now generate the AddDescriptors() function. printer->Print( - "void AddDescriptorsImpl() {\n" + "static void AddDescriptorsImpl() {\n" " InitDefaults();\n"); printer->Indent(); @@ -824,8 +919,8 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "}\n" "\n" "void AddDescriptors() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n" + " static ::google::protobuf::internal::once_flag once;\n" + " ::google::protobuf::internal::call_once(once, AddDescriptorsImpl);\n" "}\n"); printer->Print( @@ -840,47 +935,16 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { const string scc_name = ClassName(scc->GetRepresentative()); + // We use static and not anonymous namespace because symbol names are + // substantially shorter. printer->Print( - "void InitDefaults$scc_name$Impl() {\n" + "static void InitDefaults$scc_name$() {\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" - "#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n" - " ::google::protobuf::internal::InitProtobufDefaultsForceUnique();\n" - "#else\n" - " ::google::protobuf::internal::InitProtobufDefaults();\n" - "#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n", - // Force initialization of primitive values we depend on. + , // awkward comma due to macro "scc_name", scc_name); printer->Indent(); - // Call the InitDefaults() methods for all of our dependencies, to make - // sure they get added first. - for (int i = 0; i < scc->children.size(); i++) { - const SCC* child_scc = scc->children[i]; - const FileDescriptor* dependency = child_scc->GetRepresentative()->file(); - // Print the namespace prefix for the dependency. - string file_namespace = FileLevelNamespace(dependency); - std::map<string, string> variables; - variables["file_namespace"] = file_namespace; - variables["scc_name"] = ClassName(child_scc->GetRepresentative(), false); - bool using_weak_fields = UsingImplicitWeakFields(file_, options_); - if (using_weak_fields) { - // We're building for lite with implicit weak fields, so we need to handle - // the possibility that this InitDefaults function is not linked into the - // binary. Some of these might actually be guaranteed to be non-null since - // we might have a strong reference to the dependency (via a required - // field, for example), but it's simplest to just assume that any of them - // could be null. - printer->Print( - variables, - "if (&$file_namespace$::InitDefaults$scc_name$ != NULL) {\n" - " $file_namespace$::InitDefaults$scc_name$();\n" - "}\n"); - } else { - printer->Print(variables, - "$file_namespace$::InitDefaults$scc_name$();\n"); - } - } // First construct all the necessary default instances. for (int i = 0; i < message_generators_.size(); i++) { @@ -915,23 +979,24 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { } printer->Outdent(); printer->Print("}\n\n"); + printer->Print( - "void InitDefaults$scc_name$() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, " - "&InitDefaults$scc_name$Impl);\n" - "}\n\n", - "scc_name", scc_name); + "$dllexport_decl$::google::protobuf::internal::SCCInfo<$size$> " + "scc_info_$scc_name$ =\n" + " {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), " + "$size$, InitDefaults$scc_name$}, {", + "size", SimpleItoa(scc->children.size()), "scc_name", + ClassName(scc->GetRepresentative()), "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + for (const SCC* child : scc->children) { + auto repr = child->GetRepresentative(); + printer->Print("\n &$ns$::scc_info_$child$.base,", "ns", + FileLevelNamespace(repr), "child", ClassName(repr)); + } + printer->Print("}};\n\n"); } -void FileGenerator::GenerateInitializationCode(io::Printer* printer) { - // Messages depend on the existence of a default instance, which has to - // initialized properly. The default instances are allocated in the data - // segment, but we can't quite allocate the type directly. The destructors - // cannot run at program exit as this could lead to segfaults in a threaded - // environment. Hence these instances must be inplace constructed at first - // use. - +void FileGenerator::GenerateTables(io::Printer* printer) { if (options_.table_driven_parsing) { // TODO(ckennelly): Gate this with the same options flag to enable // table-driven parsing. @@ -1038,22 +1103,12 @@ void FileGenerator::GenerateInitializationCode(io::Printer* printer) { "};\n" "\n"); } - - // ----------------------------------------------------------------- - // All functionality that need private access. - - // Now generate the InitDefaults for each SCC. - for (int i = 0; i < message_generators_.size(); i++) { - if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { - GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), printer); - } - } } void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { ForwardDeclarations decls; FillForwardDeclarations(&decls); - decls.Print(printer, options_); + decls.PrintForwardDeclarations(printer, options_); } void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { @@ -1078,8 +1133,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, "// 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" + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$\n" "\n" "#include <string>\n", "filename", file_->name(), "filename_identifier", filename_identifier); @@ -1089,7 +1144,7 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, void FileGenerator::GenerateBottomHeaderGuard( io::Printer* printer, const string& filename_identifier) { printer->Print( - "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", + "#endif // PROTOBUF_INCLUDED_$filename_identifier$\n", "filename_identifier", filename_identifier); } @@ -1126,7 +1181,9 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include <google/protobuf/arena.h>\n" "#include <google/protobuf/arenastring.h>\n" "#include <google/protobuf/generated_message_table_driven.h>\n" - "#include <google/protobuf/generated_message_util.h>\n"); + "#include <google/protobuf/generated_message_util.h>\n" + "#include <google/protobuf/inlined_string_field.h>\n"); + if (HasDescriptorMethods(file_, options_)) { printer->Print( @@ -1213,11 +1270,12 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); + string basename = StripProto(name); printer->Print( "#include $left$$dependency$.pb.h$right$$iwyu$\n", - "dependency", StripProto(name), + "dependency", basename, "iwyu", (public_import) ? " // IWYU pragma: export" : "", "left", use_system_include ? "<" : "\"", "right", use_system_include ? ">" : "\""); @@ -1251,28 +1309,6 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); } - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; - string scc_name = ClassName(message_generators_[i]->descriptor_); - // TODO(gerbens) Remove the Impl from header. This is solely because - // it currently still needs to be a friend of the protos. - printer->Print( - "void $dllexport_decl$InitDefaults$scc_name$Impl();\n" - "void $dllexport_decl$InitDefaults$scc_name$();\n", - "scc_name", scc_name, "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - } - // TODO(gerbens) This is for proto1 interoperability. Remove when proto1 - // is gone. - printer->Print( - "inline void $dllexport_decl$InitDefaults() {\n", "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; - string scc_name = ClassName(message_generators_[i]->descriptor_); - printer->Print(" InitDefaults$scc_name$();\n", "scc_name", scc_name); - } - printer->Print("}\n"); printer->Print( "} // namespace $file_namespace$\n", "file_namespace", FileLevelNamespace(file_)); @@ -1349,8 +1385,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { printer->Print(kThinSeparator); printer->Print("\n"); } - // Methods of the dependent base class must always be inline in the header. - message_generators_[i]->GenerateDependentInlineMethods(printer); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 7e61cbad..94da9a14 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -37,9 +37,6 @@ #include <algorithm> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <set> #include <string> #include <vector> @@ -97,7 +94,7 @@ class FileGenerator { void GenerateSourceDefaultInstance(int idx, io::Printer* printer); void GenerateInitForSCC(const SCC* scc, io::Printer* printer); - void GenerateInitializationCode(io::Printer* printer); + void GenerateTables(io::Printer* printer); void GenerateReflectionInitializationCode(io::Printer* printer); // For other imports, generates their forward-declarations. @@ -176,10 +173,10 @@ class FileGenerator { // These members are just for owning (and thus proper deleting). // Nested (enum/extension)_generators are owned by child messages. - google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_owner_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > + std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_owner_; + std::unique_ptr<std::unique_ptr<ServiceGenerator> []> service_generators_owner_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > + std::unique_ptr<std::unique_ptr<ExtensionGenerator> []> extension_generators_owner_; // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index e01e5dca..20bb8a1a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -36,17 +36,15 @@ #include <vector> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <utility> +#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/compiler/cpp/cpp_file.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> + namespace google { namespace protobuf { @@ -66,12 +64,6 @@ bool CppGenerator::Generate(const FileDescriptor* file, // ----------------------------------------------------------------- // parse generator options - // TODO(kenton): If we ever have more options, we may want to create a - // class that encapsulates them which we can pass down to all the - // generator classes. Currently we pass dllexport_decl down to all of - // them via the constructors, but we don't want to have to add another - // constructor parameter for every option. - // If the dllexport_decl option is passed to the compiler, we need to write // it in front of every symbol that should be exported if this .proto is // compiled into a Windows DLL. E.g., if the user invokes the protocol @@ -85,7 +77,6 @@ bool CppGenerator::Generate(const FileDescriptor* file, // __declspec(dllimport) depending on what is being compiled. // Options file_options; - bool split_source = false; for (int i = 0; i < options.size(); i++) { if (options[i].first == "dllexport_decl") { file_options.dllexport_decl = options[i].second; @@ -101,28 +92,39 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.enforce_lite = true; } else if (options[i].first == "lite_implicit_weak_fields") { file_options.lite_implicit_weak_fields = true; + if (!options[i].second.empty()) { + file_options.num_cc_files = strto32(options[i].second.c_str(), + NULL, 10); + } } else if (options[i].first == "table_driven_parsing") { file_options.table_driven_parsing = true; } else if (options[i].first == "table_driven_serialization") { file_options.table_driven_serialization = true; - } else if (options[i].first == "split_source") { - split_source = true; } else { *error = "Unknown generator option: " + options[i].first; return false; } } + // The safe_boundary_check option controls behavior for Google-internal + // protobuf APIs. + if (file_options.safe_boundary_check) { + *error = + "The safe_boundary_check option is not supported outside of Google."; + return false; + } + // ----------------------------------------------------------------- string basename = StripProto(file->name()); + FileGenerator file_generator(file, file_options); // Generate header(s). if (file_options.proto_h) { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".proto.h")); GeneratedCodeInfo annotations; io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( @@ -134,14 +136,14 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_generator.GenerateProtoHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output( + std::unique_ptr<io::ZeroCopyOutputStream> info_output( generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } } { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".pb.h")); GeneratedCodeInfo annotations; io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( @@ -153,30 +155,44 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_generator.GeneratePBHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output( + std::unique_ptr<io::ZeroCopyOutputStream> info_output( generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } } - // Generate cc file. - if (split_source) { + // Generate cc file(s). + if (UsingImplicitWeakFields(file, file_options)) { { // This is the global .cc file, containing enum/services/tables/reflection - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".pb.cc")); io::Printer printer(output.get(), '$'); file_generator.GenerateGlobalSource(&printer); } - for (int i = 0; i < file_generator.NumMessages(); i++) { + + int num_cc_files = file_generator.NumMessages(); + + // If we're using implicit weak fields then we allow the user to optionally + // specify how many files to generate, not counting the global pb.cc file. + // If we have more files than messages, then some files will be generated as + // empty placeholders. + if (file_options.num_cc_files > 0) { + GOOGLE_CHECK_LE(file_generator.NumMessages(), file_options.num_cc_files) + << "There must be at least as many numbered .cc files as messages."; + num_cc_files = file_options.num_cc_files; + } + for (int i = 0; i < num_cc_files; i++) { // TODO(gerbens) Agree on naming scheme. - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + "." + SimpleItoa(i) + ".cc")); io::Printer printer(output.get(), '$'); - file_generator.GenerateSourceForMessage(i, &printer); + if (i < file_generator.NumMessages()) { + file_generator.GenerateSourceForMessage(i, &printer); + } } } else { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".pb.cc")); io::Printer printer(output.get(), '$'); file_generator.GenerateSource(&printer); diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 96950e52..163dac0a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -42,6 +42,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -73,7 +74,7 @@ const char* const kKeywordList[] = { "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", - "mutable", "namespace", "new", "noexcept", "not", "not_eq", "NULL", + "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", @@ -219,24 +220,12 @@ string ReferenceFunctionName(const Descriptor* descriptor) { return QualifiedClassName(descriptor) + "_ReferenceStrong"; } -string DependentBaseClassTemplateName(const Descriptor* descriptor) { - return ClassName(descriptor, false) + "_InternalBase"; -} - string SuperClassName(const Descriptor* descriptor, const Options& options) { return HasDescriptorMethods(descriptor->file(), options) ? "::google::protobuf::Message" : "::google::protobuf::MessageLite"; } -string DependentBaseDownCast() { - return "reinterpret_cast<T*>(this)->"; -} - -string DependentBaseConstDownCast() { - return "reinterpret_cast<const T*>(this)->"; -} - string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -294,60 +283,6 @@ string FieldConstantName(const FieldDescriptor *field) { return result; } -bool IsFieldDependent(const FieldDescriptor* field) { - if (field->containing_oneof() != NULL && - field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - return true; - } - if (field->is_map()) { - const Descriptor* map_descriptor = field->message_type(); - for (int i = 0; i < map_descriptor->field_count(); i++) { - if (IsFieldDependent(map_descriptor->field(i))) { - return true; - } - } - return false; - } - 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. @@ -748,12 +683,17 @@ bool UsingImplicitWeakFields(const FileDescriptor* file, GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME; } - -bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options) { +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + SCCAnalyzer* scc_analyzer) { return UsingImplicitWeakFields(field->file(), options) && field->type() == FieldDescriptor::TYPE_MESSAGE && - !field->is_required() && !field->is_repeated() && !field->is_map() && - field->containing_oneof() == NULL; + !field->is_required() && !field->is_map() && + field->containing_oneof() == NULL && + !IsWellKnownMessage(field->message_type()->file()) && + // We do not support implicit weak fields between messages in the same + // strongly-connected component. + scc_analyzer->GetSCC(field->containing_type()) != + scc_analyzer->GetSCC(field->message_type()); } struct CompareDescriptors { @@ -920,6 +860,7 @@ void ListAllTypesForServices(const FileDescriptor* fd, } } + } // 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 e0f809c9..eac65124 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -38,8 +38,9 @@ #include <map> #include <string> #include <google/protobuf/compiler/cpp/cpp_options.h> -#include <google/protobuf/io/printer.h> +#include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/stubs/strutil.h> @@ -53,6 +54,7 @@ namespace cpp { extern const char kThickSeparator[]; extern const char kThinSeparator[]; + // Name space of the proto file. This namespace is such that the string // "<namespace>::some_name" is the correct fully qualified namespace. // This means if the package is empty the namespace is "", and otherwise @@ -102,19 +104,9 @@ string DefaultInstanceName(const Descriptor* descriptor); // fields. string ReferenceFunctionName(const Descriptor* descriptor); -// Name of the CRTP class template (for use with proto_h). -// This is a class name, like "ProtoName_InternalBase". -string DependentBaseClassTemplateName(const Descriptor* descriptor); - -// Name of the base class: either the dependent base class (for use with -// proto_h) or google::protobuf::Message. +// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite. string SuperClassName(const Descriptor* descriptor, const Options& options); -// Returns a string that down-casts from the dependent base class to the -// derived class. -string DependentBaseDownCast(); -string DependentBaseConstDownCast(); - // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names @@ -141,20 +133,6 @@ 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); @@ -310,6 +288,15 @@ inline bool IsCrossFileMessage(const FieldDescriptor* field) { field->message_type()->file() != field->file(); } +inline string MessageCreateFunction(const Descriptor* d) { + return SupportsArenas(d) ? "CreateMessage" : "Create"; +} + +inline string MakeDefaultName(const FieldDescriptor* field) { + return "_i_give_permission_to_break_this_code_default_" + FieldName(field) + + "_"; +} + bool IsAnyMessage(const FileDescriptor* descriptor); bool IsAnyMessage(const Descriptor* descriptor); @@ -346,13 +333,6 @@ inline std::vector<const Descriptor*> FlattenMessagesInFile( bool HasWeakFields(const Descriptor* desc); bool HasWeakFields(const FileDescriptor* desc); -// Indicates whether we should use implicit weak fields for this file. -bool UsingImplicitWeakFields(const FileDescriptor* file, - const Options& options); - -// Indicates whether to treat this field as implicitly weak. -bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options); - // Returns true if the "required" restriction check should be ignored for the // given field. inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, @@ -458,11 +438,21 @@ class LIBPROTOC_EXPORT SCCAnalyzer { void AddChildren(SCC* scc); }; +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields); void ListAllFields(const FileDescriptor* d, std::vector<const FieldDescriptor*>* fields); void ListAllTypesForServices(const FileDescriptor* fd, std::vector<const Descriptor*>* types); +// Indicates whether we should use implicit weak fields for this file. +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options); + +// Indicates whether to treat this field as implicitly weak. +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + SCCAnalyzer* scc_analyzer); + } // 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 b22c0754..0e485cac 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -104,9 +104,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), - descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { + : FieldGenerator(options), descriptor_(descriptor) { SetMessageVariables(descriptor, &variables_, options); } @@ -202,7 +200,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { key = "entry->key()"; value = "entry->value()"; printer->Print(variables_, - "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n"); + "::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n"); printer->Print(variables_, "{\n" " ::std::string data;\n" @@ -258,7 +256,7 @@ static void GenerateSerializationLoop(io::Printer* printer, const string& ptr, bool loop_via_iterators) { printer->Print(variables, - StrCat("::google::protobuf::scoped_ptr<$map_classname$> entry;\n", + StrCat("::std::unique_ptr<$map_classname$> entry;\n", loop_header, " {\n").c_str()); printer->Indent(); @@ -365,7 +363,7 @@ void MapFieldGenerator::GenerateSerializeWithCachedSizes( "\n" "if ($deterministic$ &&\n" " this->$name$().size() > 1) {\n" - " ::google::protobuf::scoped_array<SortItem> items(\n" + " ::std::unique_ptr<SortItem[]> items(\n" " new SortItem[this->$name$().size()]);\n" " typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n" " size_type n = 0;\n" @@ -402,7 +400,7 @@ GenerateByteSize(io::Printer* printer) const { "total_size += $tag_size$ *\n" " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" "{\n" - " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" + " ::std::unique_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" " it = this->$name$().begin();\n" " it != this->$name$().end(); ++it) {\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 88e3b464..0d54f0ea 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -66,7 +66,6 @@ class MapFieldGenerator : public FieldGenerator { io::Printer* printer, const std::map<string, string>& variables) const; const FieldDescriptor* descriptor_; - const bool dependent_field_; std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 60467598..778fc406 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -38,9 +38,6 @@ #include <google/protobuf/stubs/hash.h> #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <utility> #include <vector> @@ -49,9 +46,9 @@ #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/generated_message_table_driven.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/map_entry_lite.h> @@ -60,6 +57,7 @@ #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -113,16 +111,16 @@ struct ExtensionRangeSorter { bool IsPOD(const FieldDescriptor* field) { if (field->is_repeated() || field->is_extension()) return false; switch (field->cpp_type()) { - case internal::WireFormatLite::CPPTYPE_ENUM: - case internal::WireFormatLite::CPPTYPE_INT32: - case internal::WireFormatLite::CPPTYPE_INT64: - case internal::WireFormatLite::CPPTYPE_UINT32: - case internal::WireFormatLite::CPPTYPE_UINT64: - case internal::WireFormatLite::CPPTYPE_FLOAT: - case internal::WireFormatLite::CPPTYPE_DOUBLE: - case internal::WireFormatLite::CPPTYPE_BOOL: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_BOOL: return true; - case internal::WireFormatLite::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: return false; default: return false; @@ -325,6 +323,109 @@ bool IsCrossFileMaybeMap(const FieldDescriptor* field) { return IsCrossFileMessage(field); } +bool IsRequired(const std::vector<const FieldDescriptor*>& v) { + return v.front()->is_required(); +} + +// Allows chunking repeated fields together and non-repeated fields if the +// fields share the same has_byte index. +// TODO(seongkim): use lambda with capture instead of functor. +class MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByte(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : has_bit_indices_(*has_bit_indices), + has_field_presence_(has_field_presence) {} + + // Returns true if the following conditions are met: + // --both fields are repeated fields + // --both fields are non-repeated fields with either has_field_presence is + // false or have the same has_byte index. + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return a->is_repeated() == b->is_repeated() && + (!has_field_presence_ || a->is_repeated() || + has_bit_indices_[a->index()] / 8 == + has_bit_indices_[b->index()] / 8); + } + + private: + const std::vector<int>& has_bit_indices_; + const bool has_field_presence_; +}; + +// Allows chunking required fields separately after chunking with +// MatchRepeatedAndHasByte. +class MatchRepeatedAndHasByteAndRequired : public MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByteAndRequired(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {} + + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return MatchRepeatedAndHasByte::operator()(a, b) && + a->is_required() == b->is_required(); + } +}; + +// Allows chunking zero-initializable fields separately after chunking with +// MatchRepeatedAndHasByte. +class MatchRepeatedAndHasByteAndZeroInits : public MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByteAndZeroInits(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {} + + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return MatchRepeatedAndHasByte::operator()(a, b) && + CanInitializeByZeroing(a) == CanInitializeByZeroing(b); + } +}; + +// Collects neighboring fields based on a given criteria (equivalent predicate). +template <typename Predicate> +std::vector<std::vector<const FieldDescriptor*> > CollectFields( + const std::vector<const FieldDescriptor*>& fields, + const Predicate& equivalent) { + std::vector<std::vector<const FieldDescriptor*> > chunks; + if (fields.empty()) { + return chunks; + } + + const FieldDescriptor* last_field = fields.front(); + std::vector<const FieldDescriptor*> chunk; + for (int i = 0; i < fields.size(); i++) { + if (!equivalent(last_field, fields[i]) && !chunk.empty()) { + chunks.push_back(chunk); + chunk.clear(); + } + chunk.push_back(fields[i]); + last_field = fields[i]; + } + if (!chunk.empty()) { + chunks.push_back(chunk); + } + return chunks; +} + +// Returns a bit mask based on has_bit index of "fields" that are typically on +// the same chunk. It is used in a group presence check where _has_bits_ is +// masked to tell if any thing in "fields" is present. +uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields, + const std::vector<int>& has_bit_indices) { + GOOGLE_CHECK(!fields.empty()); + int first_index_offset = has_bit_indices[fields.front()->index()] / 32; + uint32 chunk_mask = 0; + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + // "index" defines where in the _has_bits_ the field appears. + int index = has_bit_indices[field->index()]; + GOOGLE_CHECK_EQ(first_index_offset, index / 32); + chunk_mask |= static_cast<uint32>(1) << (index % 32); + } + GOOGLE_CHECK_NE(0, chunk_mask); + return chunk_mask; +} + } // anonymous namespace // =================================================================== @@ -337,13 +438,12 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, index_in_file_messages_(index_in_file_messages), classname_(ClassName(descriptor, false)), options_(options), - field_generators_(descriptor, options), + field_generators_(descriptor, options, scc_analyzer), max_has_bit_index_(0), enum_generators_( - new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]), - extension_generators_(new google::protobuf::scoped_ptr< + new std::unique_ptr<EnumGenerator>[descriptor->enum_type_count()]), + extension_generators_(new std::unique_ptr< ExtensionGenerator>[descriptor->extension_count()]), - use_dependent_base_(false), num_weak_fields_(0), message_layout_helper_(new PaddingOptimizer()), scc_analyzer_(scc_analyzer) { @@ -389,13 +489,6 @@ 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; - } - } - if (options.proto_h && descriptor->oneof_decl_count() > 0) { - // Always make oneofs dependent. - use_dependent_base_ = true; } table_driven_ = TableDrivenParsingEnabled(descriptor_, options_); @@ -436,22 +529,6 @@ void MessageGenerator::FillMessageForwardDeclarations( } void MessageGenerator:: -GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - PrintFieldComment(printer, field); - - std::map<string, string> vars; - SetCommonFieldVariables(field, &vars, options_); - - // Generate type-specific accessor declarations. - field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); - printer->Print("\n"); - } -} - -void MessageGenerator:: GenerateFieldAccessorDeclarations(io::Printer* printer) { // optimized_fields_ does not contain fields where // field->containing_oneof() != NULL @@ -482,21 +559,6 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); - bool dependent_field = use_dependent_base_ && IsFieldDependent(field); - if (dependent_field && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !field->is_map()) { - // 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, "$deprecated_attr$int ${$$name$_size$}$() const;\n"); printer->Annotate("{", "}", field); @@ -534,6 +596,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( + "void clear_$oneof_name$();\n" "$camel_oneof_name$Case $oneof_name$_case() const;\n", "camel_oneof_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true), @@ -542,32 +605,6 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } void MessageGenerator:: -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); - - if (field->options().weak()) continue; - - PrintFieldComment(printer, field); - // 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); -} - -void MessageGenerator:: GenerateSingularFieldHasBits(const FieldDescriptor* field, std::map<string, string> vars, io::Printer* printer) { @@ -709,18 +746,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); - if (use_dependent_base_ && IsFieldDependent(field)) { - 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)->"; - } else { - vars["tmpl"] = ""; - vars["dependent_classname"] = vars["classname"]; - vars["this_message"] = ""; - vars["this_const_message"] = ""; - } // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -748,42 +773,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { printer->Print("\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); - } -} - -void MessageGenerator:: -GenerateDependentBaseClassDefinition(io::Printer* printer) { - if (!use_dependent_base_) { - return; - } - - std::map<string, string> vars; - vars["classname"] = DependentBaseClassTemplateName(descriptor_); - vars["full_name"] = descriptor_->full_name(); - vars["superclass"] = SuperClassName(descriptor_, options_); - - printer->Print(vars, - "template <class T>\n" - "class $classname$ : public $superclass$ " - "/* @@protoc_insertion_point(dep_base_class_definition:$full_name$) */ {\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"); + // Generate has_$name$() and clear_has_$name$() functions for oneofs. + GenerateOneofHasBits(printer); } void MessageGenerator:: @@ -816,7 +807,7 @@ GenerateClassDefinition(io::Printer* printer) { "$classname$*>(&_$classname$_default_instance_); }\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n" + " void MergeFrom(const ::google::protobuf::Message& other) final;\n" " ::google::protobuf::Metadata GetMetadata() const;\n" "};\n"); } else { @@ -824,10 +815,6 @@ GenerateClassDefinition(io::Printer* printer) { } return; } - if (use_dependent_base_) { - GenerateDependentBaseClassDefinition(printer); - printer->Print("\n"); - } std::map<string, string> vars; vars["classname"] = classname_; @@ -839,20 +826,12 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = options_.dllexport_decl + " "; } - if (use_dependent_base_) { - vars["superclass"] = - DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; - } else { - vars["superclass"] = SuperClassName(descriptor_, options_); - } + vars["superclass"] = SuperClassName(descriptor_, options_); printer->Print(vars, "class $dllexport$$classname$ : public $superclass$ " "/* @@protoc_insertion_point(class_definition:$full_name$) */ " "{\n"); printer->Annotate("classname", descriptor_); - if (use_dependent_base_) { - printer->Print(vars, " friend class $superclass$;\n"); - } printer->Print(" public:\n"); printer->Indent(); @@ -913,10 +892,10 @@ GenerateClassDefinition(io::Printer* printer) { // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a // MessageLite* (e.g., in RepeatedField::AddAllocated()). printer->Print( - "inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {\n" + "inline ::google::protobuf::Arena* GetArena() const final {\n" " return GetArenaNoVirtual();\n" "}\n" - "inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {\n" + "inline void* GetMaybeArenaPointer() const final {\n" " return MaybeArenaPtr();\n" "}\n"); } @@ -968,7 +947,7 @@ GenerateClassDefinition(io::Printer* printer) { " return reinterpret_cast<const $classname$*>(\n" " &_$classname$_default_instance_);\n" "}\n" - "static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =\n" + "static constexpr int kIndexInFileMessages =\n" " $message_index$;\n" "\n"); @@ -988,10 +967,12 @@ GenerateClassDefinition(io::Printer* printer) { "template<typename T> bool Is() const {\n" " return _any_metadata_.Is<T>();\n" "}\n" + "static bool ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name);\n" "\n"); } - vars["new_final"] = " PROTOBUF_FINAL"; + vars["new_final"] = " final"; printer->Print(vars, "void Swap($classname$* other);\n" @@ -1001,29 +982,33 @@ GenerateClassDefinition(io::Printer* printer) { "\n" "// implements Message ----------------------------------------------\n" "\n" - "inline $classname$* New() const$new_final$ { return New(NULL); }\n" + "inline $classname$* New() const$new_final$ {\n" + " return CreateMaybeMessage<$classname$>(NULL);\n" + "}\n" "\n" - "$classname$* New(::google::protobuf::Arena* arena) const$new_final$;\n"); + "$classname$* New(::google::protobuf::Arena* arena) const$new_final$ {\n" + " return CreateMaybeMessage<$classname$>(arena);\n" + "}\n"); // For instances that derive from Message (rather than MessageLite), some // methods are virtual and should be marked as final. string use_final = HasDescriptorMethods(descriptor_->file(), options_) ? - " PROTOBUF_FINAL" : ""; + " final" : ""; if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, - "void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n" - "void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n"); + "void CopyFrom(const ::google::protobuf::Message& from) final;\n" + "void MergeFrom(const ::google::protobuf::Message& from) final;\n"); } else { printer->Print(vars, "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)\n" - " PROTOBUF_FINAL;\n"); + " final;\n"); } - vars["clear_final"] = " PROTOBUF_FINAL"; - vars["is_initialized_final"] = " PROTOBUF_FINAL"; - vars["merge_partial_final"] = " PROTOBUF_FINAL"; + vars["clear_final"] = " final"; + vars["is_initialized_final"] = " final"; + vars["merge_partial_final"] = " final"; printer->Print( vars, @@ -1032,7 +1017,7 @@ GenerateClassDefinition(io::Printer* printer) { "void Clear()$clear_final$;\n" "bool IsInitialized() const$is_initialized_final$;\n" "\n" - "size_t ByteSizeLong() const PROTOBUF_FINAL;\n" + "size_t ByteSizeLong() const final;\n" "bool MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"); if (!options_.table_driven_serialization || @@ -1040,7 +1025,7 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print( "void SerializeWithCachedSizes(\n" " ::google::protobuf::io::CodedOutputStream* output) const " - "PROTOBUF_FINAL;\n"); + "final;\n"); } // DiscardUnknownFields() is implemented in message.cc using reflections. We // need to implement this function in generated code for messages. @@ -1052,19 +1037,18 @@ GenerateClassDefinition(io::Printer* printer) { if (HasFastArraySerialization(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n"); + " bool deterministic, ::google::protobuf::uint8* target) const final;\n"); } } printer->Print( - "int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }\n" - "private:\n" - "void SharedCtor();\n" - "void SharedDtor();\n" - "void SetCachedSize(int size) const$final$;\n" - "void InternalSwap($classname$* other);\n", - "classname", classname_, - "final", use_final); + "int GetCachedSize() const final { return _cached_size_.Get(); }" + "\n\nprivate:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" + "void SetCachedSize(int size) const$final$;\n" + "void InternalSwap($classname$* other);\n", + "classname", classname_, "final", use_final); if (SupportsArenas(descriptor_)) { printer->Print( // TODO(gerbens) Make this private! Currently people are deriving from @@ -1104,11 +1088,11 @@ GenerateClassDefinition(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - "::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;\n" + "::google::protobuf::Metadata GetMetadata() const final;\n" "\n"); } else { printer->Print( - "::std::string GetTypeName() const PROTOBUF_FINAL;\n" + "::std::string GetTypeName() const final;\n" "\n"); } @@ -1187,7 +1171,6 @@ GenerateClassDefinition(io::Printer* printer) { 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()); } @@ -1205,7 +1188,8 @@ GenerateClassDefinition(io::Printer* printer) { bool need_to_emit_cached_size = true; // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it. - const string cached_size_decl = "mutable int _cached_size_;\n"; + const string cached_size_decl = + "mutable ::google::protobuf::internal::CachedSize _cached_size_;\n"; const size_t sizeof_has_bits = HasBitsSize(); const string has_bits_decl = sizeof_has_bits == 0 ? "" : @@ -1315,13 +1299,10 @@ GenerateClassDefinition(io::Printer* printer) { // The TableStruct struct needs access to the private parts, in order to // construct the offsets of all members. - // TODO(gerbens) Remove the friend for InitDefaults. - printer->Print( - "friend struct ::$file_namespace$::TableStruct;\n" - "friend void ::$file_namespace$::InitDefaults$scc_name$Impl();\n", - // Vars. - "scc_name", scc_name_, "file_namespace", - FileLevelNamespace(descriptor_)); + printer->Print("friend struct ::$file_namespace$::TableStruct;\n", + // Vars. + "scc_name", scc_name_, "file_namespace", + FileLevelNamespace(descriptor_)); printer->Outdent(); printer->Print("};"); @@ -1329,18 +1310,6 @@ GenerateClassDefinition(io::Printer* printer) { } void MessageGenerator:: -GenerateDependentInlineMethods(io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) return; - for (int i = 0; i < descriptor_->field_count(); i++) { - if (descriptor_->field(i)->options().weak()) { - field_generators_.get(descriptor_->field(i)) - .GenerateDependentInlineAccessorDefinitions(printer); - } - } - GenerateDependentFieldAccessorDefinitions(printer); -} - -void MessageGenerator:: GenerateInlineMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) return; GenerateFieldAccessorDefinitions(printer); @@ -1495,7 +1464,8 @@ uint32 CalculateType(uint32 type, uint32 type_class) { return (type - 1) + type_class * 20; } -uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { +uint32 CalcFieldNum(const FieldGenerator&, const FieldDescriptor* field, + const Options& options) { bool is_a_map = IsMapEntryMessage(field->containing_type()); int type = field->type(); if (field->containing_oneof()) { @@ -1516,9 +1486,16 @@ uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { #else // We need to calculate for each field what function the table driven code // should use to serialize it. This returns the index in a lookup table. -uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { +uint32 CalcFieldNum(const FieldGenerator& generator, + const FieldDescriptor* field, const Options& options) { bool is_a_map = IsMapEntryMessage(field->containing_type()); int type = field->type(); + if (type == FieldDescriptor::TYPE_STRING || + type == FieldDescriptor::TYPE_BYTES) { + if (generator.IsInlined()) { + type = internal::FieldMetadata::kInlinedType; + } + } if (field->containing_oneof()) { return internal::FieldMetadata::CalculateType( type, internal::FieldMetadata::kOneOf); @@ -1560,6 +1537,8 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) { for (int i = 0; i < 2; i++) { const FieldDescriptor* field = sorted[i]; + const FieldGenerator& generator = field_generators_.get(field); + uint32 tag = internal::WireFormatLite::MakeTag( field->number(), WireFormat::WireTypeForFieldType(field->type())); @@ -1568,7 +1547,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { vars["field_name"] = FieldName(field); vars["tag"] = SimpleItoa(tag); vars["hasbit"] = SimpleItoa(i); - vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); vars["ptr"] = "NULL"; if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); @@ -1657,7 +1636,9 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { SimpleItoa(FindMessageIndexInFile(field->message_type())); } } - vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + + const FieldGenerator& generator = field_generators_.get(field); + vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); if (field->options().weak()) { @@ -1804,6 +1785,11 @@ GenerateClassMethods(io::Printer* printer) { "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" " return _any_metadata_.UnpackTo(message);\n" "}\n" + "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name) {\n" + " return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,\n" + " full_type_name);\n" + "}\n" "\n", "classname", classname_); } @@ -1941,16 +1927,26 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { } processing_type = static_cast<unsigned>(field->type()); + const FieldGenerator& generator = field_generators_.get(field); if (field->type() == FieldDescriptor::TYPE_STRING) { switch (EffectiveStringCType(field)) { case FieldOptions::STRING: - default: + default: { + if (generator.IsInlined()) { + processing_type = internal::TYPE_STRING_INLINED; + break; + } break; + } } } else if (field->type() == FieldDescriptor::TYPE_BYTES) { switch (EffectiveStringCType(field)) { case FieldOptions::STRING: default: + if (generator.IsInlined()) { + processing_type = internal::TYPE_BYTES_INLINED; + break; + } break; } } @@ -1985,7 +1981,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { "{\n" " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" " $classname$, $name$_),\n" - " static_cast< ::google::protobuf::uint32>($presence$),\n" + " static_cast<::google::protobuf::uint32>($presence$),\n" " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" "},\n"); } @@ -2042,20 +2038,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { printer->Print( vars, "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n" - " &$ns$::_$classname$_default_instance_,\n"); - - bool dont_emit_table = - !TableDrivenParsingEnabled(field->message_type(), options_); - - if (dont_emit_table) { - printer->Print(" NULL,\n"); - } else { - printer->Print(vars, - " ::$file_namespace$::TableStruct::schema +\n" - " $ns$::$classname$::kIndexInFileMessages,\n"); - } - - printer->Print("}},\n"); + " &$ns$::_$classname$_default_instance_}},\n"); last_field_number++; break; } @@ -2066,7 +2049,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { field->default_value_string().empty() ? "&::google::protobuf::internal::fixed_address_empty_string" : "&" + Namespace(field) + " ::" + classname_ + - "::_default_" + FieldName(field) + "_"; + "::" + MakeDefaultName(field); break; case FieldOptions::CORD: case FieldOptions::STRING_PIECE: @@ -2137,14 +2120,20 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->containing_oneof() || field->options().weak()) { - printer->Print("offsetof($classname$DefaultTypeInternal, $name$_),\n", + printer->Print("offsetof($classname$DefaultTypeInternal, $name$_)", "classname", full_classname, "name", FieldName(field)); } else { printer->Print( - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "$name$_),\n", + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_)", "classname", full_classname, "name", FieldName(field)); } + + uint32 tag = field_generators_.get(field).CalculateFieldTag(); + if (tag != 0) { + printer->Print(" | $tag$", "tag", SimpleItoa(tag)); + } + + printer->Print(",\n"); } for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { @@ -2178,15 +2167,6 @@ GenerateSharedConstructorCode(io::Printer* printer) { "classname", classname_); printer->Indent(); - bool need_to_clear_cached_size = true; - // We reproduce the logic used for laying out _cached_sized_ in the class - // definition, as to initialize it in-order. - if (HasFieldPresence(descriptor_->file()) && - (HasBitsSize() % 8) != 0) { - printer->Print("_cached_size_ = 0;\n"); - need_to_clear_cached_size = false; - } - std::vector<bool> processed(optimized_order_.size(), false); GenerateConstructorBody(printer, processed, false); @@ -2196,10 +2176,6 @@ GenerateSharedConstructorCode(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - if (need_to_clear_cached_size) { - printer->Print("_cached_size_ = 0;\n"); - } - printer->Outdent(); printer->Print("}\n\n"); } @@ -2304,7 +2280,7 @@ GenerateArenaDestructorCode(io::Printer* printer) { "classname", classname_); } else { printer->Print( - "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" + "void $classname$::RegisterArenaDtor(::google::protobuf::Arena*) {\n" "}\n", "classname", classname_); } @@ -2383,12 +2359,7 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, void MessageGenerator:: GenerateStructors(io::Printer* printer) { string superclass; - if (use_dependent_base_) { - superclass = - DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; - } else { - superclass = SuperClassName(descriptor_, options_); - } + superclass = SuperClassName(descriptor_, options_); string initializer_with_arena = superclass + "()"; if (descriptor_->extension_range_count() > 0) { @@ -2420,15 +2391,14 @@ GenerateStructors(io::Printer* printer) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; } if (num_weak_fields_ > 0) { - initializer_null += ", _weak_field_map_(NULL)"; + initializer_null += ", _weak_field_map_(nullptr)"; } printer->Print( "$classname$::$classname$()\n" " : $initializer$ {\n" - " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" - " }\n" + " ::google::protobuf::internal::InitSCC(\n" + " &$file_namespace$::scc_info_$scc_name$.base);\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", @@ -2440,7 +2410,9 @@ GenerateStructors(io::Printer* printer) { printer->Print( "$classname$::$classname$(::google::protobuf::Arena* arena)\n" " : $initializer$ {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" + " " + "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$." + "base);\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" @@ -2452,112 +2424,110 @@ GenerateStructors(io::Printer* printer) { } // Generate the copy constructor. - printer->Print( - "$classname$::$classname$(const $classname$& from)\n" - " : $superclass$()", - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name()); - printer->Indent(); - printer->Indent(); - printer->Indent(); + if (UsingImplicitWeakFields(descriptor_->file(), options_)) { + // If we are in lite mode and using implicit weak fields, we generate a + // one-liner copy constructor that delegates to MergeFrom. This saves some + // code size and also cuts down on the complexity of implicit weak fields. + // We might eventually want to do this for all lite protos. + printer->Print( + "$classname$::$classname$(const $classname$& from)\n" + " : $classname$() {\n" + " MergeFrom(from);\n" + "}\n", + "classname", classname_); + } else { + printer->Print( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$()", + "classname", classname_, + "superclass", superclass, + "full_name", descriptor_->full_name()); + printer->Indent(); + printer->Indent(); + printer->Indent(); - printer->Print( - ",\n_internal_metadata_(NULL)"); + printer->Print( + ",\n_internal_metadata_(NULL)"); - if (HasFieldPresence(descriptor_->file())) { - printer->Print(",\n_has_bits_(from._has_bits_)"); - } + if (HasFieldPresence(descriptor_->file())) { + printer->Print(",\n_has_bits_(from._has_bits_)"); + } - bool need_to_emit_cached_size = true; - const string cached_size_decl = ",\n_cached_size_(0)"; - // We reproduce the logic used for laying out _cached_sized_ in the class - // definition, as to initialize it in-order. - if (HasFieldPresence(descriptor_->file()) && - (HasBitsSize() % 8) != 0) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; - } + std::vector<bool> processed(optimized_order_.size(), false); + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; - std::vector<bool> processed(optimized_order_.size(), false); - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; + if (!(field->is_repeated() && !(field->is_map())) + ) { + continue; + } - if (!(field->is_repeated() && !(field->is_map())) - ) { - continue; + processed[i] = true; + printer->Print(",\n$name$_(from.$name$_)", + "name", FieldName(field)); } - processed[i] = true; - printer->Print(",\n$name$_(from.$name$_)", - "name", FieldName(field)); - } - - if (need_to_emit_cached_size) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; - } - - if (IsAnyMessage(descriptor_)) { - printer->Print(",\n_any_metadata_(&type_url_, &value_)"); - } - if (num_weak_fields_ > 0) { - printer->Print(",\n_weak_field_map_(from._weak_field_map_)"); - } + if (IsAnyMessage(descriptor_)) { + printer->Print(",\n_any_metadata_(&type_url_, &value_)"); + } + if (num_weak_fields_ > 0) { + printer->Print(",\n_weak_field_map_(from._weak_field_map_)"); + } - printer->Outdent(); - printer->Outdent(); - printer->Print(" {\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print(" {\n"); - printer->Print( - "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); + printer->Print( + "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); - if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); - } + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + } - GenerateConstructorBody(printer, processed, true); + GenerateConstructorBody(printer, processed, true); - // Copy oneof fields. Oneof field requires oneof case check. - for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { - printer->Print( - "clear_has_$oneofname$();\n" - "switch (from.$oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + // Copy oneof fields. Oneof field requires oneof case check. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); + "clear_has_$oneofname$();\n" + "switch (from.$oneofname$_case()) {\n", + "oneofname", descriptor_->oneof_decl(i)->name()); printer->Indent(); - field_generators_.get(field).GenerateMergingCode(printer); + 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", + "field_name", UnderscoresToCamelCase(field->name(), true)); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } printer->Print( - "break;\n"); + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "oneof_index", + SimpleItoa(descriptor_->oneof_decl(i)->index()), + "cap_oneof_name", + ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" - " break;\n" - "}\n", - "oneof_index", - SimpleItoa(descriptor_->oneof_decl(i)->index()), - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); + printer->Outdent(); printer->Print( - "}\n"); + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n", + "full_name", descriptor_->full_name()); } - printer->Outdent(); - printer->Print( - " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" - "}\n" - "\n", - "full_name", descriptor_->full_name()); - // Generate the shared constructor code. GenerateSharedConstructorCode(printer); @@ -2581,12 +2551,10 @@ GenerateStructors(io::Printer* printer) { // Generate SetCachedSize. printer->Print( - "void $classname$::SetCachedSize(int size) const {\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - " _cached_size_ = size;\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "}\n", - "classname", classname_); + "void $classname$::SetCachedSize(int size) const {\n" + " _cached_size_.Set(size);\n" + "}\n", + "classname", classname_); // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file(), options_) && @@ -2605,29 +2573,24 @@ GenerateStructors(io::Printer* printer) { printer->Print( "const $classname$& $classname$::default_instance() {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" + " " + "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$.base)" + ";\n" " return *internal_default_instance();\n" "}\n\n", "classname", classname_, "scc_name", scc_name_, "file_namespace", FileLevelNamespace(descriptor_)); +} - if (SupportsArenas(descriptor_)) { - printer->Print( - "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" - " return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n" - "}\n", - "classname", classname_); - } else { - printer->Print( - "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" - " $classname$* n = new $classname$;\n" - " if (arena != NULL) {\n" - " arena->Own(n);\n" - " }\n" - " return n;\n" +void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { + printer->Print( + "template<> " + "GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE " + "$classname$* Arena::CreateMaybeMessage< $classname$ >(Arena* arena) {\n" + " return Arena::$create_func$Internal< $classname$ >(arena);\n" "}\n", - "classname", classname_); - } + "classname", QualifiedClassName(descriptor_), + "create_func", MessageCreateFunction(descriptor_)); } // Return the number of bits set in n, a non-negative integer. @@ -2681,7 +2644,6 @@ GenerateClear(io::Printer* printer) { printer->Print("_extensions_.Clear();\n"); } - int last_i = -1; int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear; for (int i = 0; i < optimized_order_.size(); i++) { const FieldDescriptor* field = optimized_order_[i]; @@ -2693,197 +2655,162 @@ GenerateClear(io::Printer* printer) { unconditional_budget -= EstimateAlignmentSize(field); } - for (int i = 0; i < optimized_order_.size(); ) { - // Detect infinite loops. - GOOGLE_CHECK_NE(i, last_i); - last_i = i; + std::vector<std::vector<const FieldDescriptor*> > chunks_frag = CollectFields( + optimized_order_, + MatchRepeatedAndHasByteAndZeroInits( + &has_bit_indices_, HasFieldPresence(descriptor_->file()))); + + // Merge next non-zero initializable chunk if it has the same has_byte index + // and not meeting unconditional clear condition. + std::vector<std::vector<const FieldDescriptor*> > chunks; + if (!HasFieldPresence(descriptor_->file())) { + // Don't bother with merging without has_bit field. + chunks = chunks_frag; + } else { + // Note that only the next chunk is considered for merging. + for (int i = 0; i < chunks_frag.size(); i++) { + chunks.push_back(chunks_frag[i]); + const FieldDescriptor* field = chunks_frag[i].front(); + const FieldDescriptor* next_field = + (i + 1) < chunks_frag.size() ? chunks_frag[i + 1].front() : nullptr; + if (CanInitializeByZeroing(field) && + (chunks_frag[i].size() == 1 || unconditional_budget < 0) && + next_field != nullptr && + has_bit_indices_[field->index()] / 8 == + has_bit_indices_[next_field->index()] / 8) { + GOOGLE_CHECK(!CanInitializeByZeroing(next_field)); + // Insert next chunk to the current one and skip next chunk. + chunks.back().insert(chunks.back().end(), chunks_frag[i + 1].begin(), + chunks_frag[i + 1].end()); + i++; + } + } + } + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + GOOGLE_CHECK(!chunk.empty()); // Step 2: Repeated fields don't use _has_bits_; emit code to clear them // here. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - const FieldGenerator& generator = field_generators_.get(field); + if (chunk.front()->is_repeated()) { + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; + const FieldGenerator& generator = field_generators_.get(field); - if (!field->is_repeated()) { - break; + generator.GenerateMessageClearingCode(printer); } - - generator.GenerateMessageClearingCode(printer); + continue; } - // Step 3: Greedily seek runs of fields that can be cleared by - // memset-to-0. - int last_chunk = -1; - int last_chunk_start = -1; - int last_chunk_end = -1; - uint32 last_chunk_mask = 0; - + // Step 3: Non-repeated fields that can be cleared by memset-to-0, then + // non-repeated, non-zero initializable fields. + int last_chunk = HasFieldPresence(descriptor_->file()) + ? has_bit_indices_[chunk.front()->index()] / 8 + : 0; + int last_chunk_start = 0; int memset_run_start = -1; int memset_run_end = -1; - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - - if (!CanInitializeByZeroing(field)) { - break; - } - - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; - - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; - } - if (memset_run_start == -1) { - memset_run_start = i; + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; + if (CanInitializeByZeroing(field)) { + if (memset_run_start == -1) { + memset_run_start = i; + } + memset_run_end = i; } - - memset_run_end = i; - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } - if (memset_run_start != memset_run_end && unconditional_budget >= 0) { - // Flush the memset fields. - goto flush; - } + const bool have_outer_if = + HasFieldPresence(descriptor_->file()) && chunk.size() > 1 && + (memset_run_end != chunk.size() - 1 || unconditional_budget < 0); - // Step 4: Non-repeated, non-zero initializable fields. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field->is_repeated() || CanInitializeByZeroing(field)) { - break; - } + if (have_outer_if) { + uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_); + const int count = popcnt(last_chunk_mask); - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; + if (cached_has_bit_index != last_chunk / 4) { + cached_has_bit_index = last_chunk / 4; + printer->Print("cached_has_bits = _has_bits_[$idx$];\n", "idx", + SimpleItoa(cached_has_bit_index)); } - - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); + printer->Print("if (cached_has_bits & $mask$u) {\n", "mask", + SimpleItoa(last_chunk_mask)); + printer->Indent(); } -flush: - - if (last_chunk != -1) { - GOOGLE_DCHECK_NE(-1, last_chunk_start); - GOOGLE_DCHECK_NE(-1, last_chunk_end); - GOOGLE_DCHECK_NE(0, last_chunk_mask); - - const int count = popcnt(last_chunk_mask); - const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end) && - (memset_run_start != last_chunk_start || - memset_run_end != last_chunk_end || - unconditional_budget < 0); - - if (have_outer_if) { - // Check (up to) 8 has_bits at a time if we have more than one field in - // this chunk. Due to field layout ordering, we may check - // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, count); - GOOGLE_DCHECK_GE(8, count); + if (memset_run_start != -1) { + if (memset_run_start == memset_run_end) { + // For clarity, do not memset a single field. + const FieldGenerator& generator = + field_generators_.get(chunk[memset_run_start]); + generator.GenerateMessageClearingCode(printer); + } else { + const string first_field_name = FieldName(chunk[memset_run_start]); + const string last_field_name = FieldName(chunk[memset_run_end]); - if (cached_has_bit_index != last_chunk / 4) { - cached_has_bit_index = last_chunk / 4; - printer->Print( - "cached_has_bits = _has_bits_[$idx$];\n", - "idx", SimpleItoa(cached_has_bit_index)); - } printer->Print( - "if (cached_has_bits & $mask$u) {\n", - "mask", SimpleItoa(last_chunk_mask)); - printer->Indent(); - } - - if (memset_run_start != -1) { - if (memset_run_start == memset_run_end) { - // For clarity, do not memset a single field. - const FieldGenerator& generator = - field_generators_.get(optimized_order_[memset_run_start]); - generator.GenerateMessageClearingCode(printer); - } else { - const string first_field_name = - FieldName(optimized_order_[memset_run_start]); - const string last_field_name = - FieldName(optimized_order_[memset_run_end]); - - printer->Print( "::memset(&$first$_, 0, static_cast<size_t>(\n" " reinterpret_cast<char*>(&$last$_) -\n" " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n", - "first", first_field_name, - "last", last_field_name); - } - - // Advance last_chunk_start to skip over the fields we zeroed/memset. - last_chunk_start = memset_run_end + 1; + "first", first_field_name, "last", last_field_name); } - // Go back and emit clears for each of the fields we processed. - for (int j = last_chunk_start; j <= last_chunk_end; j++) { - const FieldDescriptor* field = optimized_order_[j]; - const string fieldname = FieldName(field); - const FieldGenerator& generator = field_generators_.get(field); + // Advance last_chunk_start to skip over the fields we zeroed/memset. + last_chunk_start = memset_run_end + 1; + } + + // Go back and emit clears for each of the fields we processed. + for (int j = last_chunk_start; j < chunk.size(); j++) { + const FieldDescriptor* field = chunk[j]; + const string fieldname = FieldName(field); + const FieldGenerator& generator = field_generators_.get(field); - // It's faster to just overwrite primitive types, but we should only - // clear strings and messages if they were set. - // - // TODO(kenton): Let the CppFieldGenerator decide this somehow. - bool should_check_bit = + // It's faster to just overwrite primitive types, but we should only + // clear strings and messages if they were set. + // + // TODO(kenton): Let the CppFieldGenerator decide this somehow. + bool should_check_bit = field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; - bool have_enclosing_if = false; - if (should_check_bit && - // If no field presence, then always clear strings/messages as well. - HasFieldPresence(descriptor_->file())) { - if (!field->options().weak() && - cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) { - cached_has_bit_index = (has_bit_indices_[field->index()] / 32); - printer->Print("cached_has_bits = _has_bits_[$new_index$];\n", - "new_index", SimpleItoa(cached_has_bit_index)); - } - if (!MaybeGenerateOptionalFieldCondition(printer, field, - cached_has_bit_index)) { - printer->Print( - "if (has_$name$()) {\n", - "name", fieldname); - } - printer->Indent(); - have_enclosing_if = true; + bool have_enclosing_if = false; + if (should_check_bit && + // If no field presence, then always clear strings/messages as well. + HasFieldPresence(descriptor_->file())) { + if (!field->options().weak() && + cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) { + cached_has_bit_index = (has_bit_indices_[field->index()] / 32); + printer->Print("cached_has_bits = _has_bits_[$new_index$];\n", + "new_index", SimpleItoa(cached_has_bit_index)); } - - generator.GenerateMessageClearingCode(printer); - - if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); + if (!MaybeGenerateOptionalFieldCondition(printer, field, + cached_has_bit_index)) { + printer->Print("if (has_$name$()) {\n", "name", fieldname); } + printer->Indent(); + have_enclosing_if = true; } - if (have_outer_if) { + generator.GenerateMessageClearingCode(printer); + + if (have_enclosing_if) { printer->Outdent(); printer->Print("}\n"); } } + + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); + } } // Step 4: Unions. @@ -3033,7 +2960,6 @@ GenerateSwap(io::Printer* printer) { printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - printer->Print("swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Swap(&other->_extensions_);\n"); } @@ -3349,7 +3275,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "}\n"); return; } - std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); @@ -3379,9 +3304,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) { return; } + if (SupportsArenas(descriptor_)) { + for (int i = 0; i < ordered_fields.size(); i++) { + const FieldDescriptor* field = ordered_fields[i]; + const FieldGenerator& field_generator = field_generators_.get(field); + if (field_generator.MergeFromCodedStreamNeedsArena()) { + printer->Print( + " ::google::protobuf::Arena* arena = GetArenaNoVirtual();\n"); + break; + } + } + } + printer->Print( - "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n" - " ::google::protobuf::uint32 tag;\n"); + "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto " + "failure\n" + " ::google::protobuf::uint32 tag;\n"); if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( @@ -3402,8 +3340,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("for (;;) {\n"); printer->Indent(); - uint32 maxtag = descriptor_->field_count() == 0 ? 0 : - WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]); + // To calculate the maximum tag to expect, we look at the highest-numbered + // field. We need to be prepared to handle more than one wire type if that + // field is a packable repeated field, so to simplify things we assume the + // highest possible wire type of 5. + uint32 maxtag = + ordered_fields.empty() ? 0 : ordered_fields.back()->number() * 8 + 5; const int kCutoff0 = 127; // fits in 1-byte varint const int kCutoff1 = (127 << 7) + 127; // fits in 2-byte varint @@ -3421,6 +3363,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { break; } } + + for (int i = 0; i < parent->extension_count(); i++) { + const FieldDescriptor* field = parent->extension(i); + if (field->type() == FieldDescriptor::TYPE_GROUP && + field->message_type() == descriptor_) { + capture_last_tag = true; + break; + } + } } for (int i = 0; i < descriptor_->file()->extension_count(); i++) { @@ -3432,7 +3383,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } - printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = " + printer->Print("::std::pair<::google::protobuf::uint32, bool> p = " "input->ReadTagWithCutoffNoLastTag($max$u);\n" "tag = p.first;\n" "if (!p.second) goto handle_unusual;\n", @@ -3531,7 +3482,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Outdent(); printer->Print("}\n\n"); } - printer->Print("default: {\n"); printer->Indent(); } @@ -3922,7 +3872,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { // Merge the fields and the extension ranges, both sorted by field number. { LazySerializerEmitter e(this, printer, to_array); - const FieldDescriptor* last_weak_field = NULL; + const FieldDescriptor* last_weak_field = nullptr; int i, j; for (i = 0, j = 0; i < ordered_fields.size() || j < sorted_extensions.size();) { @@ -3934,16 +3884,16 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { last_weak_field = field; PrintFieldComment(printer, field); } else { - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); - last_weak_field = NULL; + last_weak_field = nullptr; } e.Emit(field); } } else { - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); - last_weak_field = NULL; + last_weak_field = nullptr; } e.Flush(); GenerateSerializeOneExtensionRange(printer, @@ -3951,7 +3901,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { to_array); } } - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); } } @@ -4013,8 +3963,9 @@ static string ConditionalToCheckBitmasks(const std::vector<uint32>& masks) { } GOOGLE_CHECK(!parts.empty()); // If we have multiple parts, each expected to be 0, then bitwise-or them. - string result = parts.size() == 1 ? parts[0] : - StrCat("(", Join(parts, "\n | "), ")"); + string result = parts.size() == 1 + ? parts[0] + : StrCat("(", Join(parts, "\n | "), ")"); return result + " == 0"; } @@ -4027,20 +3978,19 @@ GenerateByteSize(io::Printer* printer) { SetUnknkownFieldsVariable(descriptor_, options_, &vars); vars["classname"] = classname_; vars["full_name"] = descriptor_->full_name(); - printer->Print(vars, - "size_t $classname$::ByteSizeLong() const {\n" - "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " size_t total_size = _extensions_.MessageSetByteSize();\n" - " if ($have_unknown_fields$) {\n" - " total_size += ::google::protobuf::internal::WireFormat::\n" - " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" - " }\n" - " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - " _cached_size_ = cached_size;\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - " return total_size;\n" - "}\n"); + printer->Print( + vars, + "size_t $classname$::ByteSizeLong() const {\n" + "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" + " size_t total_size = _extensions_.MessageSetByteSize();\n" + " if ($have_unknown_fields$) {\n" + " total_size += ::google::protobuf::internal::WireFormat::\n" + " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" + " }\n" + " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + " SetCachedSize(cached_size);\n" + " return total_size;\n" + "}\n"); return; } @@ -4141,28 +4091,30 @@ GenerateByteSize(io::Printer* printer) { } } - int last_i = -1; - for (int i = 0; i < optimized_order_.size(); ) { - // Detect infinite loops. - GOOGLE_CHECK_NE(i, last_i); - last_i = i; + std::vector<std::vector<const FieldDescriptor*> > chunks = CollectFields( + optimized_order_, + MatchRepeatedAndHasByteAndRequired( + &has_bit_indices_, HasFieldPresence(descriptor_->file()))); - // Skip required fields. - for (; i < optimized_order_.size() && - optimized_order_[i]->is_required(); i++) { - } + // Remove chunks with required fields. + chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired), + chunks.end()); + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + GOOGLE_CHECK(!chunk.empty()); // Handle repeated fields. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (!field->is_repeated()) { - break; - } + if (chunk.front()->is_repeated()) { + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; - PrintFieldComment(printer, field); - const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateByteSize(printer); - printer->Print("\n"); + PrintFieldComment(printer, field); + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateByteSize(printer); + printer->Print("\n"); + } + continue; } // Handle optional (non-repeated/oneof) fields. @@ -4174,92 +4126,62 @@ GenerateByteSize(io::Printer* printer) { // descriptor_->field(8), descriptor_->field(9), ... // descriptor_->field(15), // etc. - int last_chunk = -1; - int last_chunk_start = -1; - int last_chunk_end = -1; - uint32 last_chunk_mask = 0; - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field->is_repeated() || field->is_required()) { - break; - } + int last_chunk = HasFieldPresence(descriptor_->file()) + ? has_bit_indices_[chunk.front()->index()] / 8 + : 0; + GOOGLE_DCHECK_NE(-1, last_chunk); - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; + const bool have_outer_if = + HasFieldPresence(descriptor_->file()) && chunk.size() > 1; - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; - } + if (have_outer_if) { + uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_); + const int count = popcnt(last_chunk_mask); - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); - } + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); - if (last_chunk != -1) { - GOOGLE_DCHECK_NE(-1, last_chunk_start); - GOOGLE_DCHECK_NE(-1, last_chunk_end); - GOOGLE_DCHECK_NE(0, last_chunk_mask); + printer->Print("if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index", + SimpleItoa(last_chunk * 8), "mask", + SimpleItoa(last_chunk_mask)); + printer->Indent(); + } - const int count = popcnt(last_chunk_mask); - const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end); + // Go back and emit checks for each of the fields we processed. + for (int j = 0; j < chunk.size(); j++) { + const FieldDescriptor* field = chunk[j]; + const FieldGenerator& generator = field_generators_.get(field); - if (have_outer_if) { - // Check (up to) 8 has_bits at a time if we have more than one field in - // this chunk. Due to field layout ordering, we may check - // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, count); - GOOGLE_DCHECK_GE(8, count); + PrintFieldComment(printer, field); - printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$u) {\n", - "index", SimpleItoa(last_chunk * 8), - "mask", SimpleItoa(last_chunk_mask)); + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print("if (has_$name$()) {\n", "name", FieldName(field)); printer->Indent(); + have_enclosing_if = true; + } else { + // Without field presence: field is serialized only if it has a + // non-default value. + have_enclosing_if = + EmitFieldNonDefaultCondition(printer, "this->", field); } - // Go back and emit checks for each of the fields we processed. - for (int j = last_chunk_start; j <= last_chunk_end; j++) { - const FieldDescriptor* field = optimized_order_[j]; - const FieldGenerator& generator = field_generators_.get(field); - - PrintFieldComment(printer, field); - - bool have_enclosing_if = false; - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); - have_enclosing_if = true; - } else { - // Without field presence: field is serialized only if it has a - // non-default value. - have_enclosing_if = EmitFieldNonDefaultCondition( - printer, "this->", field); - } - - generator.GenerateByteSize(printer); + generator.GenerateByteSize(printer); - if (have_enclosing_if) { - printer->Outdent(); - printer->Print( + if (have_enclosing_if) { + printer->Outdent(); + printer->Print( "}\n" "\n"); - } } + } - if (have_outer_if) { - printer->Outdent(); - printer->Print("}\n"); - } + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); } } @@ -4300,17 +4222,18 @@ GenerateByteSize(io::Printer* printer) { printer->Print("total_size += _weak_field_map_.ByteSizeLong();\n"); } - // We update _cached_size_ even though this is a const method. In theory, - // this is not thread-compatible, because concurrent writes have undefined - // results. In practice, since any concurrent writes will be writing the - // exact same value, it works on all common processors. In a future version - // of C++, _cached_size_ should be made into an atomic<int>. + // We update _cached_size_ even though this is a const method. Because + // const methods might be called concurrently this needs to be atomic + // operations or the program is undefined. In practice, since any concurrent + // writes will be writing the exact same value, normal writes will work on + // all common processors. We use a dedicated wrapper class to abstract away + // the underlying atomic. This makes it easier on platforms where even relaxed + // memory order might have perf impact to replace it with ordinary loads and + // stores. printer->Print( - "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_cached_size_ = cached_size;\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "return total_size;\n"); + "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + "SetCachedSize(cached_size);\n" + "return total_size;\n"); printer->Outdent(); printer->Print("}\n"); @@ -4359,10 +4282,17 @@ GenerateIsInitialized(io::Printer* printer) { !ShouldIgnoreRequiredFieldCheck(field, options_) && scc_analyzer_->HasRequiredFields(field->message_type())) { if (field->is_repeated()) { - printer->Print( - "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" - " return false;\n", - "name", FieldName(field)); + if (IsImplicitWeakField(field, options_, scc_analyzer_)) { + printer->Print( + "if (!::google::protobuf::internal::AllAreInitializedWeak(this->$name$_))" + " return false;\n", + "name", FieldName(field)); + } else { + printer->Print( + "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" + " return false;\n", + "name", FieldName(field)); + } } else if (field->options().weak()) { continue; } else { diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 0387f0ca..ca2ca2c9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -36,9 +36,6 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <set> #include <string> #include <google/protobuf/compiler/cpp/cpp_field.h> @@ -87,9 +84,6 @@ class MessageGenerator { // file). void GenerateInlineMethods(io::Printer* printer); - // Dependent methods are always inline. - void GenerateDependentInlineMethods(io::Printer* printer); - // Source file stuff. // Generate extra fields @@ -106,12 +100,12 @@ class MessageGenerator { // Generate all non-inline methods for this class. void GenerateClassMethods(io::Printer* printer); + // Generate source file code that should go outside any namespace. + void GenerateSourceInProto2Namespace(io::Printer* printer); + 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 GenerateDependentFieldAccessorDefinitions(io::Printer* printer); void GenerateFieldAccessorDefinitions(io::Printer* printer); // Generate the table-driven parsing array. Returns the number of entries @@ -219,15 +213,14 @@ class MessageGenerator { std::vector<const FieldDescriptor *> optimized_order_; std::vector<int> has_bit_indices_; int max_has_bit_index_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_; + std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_; + std::unique_ptr<std::unique_ptr<ExtensionGenerator> []> extension_generators_; int num_required_fields_; - bool use_dependent_base_; int num_weak_fields_; // table_driven_ indicates the generated message uses table-driven parsing. bool table_driven_; - google::protobuf::scoped_ptr<MessageLayoutHelper> message_layout_helper_; + std::unique_ptr<MessageLayoutHelper> message_layout_helper_; SCCAnalyzer* scc_analyzer_; string scc_name_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index fe60a283..c1e15c52 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -70,21 +70,18 @@ string ReinterpretCast(const string& type, const string& expression, } void SetMessageVariables(const FieldDescriptor* descriptor, - std::map<string, string>* variables, - const Options& options) { + const Options& options, bool implicit_weak, + std::map<string, string>* variables) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); - (*variables)["casted_member"] = - ReinterpretCast((*variables)["type"] + "*", (*variables)["name"] + "_", - IsImplicitWeakField(descriptor, options)); + (*variables)["casted_member"] = ReinterpretCast( + (*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak); (*variables)["type_default_instance"] = DefaultInstanceName(descriptor->message_type()); (*variables)["type_reference_function"] = - ReferenceFunctionName(descriptor->message_type()); - if (descriptor->options().weak() || !descriptor->containing_oneof()) { - (*variables)["non_null_ptr_to_name"] = - StrCat("this->", (*variables)["name"], "_"); - } + implicit_weak + ? (" " + ReferenceFunctionName(descriptor->message_type()) + "();\n") + : ""; (*variables)["stream_writer"] = (*variables)["declared_type"] + (HasFastArraySerialization(descriptor->message_type()->file(), options) @@ -96,14 +93,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); - if (options.proto_h && IsFieldDependent(descriptor)) { - (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor); - (*variables)["dependent_typename"] = - "typename T::" + DependentTypeName(descriptor); - } else { - (*variables)["dependent_type"] = FieldMessageTypeName(descriptor); - (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor); - } } } // namespace @@ -111,12 +100,13 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // =================================================================== MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) + const Options& options, + SCCAnalyzer* scc_analyzer) : FieldGenerator(options), descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)), - implicit_weak_field_(IsImplicitWeakField(descriptor, options)) { - SetMessageVariables(descriptor, &variables_, options); + implicit_weak_field_( + IsImplicitWeakField(descriptor, options, scc_analyzer)) { + SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } MessageFieldGenerator::~MessageFieldGenerator() {} @@ -124,38 +114,30 @@ MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { if (implicit_weak_field_) { - printer->Print(variables_, "google::protobuf::MessageLite* $name$_;\n"); + printer->Print(variables_, "::google::protobuf::MessageLite* $name$_;\n"); } else { printer->Print(variables_, "$type$* $name$_;\n"); } } void MessageFieldGenerator:: -GenerateDependentAccessorDeclarations(io::Printer* printer) const { - if (!dependent_field_) { - return; - } - printer->Print(variables_, - "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); -} - -void MessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - if (SupportsArenas(descriptor_) && !implicit_weak_field_) { - printer->Print(variables_, - "private:\n" - "void _slow_mutable_$name$();\n" - "public:\n"); - } if (implicit_weak_field_) { // These private accessors are used by MergeFrom and // MergePartialFromCodedStream, and their purpose is to provide access to // the field without creating a strong dependency on the message type. printer->Print(variables_, "private:\n" - "const google::protobuf::MessageLite& _internal_$name$() const;\n" - "google::protobuf::MessageLite* _internal_mutable_$name$();\n" + "const ::google::protobuf::MessageLite& _internal_$name$() const;\n" + "::google::protobuf::MessageLite* _internal_mutable_$name$();\n" + "public:\n"); + } else { + // This inline accessor directly returns member field and is used in + // Serialize such that AFDO profile correctly captures access information to + // message fields under serialize. + printer->Print(variables_, + "private:\n" + "const $type$& _internal_$name$() const;\n" "public:\n"); } printer->Print(variables_, @@ -163,11 +145,9 @@ GenerateAccessorDeclarations(io::Printer* printer) const { printer->Annotate("name", descriptor_); printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n"); printer->Annotate("release_name", descriptor_); - if (!dependent_field_) { - printer->Print(variables_, - "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - } + printer->Print(variables_, + "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); printer->Print(variables_, "$deprecated_attr$void ${$set_allocated_$name$$}$" "($type$* $name$);\n"); @@ -189,22 +169,22 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( io::Printer* printer) const { if (implicit_weak_field_) { printer->Print(variables_, - "const google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n" + "const ::google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n" " if ($name$_ != NULL) {\n" " return *$name$_;\n" " } else if (&$type_default_instance$ != NULL) {\n" - " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " return *reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" " &$type_default_instance$);\n" " } else {\n" - " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n" - " &::google::protobuf::internal::implicit_weak_message_default_instance);\n" + " return " + "*::google::protobuf::internal::ImplicitWeakMessage::default_instance();\n" " }\n" "}\n"); } if (SupportsArenas(descriptor_)) { if (implicit_weak_field_) { printer->Print(variables_, - "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" + "::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " if (&$type_default_instance$ == NULL) {\n" @@ -212,26 +192,13 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " ::google::protobuf::internal::ImplicitWeakMessage>(\n" " GetArenaNoVirtual());\n" " } else {\n" - " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" " &$type_default_instance$)->New(GetArenaNoVirtual());\n" " }\n" " }\n" - " return $name$_;\n"); - } else { - 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"); - } + " return $name$_;\n" + "}\n"); } - printer->Print(variables_, - "}\n"); printer->Print(variables_, "void $classname$::unsafe_arena_set_allocated_$name$(\n" @@ -252,13 +219,13 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( "}\n"); } else if (implicit_weak_field_) { printer->Print(variables_, - "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" + "::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " if (&$type_default_instance$ == NULL) {\n" " $name$_ = new ::google::protobuf::internal::ImplicitWeakMessage;\n" " } else {\n" - " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" " &$type_default_instance$)->New();\n" " }\n" " }\n" @@ -268,118 +235,43 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( } void MessageFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { - if (!dependent_field_) { - return; - } - - std::map<string, string> variables(variables_); - // For the CRTP base class, all mutation methods are dependent, and so - // they must be in the header. - variables["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; - variables["this_message"] = DependentBaseDownCast(); - variables["casted_reference"] = - ReinterpretCast(variables["dependent_typename"] + "*&", - variables["this_message"] + variables["name"] + "_", - implicit_weak_field_); - if (!variables["set_hasbit"].empty()) { - variables["set_hasbit"] = - variables["this_message"] + variables["set_hasbit"]; - } - if (!variables["clear_hasbit"].empty()) { - variables["clear_hasbit"] = - variables["this_message"] + variables["clear_hasbit"]; - } - - if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "template <class T>\n" - "inline $type$* $dependent_classname$::mutable_$name$() {\n"); - if (implicit_weak_field_) { - printer->Print(variables, " $type_reference_function$();\n"); - } - printer->Print(variables, - " $set_hasbit$\n" - " $dependent_typename$*& $name$_ = $casted_reference$;\n" - " if ($name$_ == NULL) {\n"); - if (implicit_weak_field_) { - printer->Print(variables, - " $name$_ = reinterpret_cast<$dependent_typename$*>(\n" - " reinterpret_cast<const google::protobuf::MessageLite*>(\n" - " &$type_default_instance$)->New(\n" - " $this_message$GetArenaNoVirtual()));\n"); - } else { - printer->Print(variables, - " $this_message$_slow_mutable_$name$();\n"); - } - printer->Print(variables, - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" - "}\n"); - } else { - printer->Print(variables, - "template <class T>\n" - "inline $type$* $dependent_classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " $dependent_typename$*& $name$_ = $casted_reference$;\n" - " if ($name$_ == NULL) {\n" - " $name$_ = new $dependent_typename$;\n" - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" - "}\n"); - } -} - -void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - std::map<string, string> variables(variables_); - variables["const_member"] = ReinterpretCast( - "const " + variables["type"] + "*", variables["name"] + "_", - implicit_weak_field_); - printer->Print(variables, - "inline const $type$& $classname$::$name$() const {\n"); - if (implicit_weak_field_) { - printer->Print(variables, " $type_reference_function$();\n"); + if (!implicit_weak_field_) { + printer->Print(variables_, + "inline const $type$& $classname$::_internal_$name$() const {\n" + " return *$field_member$;\n" + "}\n"); } - printer->Print(variables, - " const $type$* p = $const_member$;\n" + printer->Print(variables_, + "inline const $type$& $classname$::$name$() const {\n" + " const $type$* p = $casted_member$;\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n" " &$type_default_instance$);\n" "}\n"); - printer->Print(variables, + printer->Print(variables_, "inline $type$* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n"); - if (implicit_weak_field_) { - printer->Print(variables, " $type_reference_function$();\n"); - } - printer->Print(variables, + " // @@protoc_insertion_point(field_release:$full_name$)\n" + "$type_reference_function$" " $clear_hasbit$\n" " $type$* temp = $casted_member$;\n"); if (SupportsArenas(descriptor_)) { - printer->Print(variables, + printer->Print(variables_, " if (GetArenaNoVirtual() != NULL) {\n" - " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n" + " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n" " }\n"); } - printer->Print(variables, + printer->Print(variables_, " $name$_ = NULL;\n" " return temp;\n" "}\n"); if (SupportsArenas(descriptor_)) { - printer->Print(variables, + printer->Print(variables_, "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(" - "field_unsafe_arena_release:$full_name$)\n"); - if (implicit_weak_field_) { - printer->Print(variables, " $type_reference_function$();\n"); - } - printer->Print(variables, + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + "$type_reference_function$" " $clear_hasbit$\n" " $type$* temp = $casted_member$;\n" " $name$_ = NULL;\n" @@ -387,71 +279,57 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n"); } - if (!dependent_field_) { - if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "inline $type$* $classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " if ($name$_ == NULL) {\n"); - if (implicit_weak_field_) { - printer->Print(variables, - " _internal_mutable_$name$();\n"); - } else { - printer->Print(variables, - " _slow_mutable_$name$();\n"); - } - printer->Print(variables, - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $casted_member$;\n" - "}\n"); - } else { - printer->Print(variables, - "inline $type$* $classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " if ($name$_ == NULL) {\n" - " $name$_ = new $type$;\n" - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $casted_member$;\n" - "}\n"); - } + printer->Print(variables_, + "inline $type$* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n" + " auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n"); + if (implicit_weak_field_) { + printer->Print(variables_, + " $name$_ = reinterpret_cast<::google::protobuf::MessageLite*>(p);\n"); + } else { + printer->Print(variables_, + " $name$_ = p;\n"); } - + printer->Print(variables_, + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $casted_member$;\n" + "}\n"); // We handle the most common case inline, and delegate less common cases to // the slow fallback function. - printer->Print(variables, + printer->Print(variables_, "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"); - printer->Print(variables, + printer->Print(variables_, " if (message_arena == NULL) {\n"); if (IsCrossFileMessage(descriptor_)) { - printer->Print(variables, + printer->Print(variables_, " delete reinterpret_cast< ::google::protobuf::MessageLite*>($name$_);\n"); } else { - printer->Print(variables, + printer->Print(variables_, " delete $name$_;\n"); } - printer->Print(variables, + printer->Print(variables_, " }\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type()) && IsCrossFileMessage(descriptor_)) { // We have to read the arena through the virtual method, because the type // isn't defined in this file. - printer->Print(variables, + printer->Print(variables_, " ::google::protobuf::Arena* submessage_arena =\n" - " reinterpret_cast< ::google::protobuf::MessageLite*>($name$)->GetArena();\n"); + " reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n"); } else if (!SupportsArenas(descriptor_->message_type())) { - printer->Print(variables, + printer->Print(variables_, " ::google::protobuf::Arena* submessage_arena = NULL;\n"); } else { - printer->Print(variables, + printer->Print(variables_, " ::google::protobuf::Arena* submessage_arena =\n" " ::google::protobuf::Arena::GetArena($name$);\n"); } - printer->Print(variables, + printer->Print(variables_, " if (message_arena != submessage_arena) {\n" " $name$ = ::google::protobuf::internal::GetOwnedMessage(\n" " message_arena, $name$, submessage_arena);\n" @@ -461,13 +339,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $clear_hasbit$\n" " }\n"); if (implicit_weak_field_) { - printer->Print(variables, + printer->Print(variables_, " $name$_ = reinterpret_cast<MessageLite*>($name$);\n"); } else { - printer->Print(variables, + printer->Print(variables_, " $name$_ = $name$;\n"); } - printer->Print(variables, + printer->Print(variables_, " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); } @@ -540,34 +418,12 @@ GenerateConstructorCode(io::Printer* printer) const { void MessageFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { - // For non-Arena enabled messages, everything always goes on the heap. - // - // For Arena enabled messages, the logic is a bit more convoluted. - // - // In the copy constructor, we call InternalMetadataWithArena::MergeFrom, - // which does *not* copy the Arena pointer. In the generated MergeFrom - // (see MessageFieldGenerator::GenerateMergingCode), we: - // -> copy the has bits (but this is done in bulk by a memcpy in the copy - // constructor) - // -> check whether the destination field pointer is NULL (it will be, since - // we're initializing it and would have called SharedCtor) and if so: - // -> call _slow_mutable_$name$(), which calls either - // ::google::protobuf::Arena::CreateMessage<>(GetArenaNoVirtual()), or - // ::google::protobuf::Arena::Create<>(GetArenaNoVirtual()) - // - // At this point, GetArenaNoVirtual returns NULL since the Arena pointer - // wasn't copied, so both of these methods allocate the submessage on the - // heap. - - string new_expression = (implicit_weak_field_ ? "from.$name$_->New()" - : "new $type$(*from.$name$_)"); - string output = - "if (from.has_$name$()) {\n" - " $name$_ = " + new_expression + ";\n" - "} else {\n" - " $name$_ = NULL;\n" - "}\n"; - printer->Print(variables_, output.c_str()); + printer->Print(variables_, + "if (from.has_$name$()) {\n" + " $name$_ = new $type$(*from.$name$_);\n" + "} else {\n" + " $name$_ = NULL;\n" + "}\n"); } void MessageFieldGenerator:: @@ -591,7 +447,7 @@ void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" - " $number$, *$non_null_ptr_to_name$, output);\n"); + " $number$, this->_internal_$name$(), output);\n"); } void MessageFieldGenerator:: @@ -599,7 +455,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { printer->Print(variables_, "target = ::google::protobuf::internal::WireFormatLite::\n" " InternalWrite$declared_type$ToArray(\n" - " $number$, *$non_null_ptr_to_name$, deterministic, target);\n"); + " $number$, this->_internal_$name$(), deterministic, target);\n"); } void MessageFieldGenerator:: @@ -607,16 +463,15 @@ GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, "total_size += $tag_size$ +\n" " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " *$non_null_ptr_to_name$);\n"); + " *$field_member$);\n"); } // =================================================================== -MessageOneofFieldGenerator:: -MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : MessageFieldGenerator(descriptor, options), - dependent_base_(options.proto_h) { +MessageOneofFieldGenerator::MessageOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options, + SCCAnalyzer* scc_analyzer) + : MessageFieldGenerator(descriptor, options, scc_analyzer) { SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -635,7 +490,7 @@ void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( // isn't defined in this file. printer->Print(variables_, " ::google::protobuf::Arena* submessage_arena =\n" - " reinterpret_cast< ::google::protobuf::MessageLite*>($name$)->GetArena();\n"); + " reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n"); } else if (!SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, " ::google::protobuf::Arena* submessage_arena = NULL;\n"); @@ -650,57 +505,33 @@ void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( " message_arena, $name$, submessage_arena);\n" " }\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); } void MessageOneofFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { - // For the CRTP base class, all mutation methods are dependent, and so - // they must be in the header. - if (!dependent_base_) { - return; - } - std::map<string, string> variables(variables_); - variables["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; - variables["this_message"] = "reinterpret_cast<T*>(this)->"; - // Const message access is needed for the dependent getter. - variables["this_const_message"] = "reinterpret_cast<const T*>(this)->"; - variables["tmpl"] = "template <class T>\n"; - variables["field_member"] = variables["this_message"] + - variables["oneof_prefix"] + variables["name"] + - "_"; - InternalGenerateInlineAccessorDefinitions(variables, printer); -} - -void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - - std::map<string, string> variables(variables_); - variables["dependent_classname"] = variables["classname"]; - variables["this_message"] = ""; - variables["this_const_message"] = ""; - variables["tmpl"] = ""; - variables["field_member"] = - variables["oneof_prefix"] + variables["name"] + "_"; - variables["dependent_type"] = variables["type"]; - - printer->Print(variables, + if (!implicit_weak_field_) { + printer->Print(variables_, + "inline const $type$& $classname$::_internal_$name$() const {\n" + " return *$field_member$;\n" + "}\n"); + } + printer->Print(variables_, "inline $type$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" - " if ($this_message$has_$name$()) {\n" - " $this_message$clear_has_$oneof_name$();\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" " $type$* temp = $field_member$;\n"); if (SupportsArenas(descriptor_)) { - printer->Print(variables, - " if ($this_message$GetArenaNoVirtual() != NULL) {\n" - " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n" + printer->Print(variables_, + " if (GetArenaNoVirtual() != NULL) {\n" + " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n" " }\n"); } - printer->Print(variables, + printer->Print(variables_, " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" @@ -708,23 +539,23 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " }\n" "}\n"); - printer->Print(variables, + printer->Print(variables_, "inline const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $this_const_message$has_$name$()\n" - " ? *$this_const_message$$oneof_prefix$$name$_\n" + " return has_$name$()\n" + " ? *$field_member$\n" " : *reinterpret_cast< $type$*>(&$type_default_instance$);\n" "}\n"); if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "inline $type$* $dependent_classname$::unsafe_arena_release_$name$() {\n" + printer->Print(variables_, + "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" " // @@protoc_insertion_point(field_unsafe_arena_release" ":$full_name$)\n" - " if ($this_message$has_$name$()) {\n" - " $this_message$clear_has_$oneof_name$();\n" - " $type$* temp = $this_message$$oneof_prefix$$name$_;\n" - " $this_message$$oneof_prefix$$name$_ = NULL;\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" @@ -738,58 +569,24 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " clear_$oneof_name$();\n" " if ($name$) {\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" "$full_name$)\n" "}\n"); } - if (dependent_base_) { - return; - } - - InternalGenerateInlineAccessorDefinitions(variables, printer); -} - -void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions( - const std::map<string, string>& variables, io::Printer* printer) const { - if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "$tmpl$" - "inline $type$* $dependent_classname$::mutable_$name$() {\n" - " if (!$this_message$has_$name$()) {\n" - " $this_message$clear_$oneof_name$();\n" - " $this_message$set_has_$name$();\n"); - if (SupportsArenas(descriptor_->message_type())) { - printer->Print(variables, - " $field_member$ = \n" - " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" - " $this_message$GetArenaNoVirtual());\n"); - } else { - printer->Print(variables, - " $this_message$$oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::Create< $dependent_typename$ >(\n" - " $this_message$GetArenaNoVirtual());\n"); - } - printer->Print(variables, - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $field_member$;\n" - "}\n"); - } else { - printer->Print(variables, - "$tmpl$" - "inline $type$* $dependent_classname$::mutable_$name$() {\n" - " if (!$this_message$has_$name$()) {\n" - " $this_message$clear_$oneof_name$();\n" - " $this_message$set_has_$name$();\n" - " $field_member$ = new $dependent_typename$;\n" - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $field_member$;\n" - "}\n"); - } + printer->Print(variables_, + "inline $type$* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$ = CreateMaybeMessage< $type$ >(\n" + " GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $field_member$;\n" + "}\n"); } void MessageOneofFieldGenerator:: @@ -797,11 +594,11 @@ GenerateClearingCode(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables_, "if (GetArenaNoVirtual() == NULL) {\n" - " delete $oneof_prefix$$name$_;\n" + " delete $field_member$;\n" "}\n"); } else { printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + "delete $field_member$;\n"); } } @@ -830,12 +627,13 @@ GenerateConstructorCode(io::Printer* printer) const { // =================================================================== RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) + const FieldDescriptor* descriptor, const Options& options, + SCCAnalyzer* scc_analyzer) : FieldGenerator(options), descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)), - dependent_getter_(dependent_field_ && options.safe_boundary_check) { - SetMessageVariables(descriptor, &variables_, options); + implicit_weak_field_( + IsImplicitWeakField(descriptor, options, scc_analyzer)) { + SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} @@ -847,164 +645,103 @@ GeneratePrivateMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { +GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n"); printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - if (dependent_getter_) { - printer->Print(variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const;\n"); - printer->Annotate("name", descriptor_); - } printer->Print(variables_, "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" " ${$mutable_$name$$}$();\n"); printer->Annotate("{", "}", descriptor_); -} - -void RepeatedMessageFieldGenerator:: -GenerateDependentAccessorDeclarations(io::Printer* printer) const { - if (dependent_getter_) { - printer->Print(variables_, - "$deprecated_attr$const $type$& $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - } - if (dependent_field_) { - InternalGenerateTypeDependentAccessorDeclarations(printer); - } -} -void RepeatedMessageFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { - if (!dependent_getter_) { - printer->Print(variables_, - "$deprecated_attr$const $type$& $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - } - if (!dependent_field_) { - InternalGenerateTypeDependentAccessorDeclarations(printer); - } - if (!dependent_getter_) { - printer->Print(variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const;\n"); - printer->Annotate("name", descriptor_); - } + printer->Print(variables_, + "$deprecated_attr$const $type$& $name$(int index) const;\n"); + printer->Annotate("name", descriptor_); + printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(variables_, + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const;\n"); + printer->Annotate("name", descriptor_); } void RepeatedMessageFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { - if (!dependent_field_) { - return; - } - std::map<string, string> variables(variables_); - // For the CRTP base class, all mutation methods are dependent, and so - // they must be in the header. - variables["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; - variables["this_message"] = DependentBaseDownCast(); - variables["this_const_message"] = DependentBaseConstDownCast(); - - if (dependent_getter_) { - printer->Print(variables, - "template <class T>\n" - "inline const $type$& $dependent_classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $this_const_message$$name$_.$cppget$(index);\n" - "}\n"); - } - - // Generate per-element accessors: - printer->Print(variables, - "template <class T>\n" - "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n" +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$* $classname$::mutable_$name$(int index) {\n" // TODO(dlj): move insertion points " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $this_message$$name$_.Mutable(index);\n" + "$type_reference_function$" + " return $name$_.Mutable(index);\n" "}\n" - "template <class T>\n" - "inline $type$* $dependent_classname$::add_$name$() {\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $this_message$$name$_.Add();\n" - "}\n"); - - if (dependent_getter_) { - printer->Print(variables, - "template <class T>\n" - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$dependent_classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $this_const_message$$name$_;\n" - "}\n"); - } - - // Generate mutable access to the entire list: - printer->Print(variables, - "template <class T>\n" "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$dependent_classname$::mutable_$name$() {\n" + "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$this_message$$name$_;\n" + "$type_reference_function$" + " return &$name$_;\n" "}\n"); -} -void RepeatedMessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - if (!dependent_getter_) { + if (options_.safe_boundary_check) { 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" + " return $name$_.InternalCheckedGet(index,\n" + " *reinterpret_cast<const $type$*>(&$type_default_instance$));\n" "}\n"); - } - - if (!dependent_field_) { + } else { printer->Print(variables_, - "inline $type$* $classname$::mutable_$name$(int index) {\n" - // TODO(dlj): move insertion points - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" - "}\n" - "inline $type$* $classname$::add_$name$() {\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $name$_.Add();\n" + "inline const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + "$type_reference_function$" + " return $name$_.Get(index);\n" "}\n"); } - if (!dependent_field_) { - printer->Print(variables_, - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" - "}\n"); - } - if (!dependent_getter_) { - 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"); - } + printer->Print(variables_, + "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" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + "$type_reference_function$" + " return $name$_;\n" + "}\n"); } void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + if (implicit_weak_field_) { + printer->Print( + variables_, + "CastToBase(&$name$_)->Clear<" + "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>();\n"); + } else { + printer->Print(variables_, "$name$_.Clear();\n"); + } } void RepeatedMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + if (implicit_weak_field_) { + printer->Print( + variables_, + "CastToBase(&$name$_)->MergeFrom<" + "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase(" + "from.$name$_));\n"); + } else { + printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + } } void RepeatedMessageFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n"); + printer->Print( + variables_, + "CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n"); } void RepeatedMessageFieldGenerator:: @@ -1015,9 +752,18 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::" - "ReadMessage(input, add_$name$()));\n"); + if (implicit_weak_field_) { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n" + " reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" + " &$type_default_instance$))));\n"); + } else { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadMessage(\n" + " input, add_$name$()));\n"); + } } else { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::" @@ -1031,7 +777,19 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { "for (unsigned int i = 0,\n" " n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n" " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" - " $number$, this->$name$(static_cast<int>(i)), output);\n" + " $number$,\n"); + if (implicit_weak_field_) { + printer->Print( + variables_, + " CastToBase($name$_).Get<" + "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(" + "static_cast<int>(i)),\n"); + } else { + printer->Print(variables_, + " this->$name$(static_cast<int>(i)),\n"); + } + printer->Print(variables_, + " output);\n" "}\n"); } @@ -1056,9 +814,18 @@ GenerateByteSize(io::Printer* printer) const { "total_size += $tag_size$UL * count;\n" "for (unsigned int i = 0; i < count; i++) {\n" " total_size +=\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " this->$name$(static_cast<int>(i)));\n" - "}\n"); + " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"); + if (implicit_weak_field_) { + printer->Print( + variables_, + " CastToBase($name$_).Get<" + "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(" + "static_cast<int>(i)));\n"); + } else { + printer->Print(variables_, + " this->$name$(static_cast<int>(i)));\n"); + } + printer->Print(variables_, "}\n"); printer->Outdent(); printer->Print("}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 3be505e3..6879539c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -38,25 +38,22 @@ #include <map> #include <string> #include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { namespace protobuf { namespace compiler { namespace cpp { -bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options); - class MessageFieldGenerator : public FieldGenerator { public: MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + const Options& options, SCCAnalyzer* scc_analyzer); ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; @@ -73,7 +70,6 @@ class MessageFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; - const bool dependent_field_; const bool implicit_weak_field_; std::map<string, string> variables_; @@ -84,11 +80,10 @@ class MessageFieldGenerator : public FieldGenerator { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + const Options& options, SCCAnalyzer* scc_analyzer); ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; @@ -101,24 +96,19 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { void GenerateConstructorCode(io::Printer* printer) const; private: - void InternalGenerateInlineAccessorDefinitions( - const std::map<string, string>& variables, io::Printer* printer) const; - - const bool dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); }; class RepeatedMessageFieldGenerator : public FieldGenerator { public: RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + const Options& options, + SCCAnalyzer* scc_analyzer); ~RepeatedMessageFieldGenerator(); // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; @@ -131,12 +121,8 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: - void InternalGenerateTypeDependentAccessorDeclarations( - io::Printer* printer) const; - const FieldDescriptor* descriptor_; - const bool dependent_field_; - const bool dependent_getter_; + const bool implicit_weak_field_; std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc index f72a7d60..eb7cd1c7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc @@ -34,7 +34,7 @@ #include <gtest/gtest.h> #if LANG_CXX11 -#include <google/protobuf/stubs/type_traits.h> +#include <type_traits> #endif namespace google { diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 4a29ad0e..f09885be 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -54,6 +54,8 @@ struct Options { table_driven_parsing(false), table_driven_serialization(false), lite_implicit_weak_fields(false), + bootstrap(false), + num_cc_files(0), access_info_map(NULL) {} string dllexport_decl; @@ -65,6 +67,8 @@ struct Options { bool table_driven_parsing; bool table_driven_serialization; bool lite_implicit_weak_fields; + bool bootstrap; + int num_cc_files; string annotation_pragma_name; string annotation_guard_name; const AccessInfoMap* access_info_map; diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h index 9641ba40..42a3b5cd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h +++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h @@ -50,10 +50,10 @@ namespace cpp { class PaddingOptimizer : public MessageLayoutHelper { public: PaddingOptimizer() {} - ~PaddingOptimizer() {} + ~PaddingOptimizer() override {} void OptimizeLayout(std::vector<const FieldDescriptor*>* fields, - const Options& options); + const Options& options) override; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc index ceb2270e..ff6ba0f8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -35,9 +35,6 @@ // worth. #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/command_line_interface.h> @@ -172,7 +169,7 @@ class TestGenerator : public CodeGenerator { void TryInsert(const string& filename, const string& insertion_point, GeneratorContext* context) const { - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + std::unique_ptr<io::ZeroCopyOutputStream> output( context->OpenForInsert(filename, insertion_point)); io::Printer printer(output.get(), '$'); printer.Print("// inserted $name$\n", "name", insertion_point); diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index bc2d02ea..701f9d2d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -215,7 +215,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline $type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" " }\n" " return $default$;\n" "}\n" @@ -224,14 +224,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " clear_$oneof_name$();\n" " set_has_$name$();\n" " }\n" - " $oneof_prefix$$name$_ = value;\n" + " $field_member$ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); } void PrimitiveOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n"); + printer->Print(variables_, "$field_member$ = $default$;\n"); } void PrimitiveOneofFieldGenerator:: @@ -251,7 +251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "clear_$oneof_name$();\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " $type$, $wire_format_field_type$>(\n" - " input, &$oneof_prefix$$name$_)));\n" + " input, &$field_member$)));\n" "set_has_$name$();\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 264f6124..cf6c4b33 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -34,8 +34,8 @@ #include <google/protobuf/compiler/cpp/cpp_string_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> @@ -53,7 +53,7 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["default_length"] = SimpleItoa(descriptor->default_value_string().length()); - string default_variable_string = "_default_" + FieldName(descriptor) + "_"; + string default_variable_string = MakeDefaultName(descriptor); (*variables)["default_variable_name"] = default_variable_string; (*variables)["default_variable"] = descriptor->default_value_string().empty() @@ -82,8 +82,24 @@ void SetStringVariables(const FieldDescriptor* descriptor, StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor), - lite_(!HasDescriptorMethods(descriptor->file(), options)) { + : FieldGenerator(options), + descriptor_(descriptor), + lite_(!HasDescriptorMethods(descriptor->file(), options)), + inlined_(false) { + + // TODO(ckennelly): Handle inlining for any.proto. + if (IsAnyMessage(descriptor_->containing_type())) { + inlined_ = false; + } + if (descriptor_->containing_type()->options().map_entry()) { + inlined_ = false; + } + + // Limit to proto2, as we rely on has bits to distinguish field presence for + // release_$name$. On proto3, we cannot use the address of the string + // instance when the field has been inlined. + inlined_ = inlined_ && HasFieldPresence(descriptor_->file()); + SetStringVariables(descriptor, &variables_, options); } @@ -91,27 +107,36 @@ StringFieldGenerator::~StringFieldGenerator() {} void StringFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for - // string fields, even when SupportArenas(descriptor_) == false. Why? - // The simple answer is to avoid unmaintainable complexity. The reflection - // code assumes ArenaStringPtrs. These are *almost* in-memory-compatible with - // string*, except for the pointer tags and related ownership semantics. We - // could modify the runtime code to use string* for the not-supporting-arenas - // case, but this would require a way to detect which type of class was - // generated (adding overhead and complexity to GeneratedMessageReflection) - // and littering the runtime code paths with conditionals. It's simpler to - // stick with this but use lightweight accessors that assume arena == NULL. - // There should be very little overhead anyway because it's just a tagged - // pointer in-memory. - printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n"); + if (inlined_) { + printer->Print(variables_, + "::google::protobuf::internal::InlinedStringField $name$_;\n"); + } else { + // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for + // string fields, even when SupportArenas(descriptor_) == false. Why? The + // simple answer is to avoid unmaintainable complexity. The reflection code + // assumes ArenaStringPtrs. These are *almost* in-memory-compatible with + // string*, except for the pointer tags and related ownership semantics. We + // could modify the runtime code to use string* for the + // not-supporting-arenas case, but this would require a way to detect which + // type of class was generated (adding overhead and complexity to + // GeneratedMessageReflection) and littering the runtime code paths with + // conditionals. It's simpler to stick with this but use lightweight + // accessors that assume arena == NULL. There should be very little + // overhead anyway because it's just a tagged pointer in-memory. + printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n"); + } } void StringFieldGenerator:: GenerateStaticMembers(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { + // We make the default instance public, so it can be initialized by + // non-friend code. printer->Print(variables_, + "public:\n" "static ::google::protobuf::internal::ExplicitlyConstructed< ::std::string>" - " $default_variable_name$;\n"); + " $default_variable_name$;\n" + "private:\n"); } } @@ -246,9 +271,23 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\n" "inline ::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n"); + + if (HasFieldPresence(descriptor_->file())) { + printer->Print(variables_, + " if (!has_$name$()) {\n" + " return NULL;\n" + " }\n" " $clear_hasbit$\n" - " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" + " return $name$_.ReleaseNonDefault(" + "$default_variable$, GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + " $clear_hasbit$\n" + " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"); + } + + printer->Print(variables_, "}\n" "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" @@ -322,9 +361,22 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return $name$_.MutableNoArena($default_variable$);\n" "}\n" "inline ::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n"); + + if (HasFieldPresence(descriptor_->file())) { + printer->Print(variables_, + " if (!has_$name$()) {\n" + " return NULL;\n" + " }\n" + " $clear_hasbit$\n" + " return $name$_.ReleaseNonDefaultNoArena($default_variable$);\n"); + } else { + printer->Print(variables_, " $clear_hasbit$\n" - " return $name$_.ReleaseNoArena($default_variable$);\n" + " return $name$_.ReleaseNoArena($default_variable$);\n"); + } + + printer->Print(variables_, "}\n" "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" @@ -343,7 +395,7 @@ GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { // Initialized in GenerateDefaultInstanceAllocator. printer->Print(variables_, - "::google::protobuf::internal::ExplicitlyConstructed< ::std::string> " + "::google::protobuf::internal::ExplicitlyConstructed<::std::string> " "$classname$::$default_variable_name$;\n"); } } @@ -383,18 +435,34 @@ GenerateMessageClearingCode(io::Printer* printer) const { // If we have field presence, then the Clear() method of the protocol buffer // will have checked that this field is set. If so, we can avoid redundant // checks against default_variable. - const bool must_be_present = HasFieldPresence(descriptor_->file()); - - if (must_be_present) { + const bool must_be_present = + HasFieldPresence(descriptor_->file()); + + if (inlined_ && must_be_present) { + // Calling mutable_$name$() gives us a string reference and sets the has bit + // for $name$ (in proto2). We may get here when the string field is inlined + // but the string's contents have not been changed by the user, so we cannot + // make an assertion about the contents of the string and could never make + // an assertion about the string instance. + // + // For non-inlined strings, we distinguish from non-default by comparing + // instances, rather than contents. printer->Print(variables_, "GOOGLE_DCHECK(!$name$_.IsDefault($default_variable$));\n"); } if (SupportsArenas(descriptor_)) { if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + if (must_be_present) { + printer->Print(variables_, + "$name$_.ClearNonDefaultToEmpty();\n"); + } else { + printer->Print(variables_, + "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + } } else { + // Clear to a non-empty default is more involved, as we try to use the + // Arena if one is present and may need to reallocate the string. printer->Print(variables_, "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); } @@ -402,11 +470,11 @@ GenerateMessageClearingCode(io::Printer* printer) const { // When Arenas are disabled and field presence has been checked, we can // safely treat the ArenaStringPtr as a string*. if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "(*$name$_.UnsafeRawStringPointer())->clear();\n"); + printer->Print(variables_, "$name$_.ClearNonDefaultToEmptyNoArena();\n"); } else { - printer->Print(variables_, - "(*$name$_.UnsafeRawStringPointer())->assign(*$default_variable$);\n"); + printer->Print( + variables_, + "$name$_.UnsafeMutablePointer()->assign(*$default_variable$);\n"); } } else { if (descriptor_->default_value_string().empty()) { @@ -433,13 +501,29 @@ GenerateMergingCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + if (inlined_) { + printer->Print( + variables_, + "$name$_.Swap(&other->$name$_);\n"); + } else { + printer->Print( + variables_, + "$name$_.Swap(&other->$name$_, $default_variable$,\n" + " GetArenaNoVirtual());\n"); + } } void StringFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { + // TODO(ckennelly): Construct non-empty strings as part of the initializer + // list. + if (inlined_ && descriptor_->default_value_string().empty()) { + // Automatic initialization will construct the string. + return; + } + printer->Print(variables_, - "$name$_.UnsafeSetDefault($default_variable$);\n"); + "$name$_.UnsafeSetDefault($default_variable$);\n"); } void StringFieldGenerator:: @@ -472,8 +556,23 @@ GenerateCopyConstructorCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { + if (inlined_) { + // The destructor is automatically invoked. + return; + } + + printer->Print(variables_, "$name$_.DestroyNoArena($default_variable$);\n"); +} + +bool StringFieldGenerator::GenerateArenaDestructorCode( + io::Printer* printer) const { + if (!inlined_) { + return false; + } + printer->Print(variables_, - "$name$_.DestroyNoArena($default_variable$);\n"); + "_this->$name$_.DestroyNoArena($default_variable$);\n"); + return true; } void StringFieldGenerator:: @@ -504,6 +603,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { } } +bool StringFieldGenerator:: +MergeFromCodedStreamNeedsArena() const { + return false; +} + void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { @@ -539,13 +643,17 @@ GenerateByteSize(io::Printer* printer) const { " this->$name$());\n"); } +uint32 StringFieldGenerator::CalculateFieldTag() const { + return inlined_ ? 1 : 0; +} + // =================================================================== -StringOneofFieldGenerator:: -StringOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : StringFieldGenerator(descriptor, options), - dependent_field_(options.proto_h) { +StringOneofFieldGenerator::StringOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : StringFieldGenerator(descriptor, options) { + inlined_ = false; + SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -559,7 +667,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "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();\n" + " return $field_member$.Get();\n" " }\n" " return *$default_variable$;\n" "}\n" @@ -567,9 +675,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set$lite$($default_variable$, value,\n" + " $field_member$.Set$lite$($default_variable$, value,\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" @@ -579,9 +687,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set$lite$(\n" + " $field_member$.Set$lite$(\n" " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" "}\n" @@ -591,9 +699,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set$lite$($default_variable$,\n" + " $field_member$.Set$lite$($default_variable$,\n" " $string_piece$(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" @@ -603,9 +711,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set$lite$(\n" + " $field_member$.Set$lite$(\n" " $default_variable$, $string_piece$(\n" " reinterpret_cast<const char*>(value), size),\n" " GetArenaNoVirtual());\n" @@ -615,9 +723,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " return $oneof_prefix$$name$_.Mutable($default_variable$,\n" + " return $field_member$.Mutable($default_variable$,\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" @@ -625,7 +733,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.Release($default_variable$,\n" + " return $field_member$.Release($default_variable$,\n" " GetArenaNoVirtual());\n" " } else {\n" " return NULL;\n" @@ -633,12 +741,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" " clear_$oneof_name$();\n" " if ($name$ != NULL) {\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n" + " $field_member$.SetAllocated($default_variable$, $name$,\n" " GetArenaNoVirtual());\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" @@ -649,7 +757,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n" + " return $field_member$.UnsafeArenaRelease(\n" " $default_variable$, GetArenaNoVirtual());\n" " } else {\n" " return NULL;\n" @@ -659,12 +767,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "::std::string* $name$) {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" " clear_$oneof_name$();\n" " if ($name$) {\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " + " $field_member$.UnsafeArenaSetAllocated($default_variable$, " "$name$, GetArenaNoVirtual());\n" " }\n" " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" @@ -677,7 +785,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "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();\n" + " return $field_member$.GetNoArena();\n" " }\n" " return *$default_variable$;\n" "}\n" @@ -686,9 +794,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n" + " $field_member$.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" @@ -697,10 +805,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.SetNoArena(\n" - " $default_variable$, ::std::move(value));\n" + " $field_member$.SetNoArena($default_variable$, ::std::move(value));\n" " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" "}\n" "#endif\n" @@ -709,9 +816,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n" + " $field_member$.SetNoArena($default_variable$,\n" " $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" @@ -721,10 +828,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.SetNoArena($default_variable$, " - "$string_piece$(\n" + " $field_member$.SetNoArena($default_variable$, $string_piece$(\n" " reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" @@ -732,29 +838,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" + " return $field_member$.MutableNoArena($default_variable$);\n" "}\n" "inline ::std::string* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" + " return $field_member$.ReleaseNoArena($default_variable$);\n" " } else {\n" " return NULL;\n" " }\n" "}\n" "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" " }\n" " clear_$oneof_name$();\n" " if ($name$ != NULL) {\n" " set_has_$name$();\n" - " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n" - " $name$);\n" + " $field_member$.SetAllocatedNoArena($default_variable$, $name$);\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -765,12 +870,11 @@ void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "$oneof_prefix$$name$_.Destroy($default_variable$,\n" + "$field_member$.Destroy($default_variable$,\n" " GetArenaNoVirtual());\n"); } else { printer->Print(variables_, - "$oneof_prefix$$name$_." - "DestroyNoArena($default_variable$);\n"); + "$field_member$.DestroyNoArena($default_variable$);\n"); } } @@ -796,7 +900,7 @@ void StringOneofFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { printer->Print(variables_, "if (has_$name$()) {\n" - " $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n" + " $field_member$.DestroyNoArena($default_variable$);\n" "}\n"); } @@ -912,11 +1016,21 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { + if (options_.safe_boundary_check) { + printer->Print(variables_, + "inline const ::std::string& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.InternalCheckedGet(\n" + " index, ::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n"); + } else { + printer->Print(variables_, + "inline const ::std::string& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.Get(index);\n" + "}\n"); + } 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" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable(index);\n" @@ -991,7 +1105,8 @@ GenerateMergingCode(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n"); + printer->Print(variables_, + "$name$_.InternalSwap(CastToBase(&other->$name$_));\n"); } void RepeatedStringFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index f56f0721..6cbf722f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -63,16 +63,22 @@ class StringFieldGenerator : public FieldGenerator { void GenerateConstructorCode(io::Printer* printer) const; void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; + bool GenerateArenaDestructorCode(io::Printer* printer) const; void GenerateDefaultInstanceAllocator(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; + uint32 CalculateFieldTag() const; + bool IsInlined() const { return inlined_; } + + bool MergeFromCodedStreamNeedsArena() const; protected: const FieldDescriptor* descriptor_; std::map<string, string> variables_; const bool lite_; + bool inlined_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); @@ -97,7 +103,6 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateMergeFromCodedStream(io::Printer* printer) const; private: - const bool dependent_field_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 61cc32a4..22b759a9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -46,40 +46,26 @@ #include <google/protobuf/compiler/cpp/cpp_unittest.h> -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif -#include <vector> - #include <google/protobuf/unittest.pb.h> -#include <google/protobuf/unittest_no_arena.pb.h> #include <google/protobuf/unittest_optimize_for.pb.h> #include <google/protobuf/unittest_embed_optimize_for.pb.h> -#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) -// We exclude this large proto from cmake build because it's too large for -// visual studio to compile (report internal errors). -#include <google/protobuf/unittest_enormous_descriptor.pb.h> -#endif -#include <google/protobuf/unittest_no_generic_services.pb.h> + #include <google/protobuf/test_util.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h> -#include <google/protobuf/compiler/importer.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/arena.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/stubs/callback.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/testing/googletest.h> -#include <gtest/gtest.h> -#include <google/protobuf/stubs/stl_util.h> +#define MESSAGE_TEST_NAME MessageTest +#define GENERATED_DESCRIPTOR_TEST_NAME GeneratedDescriptorTest +#define GENERATED_MESSAGE_TEST_NAME GeneratedMessageTest +#define GENERATED_ENUM_TEST_NAME GeneratedEnumTest +#define GENERATED_SERVICE_TEST_NAME GeneratedServiceTest +#define HELPERS_TEST_NAME HelpersTest +#define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest + +#define UNITTEST_PROTO_PATH "google/protobuf/unittest.proto" +#define UNITTEST ::protobuf_unittest +#define UNITTEST_IMPORT ::protobuf_unittest_import + +// Must include after the above macros. +#include <google/protobuf/compiler/cpp/cpp_unittest.inc> namespace google { namespace protobuf { @@ -91,848 +77,14 @@ namespace cpp_unittest { namespace protobuf_unittest = ::protobuf_unittest; - -class MockErrorCollector : public MultiFileErrorCollector { - public: - MockErrorCollector() {} - ~MockErrorCollector() {} - - string text_; - - // implements ErrorCollector --------------------------------------- - void AddError(const string& filename, int line, int column, - const string& message) { - strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", - filename, line, column, message); - } -}; - -#ifndef PROTOBUF_TEST_NO_DESCRIPTORS - -// Test that generated code has proper descriptors: -// Parse a descriptor directly (using google::protobuf::compiler::Importer) and -// compare it to the one that was produced by generated code. -TEST(GeneratedDescriptorTest, IdenticalDescriptors) { - const FileDescriptor* generated_descriptor = - unittest::TestAllTypes::descriptor()->file(); - - // Set up the Importer. - MockErrorCollector error_collector; - DiskSourceTree source_tree; - source_tree.MapPath("", TestSourceDir()); - Importer importer(&source_tree, &error_collector); - - // Import (parse) unittest.proto. - const FileDescriptor* parsed_descriptor = - importer.Import("google/protobuf/unittest.proto"); - EXPECT_EQ("", error_collector.text_); - ASSERT_TRUE(parsed_descriptor != NULL); - - // Test that descriptors are generated correctly by converting them to - // FileDescriptorProtos and comparing. - FileDescriptorProto generated_descriptor_proto, parsed_descriptor_proto; - generated_descriptor->CopyTo(&generated_descriptor_proto); - parsed_descriptor->CopyTo(&parsed_descriptor_proto); - - EXPECT_EQ(parsed_descriptor_proto.DebugString(), - generated_descriptor_proto.DebugString()); -} - -#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) -// 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 - -#endif // !PROTOBUF_TEST_NO_DESCRIPTORS - -// =================================================================== - -TEST(GeneratedMessageTest, Defaults) { - // Check that all default values are set correctly in the initial message. - unittest::TestAllTypes message; - - TestUtil::ExpectClear(message); - - // Messages should return pointers to default instances until first use. - // (This is not checked by ExpectClear() since it is not actually true after - // the fields have been set and then cleared.) - EXPECT_EQ(&unittest::TestAllTypes::OptionalGroup::default_instance(), - &message.optionalgroup()); - EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), - &message.optional_nested_message()); - EXPECT_EQ(&unittest::ForeignMessage::default_instance(), - &message.optional_foreign_message()); - EXPECT_EQ(&unittest_import::ImportMessage::default_instance(), - &message.optional_import_message()); -} - -#ifndef PROTOBUF_USE_DLLS -TEST(GeneratedMessageTest, Int32StringConversion) { - EXPECT_EQ("971", Int32ToString(971)); - EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min)); - EXPECT_EQ("2147483647", Int32ToString(kint32max)); -} - -TEST(GeneratedMessageTest, Int64StringConversion) { - EXPECT_EQ("GOOGLE_LONGLONG(971)", Int64ToString(971)); - EXPECT_EQ("GOOGLE_LONGLONG(-2147483648)", Int64ToString(kint32min)); - EXPECT_EQ("GOOGLE_LONGLONG(~0x7fffffffffffffff)", Int64ToString(kint64min)); - EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max)); -} -#endif // !PROTOBUF_USE_DLLS - -TEST(GeneratedMessageTest, FloatingPointDefaults) { - const unittest::TestExtremeDefaultValues& extreme_default = - unittest::TestExtremeDefaultValues::default_instance(); - - EXPECT_EQ(0.0f, extreme_default.zero_float()); - EXPECT_EQ(1.0f, extreme_default.one_float()); - EXPECT_EQ(1.5f, extreme_default.small_float()); - EXPECT_EQ(-1.0f, extreme_default.negative_one_float()); - EXPECT_EQ(-1.5f, extreme_default.negative_float()); - EXPECT_EQ(2.0e8f, extreme_default.large_float()); - EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); - EXPECT_EQ(std::numeric_limits<double>::infinity(), - extreme_default.inf_double()); - EXPECT_EQ(-std::numeric_limits<double>::infinity(), - extreme_default.neg_inf_double()); - EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); - EXPECT_EQ(std::numeric_limits<float>::infinity(), - extreme_default.inf_float()); - EXPECT_EQ(-std::numeric_limits<float>::infinity(), - extreme_default.neg_inf_float()); - EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); -} - -TEST(GeneratedMessageTest, Trigraph) { - const unittest::TestExtremeDefaultValues& extreme_default = - unittest::TestExtremeDefaultValues::default_instance(); - - EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph()); -} - -TEST(GeneratedMessageTest, ExtremeSmallIntegerDefault) { - const unittest::TestExtremeDefaultValues& extreme_default = - unittest::TestExtremeDefaultValues::default_instance(); - EXPECT_EQ(~0x7fffffff, kint32min); - EXPECT_EQ(GOOGLE_LONGLONG(~0x7fffffffffffffff), kint64min); - EXPECT_EQ(kint32min, extreme_default.really_small_int32()); - EXPECT_EQ(kint64min, extreme_default.really_small_int64()); -} - -TEST(GeneratedMessageTest, Accessors) { - // Set every field to a unique value then go back and check all those - // values. - unittest::TestAllTypes message; - - TestUtil::SetAllFields(&message); - TestUtil::ExpectAllFieldsSet(message); - - TestUtil::ModifyRepeatedFields(&message); - TestUtil::ExpectRepeatedFieldsModified(message); -} - -TEST(GeneratedMessageTest, MutableStringDefault) { - // mutable_foo() for a string should return a string initialized to its - // default value. - unittest::TestAllTypes message; - - EXPECT_EQ("hello", *message.mutable_default_string()); - - // Note that the first time we call mutable_foo(), we get a newly-allocated - // string, but if we clear it and call it again, we get the same object again. - // We should verify that it has its default value in both cases. - message.set_default_string("blah"); - message.Clear(); - - EXPECT_EQ("hello", *message.mutable_default_string()); -} - -TEST(GeneratedMessageTest, StringDefaults) { - unittest::TestExtremeDefaultValues message; - // Check if '\000' can be used in default string value. - EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero()); - EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero()); -} - -TEST(GeneratedMessageTest, ReleaseString) { - // Check that release_foo() starts out NULL, and gives us a value - // that we can delete after it's been set. - unittest::TestAllTypes message; - - EXPECT_EQ(NULL, message.release_default_string()); - EXPECT_FALSE(message.has_default_string()); - EXPECT_EQ("hello", message.default_string()); - - message.set_default_string("blah"); - EXPECT_TRUE(message.has_default_string()); - google::protobuf::scoped_ptr<string> str(message.release_default_string()); - EXPECT_FALSE(message.has_default_string()); - ASSERT_TRUE(str != NULL); - EXPECT_EQ("blah", *str); - - EXPECT_EQ(NULL, message.release_default_string()); - EXPECT_FALSE(message.has_default_string()); - EXPECT_EQ("hello", message.default_string()); -} - -TEST(GeneratedMessageTest, ReleaseMessage) { - // Check that release_foo() starts out NULL, and gives us a value - // that we can delete after it's been set. - unittest::TestAllTypes message; - - EXPECT_EQ(NULL, message.release_optional_nested_message()); - EXPECT_FALSE(message.has_optional_nested_message()); - - message.mutable_optional_nested_message()->set_bb(1); - google::protobuf::scoped_ptr<unittest::TestAllTypes::NestedMessage> nest( - message.release_optional_nested_message()); - EXPECT_FALSE(message.has_optional_nested_message()); - ASSERT_TRUE(nest != NULL); - EXPECT_EQ(1, nest->bb()); - - EXPECT_EQ(NULL, message.release_optional_nested_message()); - EXPECT_FALSE(message.has_optional_nested_message()); -} - -TEST(GeneratedMessageTest, SetAllocatedString) { - // Check that set_allocated_foo() works for strings. - unittest::TestAllTypes message; - - EXPECT_FALSE(message.has_optional_string()); - const string kHello("hello"); - message.set_optional_string(kHello); - EXPECT_TRUE(message.has_optional_string()); - - message.set_allocated_optional_string(NULL); - EXPECT_FALSE(message.has_optional_string()); - EXPECT_EQ("", message.optional_string()); - - message.set_allocated_optional_string(new string(kHello)); - EXPECT_TRUE(message.has_optional_string()); - EXPECT_EQ(kHello, message.optional_string()); -} - -TEST(GeneratedMessageTest, SetAllocatedMessage) { - // Check that set_allocated_foo() can be called in all cases. - unittest::TestAllTypes message; - - EXPECT_FALSE(message.has_optional_nested_message()); - - message.mutable_optional_nested_message()->set_bb(1); - EXPECT_TRUE(message.has_optional_nested_message()); - - message.set_allocated_optional_nested_message(NULL); - EXPECT_FALSE(message.has_optional_nested_message()); - EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), - &message.optional_nested_message()); - - message.mutable_optional_nested_message()->set_bb(1); - unittest::TestAllTypes::NestedMessage* nest = - message.release_optional_nested_message(); - ASSERT_TRUE(nest != NULL); - EXPECT_FALSE(message.has_optional_nested_message()); - - message.set_allocated_optional_nested_message(nest); - EXPECT_TRUE(message.has_optional_nested_message()); - EXPECT_EQ(1, message.optional_nested_message().bb()); -} - -TEST(GeneratedMessageTest, Clear) { - // Set every field to a unique value, clear the message, then check that - // it is cleared. - unittest::TestAllTypes message; - - TestUtil::SetAllFields(&message); - message.Clear(); - TestUtil::ExpectClear(message); - - // Unlike with the defaults test, we do NOT expect that requesting embedded - // messages will return a pointer to the default instance. Instead, they - // should return the objects that were created when mutable_blah() was - // called. - EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(), - &message.optionalgroup()); - EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(), - &message.optional_nested_message()); - EXPECT_NE(&unittest::ForeignMessage::default_instance(), - &message.optional_foreign_message()); - EXPECT_NE(&unittest_import::ImportMessage::default_instance(), - &message.optional_import_message()); -} - -TEST(GeneratedMessageTest, EmbeddedNullsInBytesCharStar) { - unittest::TestAllTypes message; - - const char* value = "\0lalala\0\0"; - message.set_optional_bytes(value, 9); - ASSERT_EQ(9, message.optional_bytes().size()); - EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9)); - - message.add_repeated_bytes(value, 9); - ASSERT_EQ(9, message.repeated_bytes(0).size()); - EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9)); -} - -TEST(GeneratedMessageTest, ClearOneField) { - // Set every field to a unique value, then clear one value and insure that - // only that one value is cleared. - unittest::TestAllTypes message; - - TestUtil::SetAllFields(&message); - int64 original_value = message.optional_int64(); - - // Clear the field and make sure it shows up as cleared. - message.clear_optional_int64(); - EXPECT_FALSE(message.has_optional_int64()); - EXPECT_EQ(0, message.optional_int64()); - - // Other adjacent fields should not be cleared. - EXPECT_TRUE(message.has_optional_int32()); - EXPECT_TRUE(message.has_optional_uint32()); - - // Make sure if we set it again, then all fields are set. - message.set_optional_int64(original_value); - TestUtil::ExpectAllFieldsSet(message); -} - -TEST(GeneratedMessageTest, StringCharStarLength) { - // Verify that we can use a char*,length to set one of the string fields. - unittest::TestAllTypes message; - message.set_optional_string("abcdef", 3); - EXPECT_EQ("abc", message.optional_string()); - - // Verify that we can use a char*,length to add to a repeated string field. - message.add_repeated_string("abcdef", 3); - EXPECT_EQ(1, message.repeated_string_size()); - EXPECT_EQ("abc", message.repeated_string(0)); - - // Verify that we can use a char*,length to set a repeated string field. - message.set_repeated_string(0, "wxyz", 2); - EXPECT_EQ("wx", message.repeated_string(0)); -} - -#if LANG_CXX11 -TEST(GeneratedMessageTest, StringMove) { - // Verify that we trigger the move behavior on a scalar setter. - protobuf_unittest_no_arena::TestAllTypes message; - { - string tmp(32, 'a'); - - const char* old_data = tmp.data(); - message.set_optional_string(std::move(tmp)); - const char* new_data = message.optional_string().data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'a'), message.optional_string()); - - string tmp2(32, 'b'); - old_data = tmp2.data(); - message.set_optional_string(std::move(tmp2)); - new_data = message.optional_string().data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'b'), message.optional_string()); - } - - // Verify that we trigger the move behavior on a oneof setter. - { - string tmp(32, 'a'); - - const char* old_data = tmp.data(); - message.set_oneof_string(std::move(tmp)); - const char* new_data = message.oneof_string().data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'a'), message.oneof_string()); - - string tmp2(32, 'b'); - old_data = tmp2.data(); - message.set_oneof_string(std::move(tmp2)); - new_data = message.oneof_string().data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'b'), message.oneof_string()); - } - - // Verify that we trigger the move behavior on a repeated setter. - { - string tmp(32, 'a'); - - const char* old_data = tmp.data(); - message.add_repeated_string(std::move(tmp)); - const char* new_data = message.repeated_string(0).data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'a'), message.repeated_string(0)); - - string tmp2(32, 'b'); - old_data = tmp2.data(); - message.set_repeated_string(0, std::move(tmp2)); - new_data = message.repeated_string(0).data(); - - EXPECT_EQ(old_data, new_data); - EXPECT_EQ(string(32, 'b'), message.repeated_string(0)); - } -} -#endif - - -TEST(GeneratedMessageTest, CopyFrom) { - unittest::TestAllTypes message1, message2; - - TestUtil::SetAllFields(&message1); - message2.CopyFrom(message1); - TestUtil::ExpectAllFieldsSet(message2); - - // Copying from self should be a no-op. - message2.CopyFrom(message2); - TestUtil::ExpectAllFieldsSet(message2); -} - - -TEST(GeneratedMessageTest, SwapWithEmpty) { - unittest::TestAllTypes message1, message2; - TestUtil::SetAllFields(&message1); - - TestUtil::ExpectAllFieldsSet(message1); - TestUtil::ExpectClear(message2); - message1.Swap(&message2); - TestUtil::ExpectAllFieldsSet(message2); - TestUtil::ExpectClear(message1); -} - -TEST(GeneratedMessageTest, SwapWithSelf) { - unittest::TestAllTypes message; - TestUtil::SetAllFields(&message); - TestUtil::ExpectAllFieldsSet(message); - message.Swap(&message); - TestUtil::ExpectAllFieldsSet(message); -} - -TEST(GeneratedMessageTest, SwapWithOther) { - unittest::TestAllTypes message1, message2; - - message1.set_optional_int32(123); - message1.set_optional_string("abc"); - message1.mutable_optional_nested_message()->set_bb(1); - message1.set_optional_nested_enum(unittest::TestAllTypes::FOO); - message1.add_repeated_int32(1); - message1.add_repeated_int32(2); - message1.add_repeated_string("a"); - message1.add_repeated_string("b"); - message1.add_repeated_nested_message()->set_bb(7); - message1.add_repeated_nested_message()->set_bb(8); - message1.add_repeated_nested_enum(unittest::TestAllTypes::FOO); - message1.add_repeated_nested_enum(unittest::TestAllTypes::BAR); - - message2.set_optional_int32(456); - message2.set_optional_string("def"); - message2.mutable_optional_nested_message()->set_bb(2); - message2.set_optional_nested_enum(unittest::TestAllTypes::BAR); - message2.add_repeated_int32(3); - message2.add_repeated_string("c"); - message2.add_repeated_nested_message()->set_bb(9); - message2.add_repeated_nested_enum(unittest::TestAllTypes::BAZ); - - message1.Swap(&message2); - - EXPECT_EQ(456, message1.optional_int32()); - EXPECT_EQ("def", message1.optional_string()); - EXPECT_EQ(2, message1.optional_nested_message().bb()); - EXPECT_EQ(unittest::TestAllTypes::BAR, message1.optional_nested_enum()); - ASSERT_EQ(1, message1.repeated_int32_size()); - EXPECT_EQ(3, message1.repeated_int32(0)); - ASSERT_EQ(1, message1.repeated_string_size()); - EXPECT_EQ("c", message1.repeated_string(0)); - ASSERT_EQ(1, message1.repeated_nested_message_size()); - EXPECT_EQ(9, message1.repeated_nested_message(0).bb()); - ASSERT_EQ(1, message1.repeated_nested_enum_size()); - EXPECT_EQ(unittest::TestAllTypes::BAZ, message1.repeated_nested_enum(0)); - - EXPECT_EQ(123, message2.optional_int32()); - EXPECT_EQ("abc", message2.optional_string()); - EXPECT_EQ(1, message2.optional_nested_message().bb()); - EXPECT_EQ(unittest::TestAllTypes::FOO, message2.optional_nested_enum()); - ASSERT_EQ(2, message2.repeated_int32_size()); - EXPECT_EQ(1, message2.repeated_int32(0)); - EXPECT_EQ(2, message2.repeated_int32(1)); - ASSERT_EQ(2, message2.repeated_string_size()); - EXPECT_EQ("a", message2.repeated_string(0)); - EXPECT_EQ("b", message2.repeated_string(1)); - ASSERT_EQ(2, message2.repeated_nested_message_size()); - EXPECT_EQ(7, message2.repeated_nested_message(0).bb()); - EXPECT_EQ(8, message2.repeated_nested_message(1).bb()); - ASSERT_EQ(2, message2.repeated_nested_enum_size()); - EXPECT_EQ(unittest::TestAllTypes::FOO, message2.repeated_nested_enum(0)); - EXPECT_EQ(unittest::TestAllTypes::BAR, message2.repeated_nested_enum(1)); -} - -TEST(GeneratedMessageTest, ADLSwap) { - unittest::TestAllTypes message1, message2; - TestUtil::SetAllFields(&message1); - - // Note the address of one of the repeated fields, to verify it was swapped - // rather than copied. - const int32* addr = &message1.repeated_int32().Get(0); - - using std::swap; - swap(message1, message2); - - TestUtil::ExpectAllFieldsSet(message2); - TestUtil::ExpectClear(message1); - - EXPECT_EQ(addr, &message2.repeated_int32().Get(0)); -} - -TEST(GeneratedMessageTest, CopyConstructor) { - // All set. - { - unittest::TestAllTypes message1; - TestUtil::SetAllFields(&message1); - - unittest::TestAllTypes message2(message1); - TestUtil::ExpectAllFieldsSet(message2); - } - - // None set. - { - unittest::TestAllTypes message1; - unittest::TestAllTypes message2(message1); - - EXPECT_FALSE(message1.has_optional_string()); - EXPECT_FALSE(message2.has_optional_string()); - EXPECT_EQ(&message1.optional_string(), - &message2.optional_string()); - - EXPECT_FALSE(message1.has_optional_bytes()); - EXPECT_FALSE(message2.has_optional_bytes()); - EXPECT_EQ(&message1.optional_bytes(), - &message2.optional_bytes()); - - EXPECT_FALSE(message1.has_optional_nested_message()); - EXPECT_FALSE(message2.has_optional_nested_message()); - EXPECT_EQ(&message1.optional_nested_message(), - &message2.optional_nested_message()); - - EXPECT_FALSE(message1.has_optional_foreign_message()); - EXPECT_FALSE(message2.has_optional_foreign_message()); - EXPECT_EQ(&message1.optional_foreign_message(), - &message2.optional_foreign_message()); - - EXPECT_FALSE(message1.has_optional_import_message()); - EXPECT_FALSE(message2.has_optional_import_message()); - EXPECT_EQ(&message1.optional_import_message(), - &message2.optional_import_message()); - - EXPECT_FALSE(message1.has_optional_public_import_message()); - EXPECT_FALSE(message2.has_optional_public_import_message()); - EXPECT_EQ(&message1.optional_public_import_message(), - &message2.optional_public_import_message()); - - EXPECT_FALSE(message1.has_optional_lazy_message()); - EXPECT_FALSE(message2.has_optional_lazy_message()); - EXPECT_EQ(&message1.optional_lazy_message(), - &message2.optional_lazy_message()); - } -} - -TEST(GeneratedMessageTest, CopyConstructorWithArenas) { - Arena arena; - unittest::TestAllTypes* message1 = - Arena::CreateMessage<unittest::TestAllTypes>(&arena); - TestUtil::SetAllFields(message1); - - unittest::TestAllTypes message2_stack(*message1); - TestUtil::ExpectAllFieldsSet(message2_stack); - - google::protobuf::scoped_ptr<unittest::TestAllTypes> message2_heap( - new unittest::TestAllTypes(*message1)); - TestUtil::ExpectAllFieldsSet(*message2_heap); - - arena.Reset(); - - // Verify that the copies are still intact. - TestUtil::ExpectAllFieldsSet(message2_stack); - TestUtil::ExpectAllFieldsSet(*message2_heap); -} - -TEST(GeneratedMessageTest, CopyAssignmentOperator) { - unittest::TestAllTypes message1; - TestUtil::SetAllFields(&message1); - - unittest::TestAllTypes message2; - message2 = message1; - TestUtil::ExpectAllFieldsSet(message2); - - // Make sure that self-assignment does something sane. - message2.operator=(message2); - TestUtil::ExpectAllFieldsSet(message2); -} - -#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \ - !defined(GOOGLE_PROTOBUF_NO_RTTI) -TEST(GeneratedMessageTest, UpcastCopyFrom) { - // Test the CopyFrom method that takes in the generic const Message& - // parameter. - unittest::TestAllTypes message1, message2; - - TestUtil::SetAllFields(&message1); - - const Message* source = implicit_cast<const Message*>(&message1); - message2.CopyFrom(*source); - - TestUtil::ExpectAllFieldsSet(message2); -} -#endif - -#ifndef PROTOBUF_TEST_NO_DESCRIPTORS - -TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { - // Test copying from a DynamicMessage, which must fall back to using - // reflection. - unittest::TestAllTypes message2; - - // Construct a new version of the dynamic message via the factory. - DynamicMessageFactory factory; - google::protobuf::scoped_ptr<Message> message1; - message1.reset(factory.GetPrototype( - unittest::TestAllTypes::descriptor())->New()); - - TestUtil::ReflectionTester reflection_tester( - unittest::TestAllTypes::descriptor()); - reflection_tester.SetAllFieldsViaReflection(message1.get()); - - message2.CopyFrom(*message1); - - TestUtil::ExpectAllFieldsSet(message2); -} - -#endif // !PROTOBUF_TEST_NO_DESCRIPTORS - -TEST(GeneratedMessageTest, NonEmptyMergeFrom) { - // Test merging with a non-empty message. Code is a modified form - // of that found in google/protobuf/reflection_ops_unittest.cc. - unittest::TestAllTypes message1, message2; - - TestUtil::SetAllFields(&message1); - - // This field will test merging into an empty spot. - message2.set_optional_int32(message1.optional_int32()); - message1.clear_optional_int32(); - - // This tests overwriting. - message2.set_optional_string(message1.optional_string()); - message1.set_optional_string("something else"); - - // This tests concatenating. - message2.add_repeated_int32(message1.repeated_int32(1)); - int32 i = message1.repeated_int32(0); - message1.clear_repeated_int32(); - message1.add_repeated_int32(i); - - message1.MergeFrom(message2); - - TestUtil::ExpectAllFieldsSet(message1); -} - - -// Test the generated SerializeWithCachedSizesToArray(), -TEST(GeneratedMessageTest, SerializationToArray) { - unittest::TestAllTypes message1, message2; - string data; - TestUtil::SetAllFields(&message1); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - TestUtil::ExpectAllFieldsSet(message2); - -} - -TEST(GeneratedMessageTest, PackedFieldsSerializationToArray) { - unittest::TestPackedTypes packed_message1, packed_message2; - string packed_data; - TestUtil::SetPackedFields(&packed_message1); - int packed_size = packed_message1.ByteSize(); - packed_data.resize(packed_size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&packed_data)); - uint8* end = packed_message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(packed_size, end - start); - EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); - TestUtil::ExpectPackedFieldsSet(packed_message2); -} - -// Test the generated SerializeWithCachedSizes() by forcing the buffer to write -// one byte at a time. -TEST(GeneratedMessageTest, SerializationToStream) { - unittest::TestAllTypes message1, message2; - TestUtil::SetAllFields(&message1); - int size = message1.ByteSize(); - string data; - data.resize(size); - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - EXPECT_TRUE(message2.ParseFromString(data)); - TestUtil::ExpectAllFieldsSet(message2); - -} - -TEST(GeneratedMessageTest, PackedFieldsSerializationToStream) { - unittest::TestPackedTypes message1, message2; - TestUtil::SetPackedFields(&message1); - int size = message1.ByteSize(); - string data; - data.resize(size); - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - EXPECT_TRUE(message2.ParseFromString(data)); - TestUtil::ExpectPackedFieldsSet(message2); -} - - -TEST(GeneratedMessageTest, Required) { - // Test that IsInitialized() returns false if required fields are missing. - unittest::TestRequired message; - - EXPECT_FALSE(message.IsInitialized()); - message.set_a(1); - EXPECT_FALSE(message.IsInitialized()); - message.set_b(2); - EXPECT_FALSE(message.IsInitialized()); - message.set_c(3); - EXPECT_TRUE(message.IsInitialized()); -} - -TEST(GeneratedMessageTest, RequiredForeign) { - // Test that IsInitialized() returns false if required fields in nested - // messages are missing. - unittest::TestRequiredForeign message; - - EXPECT_TRUE(message.IsInitialized()); - - message.mutable_optional_message(); - EXPECT_FALSE(message.IsInitialized()); - - message.mutable_optional_message()->set_a(1); - message.mutable_optional_message()->set_b(2); - message.mutable_optional_message()->set_c(3); - EXPECT_TRUE(message.IsInitialized()); - - message.add_repeated_message(); - EXPECT_FALSE(message.IsInitialized()); - - message.mutable_repeated_message(0)->set_a(1); - message.mutable_repeated_message(0)->set_b(2); - message.mutable_repeated_message(0)->set_c(3); - EXPECT_TRUE(message.IsInitialized()); -} - -TEST(GeneratedMessageTest, ForeignNested) { - // Test that TestAllTypes::NestedMessage can be embedded directly into - // another message. - unittest::TestForeignNested message; - - // If this compiles and runs without crashing, it must work. We have - // nothing more to test. - unittest::TestAllTypes::NestedMessage* nested = - message.mutable_foreign_nested(); - nested->set_bb(1); -} - -TEST(GeneratedMessageTest, ReallyLargeTagNumber) { - // Test that really large tag numbers don't break anything. - unittest::TestReallyLargeTagNumber message1, message2; - string data; - - // For the most part, if this compiles and runs then we're probably good. - // (The most likely cause for failure would be if something were attempting - // to allocate a lookup table of some sort using tag numbers as the index.) - // We'll try serializing just for fun. - message1.set_a(1234); - message1.set_bb(5678); - message1.SerializeToString(&data); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(1234, message2.a()); - EXPECT_EQ(5678, message2.bb()); -} - -TEST(GeneratedMessageTest, MutualRecursion) { - // Test that mutually-recursive message types work. - unittest::TestMutualRecursionA message; - unittest::TestMutualRecursionA* nested = message.mutable_bb()->mutable_a(); - unittest::TestMutualRecursionA* nested2 = nested->mutable_bb()->mutable_a(); - - // Again, if the above compiles and runs, that's all we really have to - // test, but just for run we'll check that the system didn't somehow come - // up with a pointer loop... - EXPECT_NE(&message, nested); - EXPECT_NE(&message, nested2); - EXPECT_NE(nested, nested2); -} - -TEST(GeneratedMessageTest, CamelCaseFieldNames) { - // This test is mainly checking that the following compiles, which verifies - // that the field names were coerced to lower-case. - // - // Protocol buffers standard style is to use lowercase-with-underscores for - // field names. Some old proto1 .protos unfortunately used camel-case field - // names. In proto1, these names were forced to lower-case. So, we do the - // same thing in proto2. - - unittest::TestCamelCaseFieldNames message; - - message.set_primitivefield(2); - message.set_stringfield("foo"); - message.set_enumfield(unittest::FOREIGN_FOO); - message.mutable_messagefield()->set_c(6); - - message.add_repeatedprimitivefield(8); - message.add_repeatedstringfield("qux"); - message.add_repeatedenumfield(unittest::FOREIGN_BAR); - message.add_repeatedmessagefield()->set_c(15); - - EXPECT_EQ(2, message.primitivefield()); - EXPECT_EQ("foo", message.stringfield()); - EXPECT_EQ(unittest::FOREIGN_FOO, message.enumfield()); - EXPECT_EQ(6, message.messagefield().c()); - - EXPECT_EQ(8, message.repeatedprimitivefield(0)); - EXPECT_EQ("qux", message.repeatedstringfield(0)); - EXPECT_EQ(unittest::FOREIGN_BAR, message.repeatedenumfield(0)); - EXPECT_EQ(15, message.repeatedmessagefield(0).c()); -} - -TEST(GeneratedMessageTest, TestConflictingSymbolNames) { +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingSymbolNames) { // test_bad_identifiers.proto successfully compiled, then it works. The // following is just a token usage to insure that the code is, in fact, // being compiled and linked. protobuf_unittest::TestConflictingSymbolNames message; message.set_uint32(1); - EXPECT_EQ(3, message.ByteSize()); + EXPECT_EQ(3, message.ByteSizeLong()); message.set_friend_(5); EXPECT_EQ(5, message.friend_()); @@ -948,7 +100,7 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) { message.GetExtension(ExtensionMessage::repeated_int32_ext, 0)); } -TEST(GeneratedMessageTest, TestConflictingEnumNames) { +TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) { protobuf_unittest::TestConflictingEnumNames message; message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_); EXPECT_EQ(1, message.conflicting_enum()); @@ -963,1365 +115,7 @@ TEST(GeneratedMessageTest, TestConflictingEnumNames) { EXPECT_EQ(3, conflicting_enum); } -#ifndef PROTOBUF_TEST_NO_DESCRIPTORS - -TEST(GeneratedMessageTest, TestOptimizedForSize) { - // We rely on the tests in reflection_ops_unittest and wire_format_unittest - // to really test that reflection-based methods work. Here we are mostly - // just making sure that TestOptimizedForSize actually builds and seems to - // function. - - protobuf_unittest::TestOptimizedForSize message, message2; - message.set_i(1); - message.mutable_msg()->set_c(2); - message2.CopyFrom(message); - EXPECT_EQ(1, message2.i()); - EXPECT_EQ(2, message2.msg().c()); -} - -TEST(GeneratedMessageTest, TestEmbedOptimizedForSize) { - // Verifies that something optimized for speed can contain something optimized - // for size. - - protobuf_unittest::TestEmbedOptimizedForSize message, message2; - message.mutable_optional_message()->set_i(1); - message.add_repeated_message()->mutable_msg()->set_c(2); - string data; - message.SerializeToString(&data); - ASSERT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(1, message2.optional_message().i()); - EXPECT_EQ(2, message2.repeated_message(0).msg().c()); -} - -TEST(GeneratedMessageTest, TestSpaceUsed) { - unittest::TestAllTypes message1; - // sizeof provides a lower bound on SpaceUsed(). - EXPECT_LE(sizeof(unittest::TestAllTypes), message1.SpaceUsed()); - const int empty_message_size = message1.SpaceUsed(); - - // Setting primitive types shouldn't affect the space used. - message1.set_optional_int32(123); - message1.set_optional_int64(12345); - message1.set_optional_uint32(123); - message1.set_optional_uint64(12345); - EXPECT_EQ(empty_message_size, message1.SpaceUsed()); - - // On some STL implementations, setting the string to a small value should - // only increase SpaceUsed() by the size of a string object, though this is - // not true everywhere. - message1.set_optional_string("abc"); - EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed()); - - // Setting a string to a value larger than the string object itself should - // increase SpaceUsed(), because it cannot store the value internally. - message1.set_optional_string(string(sizeof(string) + 1, 'x')); - int min_expected_increase = message1.optional_string().capacity() + - sizeof(string); - EXPECT_LE(empty_message_size + min_expected_increase, - message1.SpaceUsed()); - - int previous_size = message1.SpaceUsed(); - // Adding an optional message should increase the size by the size of the - // nested message type. NestedMessage is simple enough (1 int field) that it - // is equal to sizeof(NestedMessage) - message1.mutable_optional_nested_message(); - ASSERT_EQ(sizeof(unittest::TestAllTypes::NestedMessage), - message1.optional_nested_message().SpaceUsed()); - EXPECT_EQ(previous_size + - sizeof(unittest::TestAllTypes::NestedMessage), - message1.SpaceUsed()); -} - -TEST(GeneratedMessageTest, TestOneofSpaceUsed) { - unittest::TestOneof2 message1; - EXPECT_LE(sizeof(unittest::TestOneof2), message1.SpaceUsed()); - - const int empty_message_size = message1.SpaceUsed(); - // Setting primitive types shouldn't affect the space used. - message1.set_foo_int(123); - message1.set_bar_int(12345); - EXPECT_EQ(empty_message_size, message1.SpaceUsed()); - - // Setting a string in oneof to a small value should only increase SpaceUsed() - // by the size of a string object. - message1.set_foo_string("abc"); - EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed()); - - // Setting a string in oneof to a value larger than the string object itself - // should increase SpaceUsed(), because it cannot store the value internally. - message1.set_foo_string(string(sizeof(string) + 1, 'x')); - int min_expected_increase = message1.foo_string().capacity() + - sizeof(string); - EXPECT_LE(empty_message_size + min_expected_increase, - message1.SpaceUsed()); - - // Setting a message in oneof should delete the other fields and increase the - // size by the size of the nested message type. NestedMessage is simple enough - // that it is equal to sizeof(NestedMessage) - message1.mutable_foo_message(); - ASSERT_EQ(sizeof(unittest::TestOneof2::NestedMessage), - message1.foo_message().SpaceUsed()); - EXPECT_EQ(empty_message_size + - sizeof(unittest::TestOneof2::NestedMessage), - message1.SpaceUsed()); -} - -#endif // !PROTOBUF_TEST_NO_DESCRIPTORS - - -TEST(GeneratedMessageTest, FieldConstantValues) { - unittest::TestRequired message; - EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1); - EXPECT_EQ(unittest::TestAllTypes::kOptionalInt32FieldNumber, 1); - EXPECT_EQ(unittest::TestAllTypes::kOptionalgroupFieldNumber, 16); - EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedMessageFieldNumber, 18); - EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedEnumFieldNumber, 21); - EXPECT_EQ(unittest::TestAllTypes::kRepeatedInt32FieldNumber, 31); - EXPECT_EQ(unittest::TestAllTypes::kRepeatedgroupFieldNumber, 46); - EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48); - EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51); -} - -TEST(GeneratedMessageTest, ExtensionConstantValues) { - EXPECT_EQ(unittest::TestRequired::kSingleFieldNumber, 1000); - EXPECT_EQ(unittest::TestRequired::kMultiFieldNumber, 1001); - EXPECT_EQ(unittest::kOptionalInt32ExtensionFieldNumber, 1); - EXPECT_EQ(unittest::kOptionalgroupExtensionFieldNumber, 16); - EXPECT_EQ(unittest::kOptionalNestedMessageExtensionFieldNumber, 18); - EXPECT_EQ(unittest::kOptionalNestedEnumExtensionFieldNumber, 21); - EXPECT_EQ(unittest::kRepeatedInt32ExtensionFieldNumber, 31); - EXPECT_EQ(unittest::kRepeatedgroupExtensionFieldNumber, 46); - EXPECT_EQ(unittest::kRepeatedNestedMessageExtensionFieldNumber, 48); - 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) { - // Test that our nested enum values can be used as switch cases. This test - // doesn't actually do anything, the proof that it works is that it - // compiles. - int i =0; - unittest::TestAllTypes::NestedEnum a = unittest::TestAllTypes::BAR; - switch (a) { - case unittest::TestAllTypes::FOO: - i = 1; - break; - case unittest::TestAllTypes::BAR: - i = 2; - break; - case unittest::TestAllTypes::BAZ: - i = 3; - break; - case unittest::TestAllTypes::NEG: - i = -1; - break; - // no default case: We want to make sure the compiler recognizes that - // all cases are covered. (GCC warns if you do not cover all cases of - // an enum in a switch.) - } - - // Token check just for fun. - EXPECT_EQ(2, i); -} - -TEST(GeneratedEnumTest, IsValidValue) { - // Test enum IsValidValue. - EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(1)); - EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(2)); - EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(3)); - - EXPECT_FALSE(unittest::TestAllTypes::NestedEnum_IsValid(0)); - EXPECT_FALSE(unittest::TestAllTypes::NestedEnum_IsValid(4)); - - // Make sure it also works when there are dups. - EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(1)); - EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(2)); - EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(3)); - - EXPECT_FALSE(unittest::TestEnumWithDupValue_IsValid(0)); - EXPECT_FALSE(unittest::TestEnumWithDupValue_IsValid(4)); -} - -TEST(GeneratedEnumTest, MinAndMax) { - EXPECT_EQ(unittest::TestAllTypes::NEG, - unittest::TestAllTypes::NestedEnum_MIN); - EXPECT_EQ(unittest::TestAllTypes::BAZ, - unittest::TestAllTypes::NestedEnum_MAX); - EXPECT_EQ(4, unittest::TestAllTypes::NestedEnum_ARRAYSIZE); - - EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN); - EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX); - EXPECT_EQ(7, unittest::ForeignEnum_ARRAYSIZE); - - EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN); - EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX); - EXPECT_EQ(4, unittest::TestEnumWithDupValue_ARRAYSIZE); - - EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN); - EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX); - EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE); - - // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. - void* null_pointer = 0; // NULL may be integer-type, not pointer-type. - EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_MIN); - EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_MAX); - EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_ARRAYSIZE); - - EXPECT_NE(null_pointer, &unittest::ForeignEnum_MIN); - EXPECT_NE(null_pointer, &unittest::ForeignEnum_MAX); - EXPECT_NE(null_pointer, &unittest::ForeignEnum_ARRAYSIZE); - - // Make sure we can use _MIN and _MAX as switch cases. - switch (unittest::SPARSE_A) { - case unittest::TestSparseEnum_MIN: - case unittest::TestSparseEnum_MAX: - break; - default: - break; - } -} - -#ifndef PROTOBUF_TEST_NO_DESCRIPTORS - -TEST(GeneratedEnumTest, Name) { - // "Names" in the presence of dup values are a bit arbitrary. - EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO1)); - EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO2)); - - EXPECT_EQ("SPARSE_A", unittest::TestSparseEnum_Name(unittest::SPARSE_A)); - EXPECT_EQ("SPARSE_B", unittest::TestSparseEnum_Name(unittest::SPARSE_B)); - EXPECT_EQ("SPARSE_C", unittest::TestSparseEnum_Name(unittest::SPARSE_C)); - EXPECT_EQ("SPARSE_D", unittest::TestSparseEnum_Name(unittest::SPARSE_D)); - EXPECT_EQ("SPARSE_E", unittest::TestSparseEnum_Name(unittest::SPARSE_E)); - EXPECT_EQ("SPARSE_F", unittest::TestSparseEnum_Name(unittest::SPARSE_F)); - EXPECT_EQ("SPARSE_G", unittest::TestSparseEnum_Name(unittest::SPARSE_G)); -} - -TEST(GeneratedEnumTest, Parse) { - unittest::TestEnumWithDupValue dup_value = unittest::FOO1; - EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO1", &dup_value)); - EXPECT_EQ(unittest::FOO1, dup_value); - EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO2", &dup_value)); - EXPECT_EQ(unittest::FOO2, dup_value); - EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value)); -} - -TEST(GeneratedEnumTest, GetEnumDescriptor) { - EXPECT_EQ(unittest::TestAllTypes::NestedEnum_descriptor(), - GetEnumDescriptor<unittest::TestAllTypes::NestedEnum>()); - EXPECT_EQ(unittest::ForeignEnum_descriptor(), - GetEnumDescriptor<unittest::ForeignEnum>()); - EXPECT_EQ(unittest::TestEnumWithDupValue_descriptor(), - GetEnumDescriptor<unittest::TestEnumWithDupValue>()); - EXPECT_EQ(unittest::TestSparseEnum_descriptor(), - GetEnumDescriptor<unittest::TestSparseEnum>()); -} - -enum NonProtoEnum { - kFoo = 1, -}; - -TEST(GeneratedEnumTest, IsProtoEnumTypeTrait) { - EXPECT_TRUE(is_proto_enum<unittest::TestAllTypes::NestedEnum>::value); - EXPECT_TRUE(is_proto_enum<unittest::ForeignEnum>::value); - EXPECT_TRUE(is_proto_enum<unittest::TestEnumWithDupValue>::value); - EXPECT_TRUE(is_proto_enum<unittest::TestSparseEnum>::value); - - EXPECT_FALSE(is_proto_enum<int>::value); - EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value); -} - -#endif // PROTOBUF_TEST_NO_DESCRIPTORS - -// =================================================================== - -#ifndef PROTOBUF_TEST_NO_DESCRIPTORS - -// Support code for testing services. -class GeneratedServiceTest : public testing::Test { - protected: - class MockTestService : public unittest::TestService { - public: - MockTestService() - : called_(false), - method_(""), - controller_(NULL), - request_(NULL), - response_(NULL), - done_(NULL) {} - - ~MockTestService() {} - - void Reset() { called_ = false; } - - // implements TestService ---------------------------------------- - - void Foo(RpcController* controller, - const unittest::FooRequest* request, - unittest::FooResponse* response, - Closure* done) { - ASSERT_FALSE(called_); - called_ = true; - method_ = "Foo"; - controller_ = controller; - request_ = request; - response_ = response; - done_ = done; - } - - void Bar(RpcController* controller, - const unittest::BarRequest* request, - unittest::BarResponse* response, - Closure* done) { - ASSERT_FALSE(called_); - called_ = true; - method_ = "Bar"; - controller_ = controller; - request_ = request; - response_ = response; - done_ = done; - } - - // --------------------------------------------------------------- - - bool called_; - string method_; - RpcController* controller_; - const Message* request_; - Message* response_; - Closure* done_; - }; - - class MockRpcChannel : public RpcChannel { - public: - MockRpcChannel() - : called_(false), - method_(NULL), - controller_(NULL), - request_(NULL), - response_(NULL), - done_(NULL), - destroyed_(NULL) {} - - ~MockRpcChannel() { - if (destroyed_ != NULL) *destroyed_ = true; - } - - void Reset() { called_ = false; } - - // implements TestService ---------------------------------------- - - void CallMethod(const MethodDescriptor* method, - RpcController* controller, - const Message* request, - Message* response, - Closure* done) { - ASSERT_FALSE(called_); - called_ = true; - method_ = method; - controller_ = controller; - request_ = request; - response_ = response; - done_ = done; - } - - // --------------------------------------------------------------- - - bool called_; - const MethodDescriptor* method_; - RpcController* controller_; - const Message* request_; - Message* response_; - Closure* done_; - bool* destroyed_; - }; - - class MockController : public RpcController { - public: - void Reset() { - ADD_FAILURE() << "Reset() not expected during this test."; - } - bool Failed() const { - ADD_FAILURE() << "Failed() not expected during this test."; - return false; - } - string ErrorText() const { - ADD_FAILURE() << "ErrorText() not expected during this test."; - return ""; - } - void StartCancel() { - ADD_FAILURE() << "StartCancel() not expected during this test."; - } - void SetFailed(const string& reason) { - ADD_FAILURE() << "SetFailed() not expected during this test."; - } - bool IsCanceled() const { - ADD_FAILURE() << "IsCanceled() not expected during this test."; - return false; - } - void NotifyOnCancel(Closure* callback) { - ADD_FAILURE() << "NotifyOnCancel() not expected during this test."; - } - }; - - GeneratedServiceTest() - : descriptor_(unittest::TestService::descriptor()), - foo_(descriptor_->FindMethodByName("Foo")), - bar_(descriptor_->FindMethodByName("Bar")), - stub_(&mock_channel_), - done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {} - - virtual void SetUp() { - ASSERT_TRUE(foo_ != NULL); - ASSERT_TRUE(bar_ != NULL); - } - - const ServiceDescriptor* descriptor_; - const MethodDescriptor* foo_; - const MethodDescriptor* bar_; - - MockTestService mock_service_; - MockController mock_controller_; - - MockRpcChannel mock_channel_; - unittest::TestService::Stub stub_; - - // Just so we don't have to re-define these with every test. - unittest::FooRequest foo_request_; - unittest::FooResponse foo_response_; - unittest::BarRequest bar_request_; - unittest::BarResponse bar_response_; - google::protobuf::scoped_ptr<Closure> done_; -}; - -TEST_F(GeneratedServiceTest, GetDescriptor) { - // Test that GetDescriptor() works. - - EXPECT_EQ(descriptor_, mock_service_.GetDescriptor()); -} - -TEST_F(GeneratedServiceTest, GetChannel) { - EXPECT_EQ(&mock_channel_, stub_.channel()); -} - -TEST_F(GeneratedServiceTest, OwnsChannel) { - MockRpcChannel* channel = new MockRpcChannel; - bool destroyed = false; - channel->destroyed_ = &destroyed; - - { - unittest::TestService::Stub owning_stub(channel, - Service::STUB_OWNS_CHANNEL); - EXPECT_FALSE(destroyed); - } - - EXPECT_TRUE(destroyed); -} - -TEST_F(GeneratedServiceTest, CallMethod) { - // Test that CallMethod() works. - - // Call Foo() via CallMethod(). - mock_service_.CallMethod(foo_, &mock_controller_, - &foo_request_, &foo_response_, done_.get()); - - ASSERT_TRUE(mock_service_.called_); - - EXPECT_EQ("Foo" , mock_service_.method_ ); - EXPECT_EQ(&mock_controller_, mock_service_.controller_); - EXPECT_EQ(&foo_request_ , mock_service_.request_ ); - EXPECT_EQ(&foo_response_ , mock_service_.response_ ); - EXPECT_EQ(done_.get() , mock_service_.done_ ); - - // Try again, but call Bar() instead. - mock_service_.Reset(); - mock_service_.CallMethod(bar_, &mock_controller_, - &bar_request_, &bar_response_, done_.get()); - - ASSERT_TRUE(mock_service_.called_); - EXPECT_EQ("Bar", mock_service_.method_); -} - -TEST_F(GeneratedServiceTest, CallMethodTypeFailure) { - // Verify death if we call Foo() with Bar's message types. - -#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet - EXPECT_DEBUG_DEATH( - mock_service_.CallMethod(foo_, &mock_controller_, - &foo_request_, &bar_response_, done_.get()), - "dynamic_cast"); - - mock_service_.Reset(); - EXPECT_DEBUG_DEATH( - mock_service_.CallMethod(foo_, &mock_controller_, - &bar_request_, &foo_response_, done_.get()), - "dynamic_cast"); -#endif // PROTOBUF_HAS_DEATH_TEST -} - -TEST_F(GeneratedServiceTest, GetPrototypes) { - // Test Get{Request,Response}Prototype() methods. - - EXPECT_EQ(&unittest::FooRequest::default_instance(), - &mock_service_.GetRequestPrototype(foo_)); - EXPECT_EQ(&unittest::BarRequest::default_instance(), - &mock_service_.GetRequestPrototype(bar_)); - - EXPECT_EQ(&unittest::FooResponse::default_instance(), - &mock_service_.GetResponsePrototype(foo_)); - EXPECT_EQ(&unittest::BarResponse::default_instance(), - &mock_service_.GetResponsePrototype(bar_)); -} - -TEST_F(GeneratedServiceTest, Stub) { - // Test that the stub class works. - - // Call Foo() via the stub. - stub_.Foo(&mock_controller_, &foo_request_, &foo_response_, done_.get()); - - ASSERT_TRUE(mock_channel_.called_); - - EXPECT_EQ(foo_ , mock_channel_.method_ ); - EXPECT_EQ(&mock_controller_, mock_channel_.controller_); - EXPECT_EQ(&foo_request_ , mock_channel_.request_ ); - EXPECT_EQ(&foo_response_ , mock_channel_.response_ ); - EXPECT_EQ(done_.get() , mock_channel_.done_ ); - - // Call Bar() via the stub. - mock_channel_.Reset(); - stub_.Bar(&mock_controller_, &bar_request_, &bar_response_, done_.get()); - - ASSERT_TRUE(mock_channel_.called_); - EXPECT_EQ(bar_, mock_channel_.method_); -} - -TEST_F(GeneratedServiceTest, NotImplemented) { - // Test that failing to implement a method of a service causes it to fail - // with a "not implemented" error message. - - // A service which doesn't implement any methods. - class UnimplementedService : public unittest::TestService { - public: - UnimplementedService() {} - }; - - UnimplementedService unimplemented_service; - - // And a controller which expects to get a "not implemented" error. - class ExpectUnimplementedController : public MockController { - public: - ExpectUnimplementedController() : called_(false) {} - - void SetFailed(const string& reason) { - EXPECT_FALSE(called_); - called_ = true; - EXPECT_EQ("Method Foo() not implemented.", reason); - } - - bool called_; - }; - - ExpectUnimplementedController controller; - - // Call Foo. - unimplemented_service.Foo(&controller, &foo_request_, &foo_response_, - done_.get()); - - EXPECT_TRUE(controller.called_); -} - -// =================================================================== - -class OneofTest : public testing::Test { - protected: - virtual void SetUp() { - } - - void ExpectEnumCasesWork(const unittest::TestOneof2 &message) { - switch (message.foo_case()) { - case unittest::TestOneof2::kFooInt: - EXPECT_TRUE(message.has_foo_int()); - break; - 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; - case unittest::TestOneof2::kFooEnum: - EXPECT_TRUE(message.has_foo_enum()); - break; - case unittest::TestOneof2::kFooMessage: - EXPECT_TRUE(message.has_foo_message()); - break; - 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; - } - } -}; - -TEST_F(OneofTest, SettingOneFieldClearsOthers) { - unittest::TestOneof2 message; - - message.set_foo_int(123); - EXPECT_TRUE(message.has_foo_int()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - message.set_foo_string("foo"); - EXPECT_TRUE(message.has_foo_string()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - - message.set_foo_bytes("qux"); - EXPECT_TRUE(message.has_foo_bytes()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - message.set_foo_enum(unittest::TestOneof2::FOO); - EXPECT_TRUE(message.has_foo_enum()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - message.mutable_foo_message()->set_qux_int(234); - EXPECT_TRUE(message.has_foo_message()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - message.mutable_foogroup()->set_a(345); - EXPECT_TRUE(message.has_foogroup()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); - - - // we repeat this because we didn't test if this properly clears other fields - // at the beginning. - message.set_foo_int(123); - EXPECT_TRUE(message.has_foo_int()); - TestUtil::ExpectAtMostOneFieldSetInOneof(message); -} - -TEST_F(OneofTest, EnumCases) { - unittest::TestOneof2 message; - - message.set_foo_int(123); - ExpectEnumCasesWork(message); - message.set_foo_string("foo"); - ExpectEnumCasesWork(message); - message.set_foo_bytes("qux"); - ExpectEnumCasesWork(message); - message.set_foo_enum(unittest::TestOneof2::FOO); - ExpectEnumCasesWork(message); - message.mutable_foo_message()->set_qux_int(234); - ExpectEnumCasesWork(message); - message.mutable_foogroup()->set_a(345); - ExpectEnumCasesWork(message); -} - -TEST_F(OneofTest, PrimitiveType) { - unittest::TestOneof2 message; - // Unset field returns default value - EXPECT_EQ(message.foo_int(), 0); - - message.set_foo_int(123); - EXPECT_TRUE(message.has_foo_int()); - EXPECT_EQ(message.foo_int(), 123); - message.clear_foo_int(); - EXPECT_FALSE(message.has_foo_int()); -} - -TEST_F(OneofTest, EnumType) { - unittest::TestOneof2 message; - // Unset field returns default value - EXPECT_EQ(message.foo_enum(), 1); - - message.set_foo_enum(unittest::TestOneof2::FOO); - EXPECT_TRUE(message.has_foo_enum()); - EXPECT_EQ(message.foo_enum(), unittest::TestOneof2::FOO); - message.clear_foo_enum(); - EXPECT_FALSE(message.has_foo_enum()); -} - -TEST_F(OneofTest, SetString) { - // Check that setting a string field in various ways works - unittest::TestOneof2 message; - - // Unset field returns default value - EXPECT_EQ(message.foo_string(), ""); - - message.set_foo_string("foo"); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "foo"); - message.clear_foo_string(); - EXPECT_FALSE(message.has_foo_string()); - - message.set_foo_string(string("bar")); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "bar"); - message.clear_foo_string(); - EXPECT_FALSE(message.has_foo_string()); - - - message.set_foo_string("qux", 3); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "qux"); - message.clear_foo_string(); - EXPECT_FALSE(message.has_foo_string()); - - message.mutable_foo_string()->assign("quux"); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "quux"); - message.clear_foo_string(); - EXPECT_FALSE(message.has_foo_string()); - - message.set_foo_string("corge"); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "corge"); - message.clear_foo_string(); - EXPECT_FALSE(message.has_foo_string()); -} - -TEST_F(OneofTest, ReleaseString) { - // Check that release_foo() starts out NULL, and gives us a value - // that we can delete after it's been set. - unittest::TestOneof2 message; - - EXPECT_EQ(NULL, message.release_foo_string()); - EXPECT_FALSE(message.has_foo_string()); - - message.set_foo_string("blah"); - EXPECT_TRUE(message.has_foo_string()); - google::protobuf::scoped_ptr<string> str(message.release_foo_string()); - EXPECT_FALSE(message.has_foo_string()); - ASSERT_TRUE(str != NULL); - EXPECT_EQ("blah", *str); - - EXPECT_EQ(NULL, message.release_foo_string()); - EXPECT_FALSE(message.has_foo_string()); -} - -TEST_F(OneofTest, SetAllocatedString) { - // Check that set_allocated_foo() works for strings. - unittest::TestOneof2 message; - - EXPECT_FALSE(message.has_foo_string()); - const string kHello("hello"); - message.set_foo_string(kHello); - EXPECT_TRUE(message.has_foo_string()); - - message.set_allocated_foo_string(NULL); - EXPECT_FALSE(message.has_foo_string()); - EXPECT_EQ("", message.foo_string()); - - message.set_allocated_foo_string(new string(kHello)); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(kHello, message.foo_string()); -} - - -TEST_F(OneofTest, SetMessage) { - // Check that setting a message field works - unittest::TestOneof2 message; - - // Unset field returns default instance - EXPECT_EQ(&message.foo_message(), - &unittest::TestOneof2_NestedMessage::default_instance()); - EXPECT_EQ(message.foo_message().qux_int(), 0); - - message.mutable_foo_message()->set_qux_int(234); - EXPECT_TRUE(message.has_foo_message()); - EXPECT_EQ(message.foo_message().qux_int(), 234); - message.clear_foo_message(); - EXPECT_FALSE(message.has_foo_message()); -} - -TEST_F(OneofTest, ReleaseMessage) { - // Check that release_foo() starts out NULL, and gives us a value - // that we can delete after it's been set. - unittest::TestOneof2 message; - - EXPECT_EQ(NULL, message.release_foo_message()); - EXPECT_FALSE(message.has_foo_message()); - - message.mutable_foo_message()->set_qux_int(1); - EXPECT_TRUE(message.has_foo_message()); - google::protobuf::scoped_ptr<unittest::TestOneof2_NestedMessage> mes( - message.release_foo_message()); - EXPECT_FALSE(message.has_foo_message()); - ASSERT_TRUE(mes != NULL); - EXPECT_EQ(1, mes->qux_int()); - - EXPECT_EQ(NULL, message.release_foo_message()); - EXPECT_FALSE(message.has_foo_message()); -} - -TEST_F(OneofTest, SetAllocatedMessage) { - // Check that set_allocated_foo() works for messages. - unittest::TestOneof2 message; - - EXPECT_FALSE(message.has_foo_message()); - - message.mutable_foo_message()->set_qux_int(1); - EXPECT_TRUE(message.has_foo_message()); - - message.set_allocated_foo_message(NULL); - EXPECT_FALSE(message.has_foo_message()); - EXPECT_EQ(&message.foo_message(), - &unittest::TestOneof2_NestedMessage::default_instance()); - - message.mutable_foo_message()->set_qux_int(1); - unittest::TestOneof2_NestedMessage* mes = message.release_foo_message(); - ASSERT_TRUE(mes != NULL); - EXPECT_FALSE(message.has_foo_message()); - - message.set_allocated_foo_message(mes); - EXPECT_TRUE(message.has_foo_message()); - EXPECT_EQ(1, message.foo_message().qux_int()); -} - - -TEST_F(OneofTest, Clear) { - unittest::TestOneof2 message; - - message.set_foo_int(1); - EXPECT_TRUE(message.has_foo_int()); - message.clear_foo_int(); - EXPECT_FALSE(message.has_foo_int()); -} - -TEST_F(OneofTest, Defaults) { - unittest::TestOneof2 message; - - EXPECT_FALSE(message.has_foo_int()); - EXPECT_EQ(message.foo_int(), 0); - - EXPECT_FALSE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), ""); - - - EXPECT_FALSE(message.has_foo_bytes()); - EXPECT_EQ(message.foo_bytes(), ""); - - EXPECT_FALSE(message.has_foo_enum()); - EXPECT_EQ(message.foo_enum(), 1); - - EXPECT_FALSE(message.has_foo_message()); - EXPECT_EQ(message.foo_message().qux_int(), 0); - - EXPECT_FALSE(message.has_foogroup()); - EXPECT_EQ(message.foogroup().a(), 0); - - - EXPECT_FALSE(message.has_bar_int()); - EXPECT_EQ(message.bar_int(), 5); - - EXPECT_FALSE(message.has_bar_string()); - EXPECT_EQ(message.bar_string(), "STRING"); - - - EXPECT_FALSE(message.has_bar_bytes()); - EXPECT_EQ(message.bar_bytes(), "BYTES"); - - EXPECT_FALSE(message.has_bar_enum()); - EXPECT_EQ(message.bar_enum(), 2); -} - -TEST_F(OneofTest, SwapWithEmpty) { - unittest::TestOneof2 message1, message2; - message1.set_foo_string("FOO"); - EXPECT_TRUE(message1.has_foo_string()); - message1.Swap(&message2); - EXPECT_FALSE(message1.has_foo_string()); - EXPECT_TRUE(message2.has_foo_string()); - EXPECT_EQ(message2.foo_string(), "FOO"); -} - -TEST_F(OneofTest, SwapWithSelf) { - unittest::TestOneof2 message; - message.set_foo_string("FOO"); - EXPECT_TRUE(message.has_foo_string()); - message.Swap(&message); - EXPECT_TRUE(message.has_foo_string()); - EXPECT_EQ(message.foo_string(), "FOO"); -} - -TEST_F(OneofTest, SwapBothHasFields) { - unittest::TestOneof2 message1, message2; - - message1.set_foo_string("FOO"); - EXPECT_TRUE(message1.has_foo_string()); - message2.mutable_foo_message()->set_qux_int(1); - EXPECT_TRUE(message2.has_foo_message()); - - message1.Swap(&message2); - EXPECT_FALSE(message1.has_foo_string()); - EXPECT_FALSE(message2.has_foo_message()); - EXPECT_TRUE(message1.has_foo_message()); - EXPECT_EQ(message1.foo_message().qux_int(), 1); - EXPECT_TRUE(message2.has_foo_string()); - EXPECT_EQ(message2.foo_string(), "FOO"); -} - -TEST_F(OneofTest, CopyConstructor) { - unittest::TestOneof2 message1; - message1.set_foo_bytes("FOO"); - - unittest::TestOneof2 message2(message1); - EXPECT_TRUE(message2.has_foo_bytes()); - EXPECT_EQ(message2.foo_bytes(), "FOO"); -} - -TEST_F(OneofTest, CopyFrom) { - unittest::TestOneof2 message1, message2; - message1.set_foo_enum(unittest::TestOneof2::BAR); - EXPECT_TRUE(message1.has_foo_enum()); - - message2.CopyFrom(message1); - EXPECT_TRUE(message2.has_foo_enum()); - EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR); - - // Copying from self should be a no-op. - message2.CopyFrom(message2); - EXPECT_TRUE(message2.has_foo_enum()); - EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR); -} - -TEST_F(OneofTest, CopyAssignmentOperator) { - unittest::TestOneof2 message1; - message1.mutable_foo_message()->set_qux_int(123); - EXPECT_TRUE(message1.has_foo_message()); - - unittest::TestOneof2 message2; - message2 = message1; - EXPECT_EQ(message2.foo_message().qux_int(), 123); - - // Make sure that self-assignment does something sane. - message2 = message2; - EXPECT_EQ(message2.foo_message().qux_int(), 123); -} - -TEST_F(OneofTest, UpcastCopyFrom) { - // Test the CopyFrom method that takes in the generic const Message& - // parameter. - unittest::TestOneof2 message1, message2; - message1.mutable_foogroup()->set_a(123); - EXPECT_TRUE(message1.has_foogroup()); - - const Message* source = implicit_cast<const Message*>(&message1); - message2.CopyFrom(*source); - - EXPECT_TRUE(message2.has_foogroup()); - EXPECT_EQ(message2.foogroup().a(), 123); -} - -// Test the generated SerializeWithCachedSizesToArray(), -// This indirectly tests MergePartialFromCodedStream() -// We have to test each field type separately because we cannot set them at the -// same time -TEST_F(OneofTest, SerializationToArray) { - // Primitive type - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_int(123); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_int(), 123); - } - - // String - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_string("foo"); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_string(), "foo"); - } - - - // Bytes - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_bytes("qux"); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_bytes(), "qux"); - } - - // Enum - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_enum(unittest::TestOneof2::FOO); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO); - } - - // Message - { - unittest::TestOneof2 message1, message2; - string data; - message1.mutable_foo_message()->set_qux_int(234); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_message().qux_int(), 234); - } - - // Group - { - unittest::TestOneof2 message1, message2; - string data; - message1.mutable_foogroup()->set_a(345); - int size = message1.ByteSize(); - data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); - uint8* end = message1.SerializeWithCachedSizesToArray(start); - EXPECT_EQ(size, end - start); - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foogroup().a(), 345); - } - -} - -// Test the generated SerializeWithCachedSizes() by forcing the buffer to write -// one byte at a time. -// This indirectly tests MergePartialFromCodedStream() -// We have to test each field type separately because we cannot set them at the -// same time -TEST_F(OneofTest, SerializationToStream) { - // Primitive type - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_int(123); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_int(), 123); - } - - // String - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_string("foo"); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_string(), "foo"); - } - - - // Bytes - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_bytes("qux"); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_bytes(), "qux"); - } - - // Enum - { - unittest::TestOneof2 message1, message2; - string data; - message1.set_foo_enum(unittest::TestOneof2::FOO); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO); - } - - // Message - { - unittest::TestOneof2 message1, message2; - string data; - message1.mutable_foo_message()->set_qux_int(234); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foo_message().qux_int(), 234); - } - - // Group - { - unittest::TestOneof2 message1, message2; - string data; - message1.mutable_foogroup()->set_a(345); - int size = message1.ByteSize(); - data.resize(size); - - { - // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); - } - - EXPECT_TRUE(message2.ParseFromString(data)); - EXPECT_EQ(message2.foogroup().a(), 345); - } - -} - -TEST_F(OneofTest, MergeFrom) { - unittest::TestOneof2 message1, message2; - - message1.set_foo_int(123); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foo_int()); - EXPECT_EQ(message2.foo_int(), 123); - - message1.set_foo_string("foo"); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foo_string()); - EXPECT_EQ(message2.foo_string(), "foo"); - - - message1.set_foo_bytes("qux"); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foo_bytes()); - EXPECT_EQ(message2.foo_bytes(), "qux"); - - message1.set_foo_enum(unittest::TestOneof2::FOO); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foo_enum()); - EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO); - - message1.mutable_foo_message()->set_qux_int(234); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foo_message()); - EXPECT_EQ(message2.foo_message().qux_int(), 234); - - message1.mutable_foogroup()->set_a(345); - message2.MergeFrom(message1); - TestUtil::ExpectAtMostOneFieldSetInOneof(message2); - EXPECT_TRUE(message2.has_foogroup()); - EXPECT_EQ(message2.foogroup().a(), 345); - -} - -TEST(HelpersTest, TestSCC) { - protobuf_unittest::TestMutualRecursionA a; - SCCAnalyzer scc_analyzer((Options())); - const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor()); - std::vector<string> names; - for (int i = 0; i < scc->descriptors.size(); i++) { - names.push_back(scc->descriptors[i]->full_name()); - } - ASSERT_EQ(names.size(), 4); - std::sort(names.begin(), names.end()); - EXPECT_EQ(names[0], "protobuf_unittest.TestMutualRecursionA"); - EXPECT_EQ(names[1], "protobuf_unittest.TestMutualRecursionA.SubGroup"); - EXPECT_EQ(names[2], "protobuf_unittest.TestMutualRecursionA.SubMessage"); - EXPECT_EQ(names[3], "protobuf_unittest.TestMutualRecursionB"); - - MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); - EXPECT_EQ(result.is_recursive, true); - EXPECT_EQ(result.contains_required, false); - EXPECT_EQ(result.contains_cord, true); // TestAllTypes - EXPECT_EQ(result.contains_extension, false); // TestAllTypes -} - -TEST(HelpersTest, TestSCCAnalysis) { - { - protobuf_unittest::TestRecursiveMessage msg; - SCCAnalyzer scc_analyzer((Options())); - const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); - MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); - EXPECT_EQ(result.is_recursive, true); - EXPECT_EQ(result.contains_required, false); - EXPECT_EQ(result.contains_cord, false); - EXPECT_EQ(result.contains_extension, false); - } - { - protobuf_unittest::TestAllExtensions msg; - SCCAnalyzer scc_analyzer((Options())); - const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); - MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); - EXPECT_EQ(result.is_recursive, false); - EXPECT_EQ(result.contains_required, false); - EXPECT_EQ(result.contains_cord, false); - EXPECT_EQ(result.contains_extension, true); - } - { - protobuf_unittest::TestRequired msg; - SCCAnalyzer scc_analyzer((Options())); - const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); - MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); - EXPECT_EQ(result.is_recursive, false); - EXPECT_EQ(result.contains_required, true); - EXPECT_EQ(result.contains_cord, false); - EXPECT_EQ(result.contains_extension, false); - } -} - -} // namespace cpp_unittest -} // namespace cpp -} // namespace compiler - -namespace no_generic_services_test { - // Verify that no class called "TestService" was defined in - // unittest_no_generic_services.pb.h by defining a different type by the same - // name. If such a service was generated, this will not compile. - struct TestService { - int i; - }; -} - -namespace compiler { -namespace cpp { -namespace cpp_unittest { - -TEST_F(GeneratedServiceTest, NoGenericServices) { - // Verify that non-services in unittest_no_generic_services.proto were - // generated. - no_generic_services_test::TestMessage message; - message.set_a(1); - message.SetExtension(no_generic_services_test::test_extension, 123); - no_generic_services_test::TestEnum e = no_generic_services_test::FOO; - EXPECT_EQ(e, 1); - - // Verify that a ServiceDescriptor is generated for the service even if the - // class itself is not. - const FileDescriptor* file = - no_generic_services_test::TestMessage::descriptor()->file(); - - ASSERT_EQ(1, file->service_count()); - EXPECT_EQ("TestService", file->service(0)->name()); - ASSERT_EQ(1, file->service(0)->method_count()); - EXPECT_EQ("Foo", file->service(0)->method(0)->name()); -} - -#endif // !PROTOBUF_TEST_NO_DESCRIPTORS - -// =================================================================== - -// This test must run last. It verifies that descriptors were or were not -// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. -// When this is defined, we skip all tests which are expected to trigger -// descriptor initialization. This verifies that everything else still works -// if descriptors are not initialized. -TEST(DescriptorInitializationTest, Initialized) { -#ifdef PROTOBUF_TEST_NO_DESCRIPTORS - bool should_have_descriptors = false; -#else - bool should_have_descriptors = true; -#endif - - EXPECT_EQ(should_have_descriptors, - DescriptorPool::generated_pool()->InternalIsFileLoaded( - "google/protobuf/unittest.proto")); -} - } // namespace cpp_unittest - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc new file mode 100644 index 00000000..ff6354f8 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc @@ -0,0 +1,2281 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// To test the code generator, we actually use it to generate code for +// google/protobuf/unittest.proto, then test that. This means that we +// are actually testing the parser and other parts of the system at the same +// time, and that problems in the generator may show up as compile-time errors +// rather than unittest failures, which may be surprising. However, testing +// the output of the C++ generator directly would be very hard. We can't very +// well just check it against golden files since those files would have to be +// updated for any small change; such a test would be very brittle and probably +// not very helpful. What we really want to test is that the code compiles +// correctly and produces the interfaces we expect, which is why this test +// is written this way. + +#include <google/protobuf/compiler/cpp/cpp_unittest.h> + +#include <memory> +#include <vector> + +#include <google/protobuf/unittest_no_arena.pb.h> +#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) +// We exclude this large proto from cmake build because it's too large for +// visual studio to compile (report internal errors). +#include <google/protobuf/unittest_enormous_descriptor.pb.h> +#endif +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h> +#include <google/protobuf/compiler/importer.h> +#include <google/protobuf/unittest_no_generic_services.pb.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/arena.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/dynamic_message.h> + +#include <google/protobuf/stubs/callback.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/stubs/stl_util.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + string text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const string& filename, int line, int column, + const string& message) { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", + filename, line, column, message); + } +}; + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Test that generated code has proper descriptors: +// Parse a descriptor directly (using google::protobuf::compiler::Importer) and +// compare it to the one that was produced by generated code. +TEST(GENERATED_DESCRIPTOR_TEST_NAME, IdenticalDescriptors) { + const FileDescriptor* generated_descriptor = + UNITTEST::TestAllTypes::descriptor()->file(); + + // Set up the Importer. + MockErrorCollector error_collector; + DiskSourceTree source_tree; + source_tree.MapPath("", TestSourceDir()); + Importer importer(&source_tree, &error_collector); + + // Import (parse) unittest.proto. + const FileDescriptor* parsed_descriptor = + importer.Import(UNITTEST_PROTO_PATH); + EXPECT_EQ("", error_collector.text_); + ASSERT_TRUE(parsed_descriptor != NULL); + + // Test that descriptors are generated correctly by converting them to + // FileDescriptorProtos and comparing. + FileDescriptorProto generated_descriptor_proto, parsed_descriptor_proto; + generated_descriptor->CopyTo(&generated_descriptor_proto); + parsed_descriptor->CopyTo(&parsed_descriptor_proto); + + EXPECT_EQ(parsed_descriptor_proto.DebugString(), + generated_descriptor_proto.DebugString()); +} + +#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) +// 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(GENERATED_DESCRIPTOR_TEST_NAME, EnormousDescriptor) { + const Descriptor* generated_descriptor = + TestEnormousDescriptor::descriptor(); + + EXPECT_TRUE(generated_descriptor != NULL); +} +#endif + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +TEST(GENERATED_MESSAGE_TEST_NAME, Defaults) { + // Check that all default values are set correctly in the initial message. + UNITTEST::TestAllTypes message; + + TestUtil::ExpectClear(message); + + // Messages should return pointers to default instances until first use. + // (This is not checked by ExpectClear() since it is not actually true after + // the fields have been set and then cleared.) + EXPECT_EQ(&UNITTEST::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_EQ(&UNITTEST::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_EQ(&UNITTEST_IMPORT::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +#ifndef PROTOBUF_USE_DLLS +TEST(GENERATED_MESSAGE_TEST_NAME, Int32StringConversion) { + EXPECT_EQ("971", Int32ToString(971)); + EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min)); + EXPECT_EQ("2147483647", Int32ToString(kint32max)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Int64StringConversion) { + EXPECT_EQ("GOOGLE_LONGLONG(971)", Int64ToString(971)); + EXPECT_EQ("GOOGLE_LONGLONG(-2147483648)", Int64ToString(kint32min)); + EXPECT_EQ("GOOGLE_LONGLONG(~0x7fffffffffffffff)", Int64ToString(kint64min)); + EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max)); +} +#endif // !PROTOBUF_USE_DLLS + +TEST(GENERATED_MESSAGE_TEST_NAME, FloatingPointDefaults) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ(0.0f, extreme_default.zero_float()); + EXPECT_EQ(1.0f, extreme_default.one_float()); + EXPECT_EQ(1.5f, extreme_default.small_float()); + EXPECT_EQ(-1.0f, extreme_default.negative_one_float()); + EXPECT_EQ(-1.5f, extreme_default.negative_float()); + EXPECT_EQ(2.0e8f, extreme_default.large_float()); + EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(std::numeric_limits<float>::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-std::numeric_limits<float>::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Trigraph) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ExtremeSmallIntegerDefault) { + const UNITTEST::TestExtremeDefaultValues& extreme_default = + UNITTEST::TestExtremeDefaultValues::default_instance(); + EXPECT_EQ(~0x7fffffff, kint32min); + EXPECT_EQ(GOOGLE_LONGLONG(~0x7fffffffffffffff), kint64min); + EXPECT_EQ(kint32min, extreme_default.really_small_int32()); + EXPECT_EQ(kint64min, extreme_default.really_small_int64()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Accessors) { + // Set every field to a unique value then go back and check all those + // values. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + + TestUtil::ModifyRepeatedFields(&message); + TestUtil::ExpectRepeatedFieldsModified(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, MutableStringDefault) { + // mutable_foo() for a string should return a string initialized to its + // default value. + UNITTEST::TestAllTypes message; + + EXPECT_EQ("hello", *message.mutable_default_string()); + + // Note that the first time we call mutable_foo(), we get a newly-allocated + // string, but if we clear it and call it again, we get the same object again. + // We should verify that it has its default value in both cases. + message.set_default_string("blah"); + message.Clear(); + + EXPECT_EQ("hello", *message.mutable_default_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, StringDefaults) { + UNITTEST::TestExtremeDefaultValues message; + // Check if '\000' can be used in default string value. + EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero()); + EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseString) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); + + message.set_default_string("blah"); + EXPECT_TRUE(message.has_default_string()); + std::unique_ptr<string> str(message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + ASSERT_TRUE(str != NULL); + EXPECT_EQ("blah", *str); + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseMessage) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + std::unique_ptr<UNITTEST::TestAllTypes::NestedMessage> nest( + message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); + ASSERT_TRUE(nest != NULL); + EXPECT_EQ(1, nest->bb()); + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedString) { + // Check that set_allocated_foo() works for strings. + UNITTEST::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_string()); + const string kHello("hello"); + message.set_optional_string(kHello); + EXPECT_TRUE(message.has_optional_string()); + + message.set_allocated_optional_string(NULL); + EXPECT_FALSE(message.has_optional_string()); + EXPECT_EQ("", message.optional_string()); + + message.set_allocated_optional_string(new string(kHello)); + EXPECT_TRUE(message.has_optional_string()); + EXPECT_EQ(kHello, message.optional_string()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedMessage) { + // Check that set_allocated_foo() can be called in all cases. + UNITTEST::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + EXPECT_TRUE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + UNITTEST::TestAllTypes::NestedMessage* nest = + message.release_optional_nested_message(); + ASSERT_TRUE(nest != NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(nest); + EXPECT_TRUE(message.has_optional_nested_message()); + EXPECT_EQ(1, message.optional_nested_message().bb()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, Clear) { + // Set every field to a unique value, clear the message, then check that + // it is cleared. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + message.Clear(); + TestUtil::ExpectClear(message); + + // Unlike with the defaults test, we do NOT expect that requesting embedded + // messages will return a pointer to the default instance. Instead, they + // should return the objects that were created when mutable_blah() was + // called. + EXPECT_NE(&UNITTEST::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_NE(&UNITTEST::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_NE(&UNITTEST::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_NE(&UNITTEST_IMPORT::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, EmbeddedNullsInBytesCharStar) { + UNITTEST::TestAllTypes message; + + const char* value = "\0lalala\0\0"; + message.set_optional_bytes(value, 9); + ASSERT_EQ(9, message.optional_bytes().size()); + EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9)); + + message.add_repeated_bytes(value, 9); + ASSERT_EQ(9, message.repeated_bytes(0).size()); + EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ClearOneField) { + // Set every field to a unique value, then clear one value and insure that + // only that one value is cleared. + UNITTEST::TestAllTypes message; + + TestUtil::SetAllFields(&message); + int64 original_value = message.optional_int64(); + + // Clear the field and make sure it shows up as cleared. + message.clear_optional_int64(); + EXPECT_FALSE(message.has_optional_int64()); + EXPECT_EQ(0, message.optional_int64()); + + // Other adjacent fields should not be cleared. + EXPECT_TRUE(message.has_optional_int32()); + EXPECT_TRUE(message.has_optional_uint32()); + + // Make sure if we set it again, then all fields are set. + message.set_optional_int64(original_value); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, StringCharStarLength) { + // Verify that we can use a char*,length to set one of the string fields. + UNITTEST::TestAllTypes message; + message.set_optional_string("abcdef", 3); + EXPECT_EQ("abc", message.optional_string()); + + // Verify that we can use a char*,length to add to a repeated string field. + message.add_repeated_string("abcdef", 3); + EXPECT_EQ(1, message.repeated_string_size()); + EXPECT_EQ("abc", message.repeated_string(0)); + + // Verify that we can use a char*,length to set a repeated string field. + message.set_repeated_string(0, "wxyz", 2); + EXPECT_EQ("wx", message.repeated_string(0)); +} + +#if LANG_CXX11 +TEST(GENERATED_MESSAGE_TEST_NAME, StringMove) { + // Verify that we trigger the move behavior on a scalar setter. + protobuf_unittest_no_arena::TestAllTypes message; + { + string tmp(32, 'a'); + + const char* old_data = tmp.data(); + message.set_optional_string(std::move(tmp)); + const char* new_data = message.optional_string().data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'a'), message.optional_string()); + + string tmp2(32, 'b'); + old_data = tmp2.data(); + message.set_optional_string(std::move(tmp2)); + new_data = message.optional_string().data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'b'), message.optional_string()); + } + + // Verify that we trigger the move behavior on a oneof setter. + { + string tmp(32, 'a'); + + const char* old_data = tmp.data(); + message.set_oneof_string(std::move(tmp)); + const char* new_data = message.oneof_string().data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'a'), message.oneof_string()); + + string tmp2(32, 'b'); + old_data = tmp2.data(); + message.set_oneof_string(std::move(tmp2)); + new_data = message.oneof_string().data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'b'), message.oneof_string()); + } + + // Verify that we trigger the move behavior on a repeated setter. + { + string tmp(32, 'a'); + + const char* old_data = tmp.data(); + message.add_repeated_string(std::move(tmp)); + const char* new_data = message.repeated_string(0).data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'a'), message.repeated_string(0)); + + string tmp2(32, 'b'); + old_data = tmp2.data(); + message.set_repeated_string(0, std::move(tmp2)); + new_data = message.repeated_string(0).data(); + + EXPECT_EQ(old_data, new_data); + EXPECT_EQ(string(32, 'b'), message.repeated_string(0)); + } +} +#endif + + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyFrom) { + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + message2.CopyFrom(message1); + TestUtil::ExpectAllFieldsSet(message2); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithEmpty) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + + TestUtil::ExpectAllFieldsSet(message1); + TestUtil::ExpectClear(message2); + message1.Swap(&message2); + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithSelf) { + UNITTEST::TestAllTypes message; + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + message.Swap(&message); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) { + UNITTEST::TestAllTypes message1, message2; + + message1.set_optional_int32(123); + message1.set_optional_string("abc"); + message1.mutable_optional_nested_message()->set_bb(1); + message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO); + message1.add_repeated_int32(1); + message1.add_repeated_int32(2); + message1.add_repeated_string("a"); + message1.add_repeated_string("b"); + message1.add_repeated_nested_message()->set_bb(7); + message1.add_repeated_nested_message()->set_bb(8); + message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::FOO); + message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAR); + + message2.set_optional_int32(456); + message2.set_optional_string("def"); + message2.mutable_optional_nested_message()->set_bb(2); + message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR); + message2.add_repeated_int32(3); + message2.add_repeated_string("c"); + message2.add_repeated_nested_message()->set_bb(9); + message2.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAZ); + + message1.Swap(&message2); + + EXPECT_EQ(456, message1.optional_int32()); + EXPECT_EQ("def", message1.optional_string()); + EXPECT_EQ(2, message1.optional_nested_message().bb()); + EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum()); + ASSERT_EQ(1, message1.repeated_int32_size()); + EXPECT_EQ(3, message1.repeated_int32(0)); + ASSERT_EQ(1, message1.repeated_string_size()); + EXPECT_EQ("c", message1.repeated_string(0)); + ASSERT_EQ(1, message1.repeated_nested_message_size()); + EXPECT_EQ(9, message1.repeated_nested_message(0).bb()); + ASSERT_EQ(1, message1.repeated_nested_enum_size()); + EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message1.repeated_nested_enum(0)); + + EXPECT_EQ(123, message2.optional_int32()); + EXPECT_EQ("abc", message2.optional_string()); + EXPECT_EQ(1, message2.optional_nested_message().bb()); + EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum()); + ASSERT_EQ(2, message2.repeated_int32_size()); + EXPECT_EQ(1, message2.repeated_int32(0)); + EXPECT_EQ(2, message2.repeated_int32(1)); + ASSERT_EQ(2, message2.repeated_string_size()); + EXPECT_EQ("a", message2.repeated_string(0)); + EXPECT_EQ("b", message2.repeated_string(1)); + ASSERT_EQ(2, message2.repeated_nested_message_size()); + EXPECT_EQ(7, message2.repeated_nested_message(0).bb()); + EXPECT_EQ(8, message2.repeated_nested_message(1).bb()); + ASSERT_EQ(2, message2.repeated_nested_enum_size()); + EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.repeated_nested_enum(0)); + EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message2.repeated_nested_enum(1)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ADLSwap) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + + // Note the address of one of the repeated fields, to verify it was swapped + // rather than copied. + const int32* addr = &message1.repeated_int32().Get(0); + + using std::swap; + swap(message1, message2); + + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); + + EXPECT_EQ(addr, &message2.repeated_int32().Get(0)); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructor) { + // All set. + { + UNITTEST::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + UNITTEST::TestAllTypes message2(message1); + TestUtil::ExpectAllFieldsSet(message2); + } + + // None set. + { + UNITTEST::TestAllTypes message1; + UNITTEST::TestAllTypes message2(message1); + + EXPECT_FALSE(message1.has_optional_string()); + EXPECT_FALSE(message2.has_optional_string()); + EXPECT_EQ(message1.optional_string(), message2.optional_string()); + + EXPECT_FALSE(message1.has_optional_bytes()); + EXPECT_FALSE(message2.has_optional_bytes()); + EXPECT_EQ(message1.optional_bytes(), message2.optional_bytes()); + + EXPECT_FALSE(message1.has_optional_nested_message()); + EXPECT_FALSE(message2.has_optional_nested_message()); + EXPECT_EQ(&message1.optional_nested_message(), + &message2.optional_nested_message()); + + EXPECT_FALSE(message1.has_optional_foreign_message()); + EXPECT_FALSE(message2.has_optional_foreign_message()); + EXPECT_EQ(&message1.optional_foreign_message(), + &message2.optional_foreign_message()); + + EXPECT_FALSE(message1.has_optional_import_message()); + EXPECT_FALSE(message2.has_optional_import_message()); + EXPECT_EQ(&message1.optional_import_message(), + &message2.optional_import_message()); + + EXPECT_FALSE(message1.has_optional_public_import_message()); + EXPECT_FALSE(message2.has_optional_public_import_message()); + EXPECT_EQ(&message1.optional_public_import_message(), + &message2.optional_public_import_message()); + + EXPECT_FALSE(message1.has_optional_lazy_message()); + EXPECT_FALSE(message2.has_optional_lazy_message()); + EXPECT_EQ(&message1.optional_lazy_message(), + &message2.optional_lazy_message()); + } +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructorWithArenas) { + Arena arena; + UNITTEST::TestAllTypes* message1 = + Arena::CreateMessage<UNITTEST::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1); + + UNITTEST::TestAllTypes message2_stack(*message1); + TestUtil::ExpectAllFieldsSet(message2_stack); + + std::unique_ptr<UNITTEST::TestAllTypes> message2_heap( + new UNITTEST::TestAllTypes(*message1)); + TestUtil::ExpectAllFieldsSet(*message2_heap); + + arena.Reset(); + + // Verify that the copies are still intact. + TestUtil::ExpectAllFieldsSet(message2_stack); + TestUtil::ExpectAllFieldsSet(*message2_heap); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CopyAssignmentOperator) { + UNITTEST::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + UNITTEST::TestAllTypes message2; + message2 = message1; + TestUtil::ExpectAllFieldsSet(message2); + + // Make sure that self-assignment does something sane. + message2.operator=(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + +#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \ + !defined(GOOGLE_PROTOBUF_NO_RTTI) +TEST(GENERATED_MESSAGE_TEST_NAME, UpcastCopyFrom) { + // Test the CopyFrom method that takes in the generic const Message& + // parameter. + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + const Message* source = implicit_cast<const Message*>(&message1); + message2.CopyFrom(*source); + + TestUtil::ExpectAllFieldsSet(message2); +} +#endif + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, DynamicMessageCopyFrom) { + // Test copying from a DynamicMessage, which must fall back to using + // reflection. + UNITTEST::TestAllTypes message2; + + // Construct a new version of the dynamic message via the factory. + DynamicMessageFactory factory; + std::unique_ptr<Message> message1; + message1.reset(factory.GetPrototype( + UNITTEST::TestAllTypes::descriptor())->New()); + + TestUtil::ReflectionTester reflection_tester( + UNITTEST::TestAllTypes::descriptor()); + reflection_tester.SetAllFieldsViaReflection(message1.get()); + + message2.CopyFrom(*message1); + + TestUtil::ExpectAllFieldsSet(message2); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, NonEmptyMergeFrom) { + // Test merging with a non-empty message. Code is a modified form + // of that found in google/protobuf/reflection_ops_unittest.cc. + UNITTEST::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + // This field will test merging into an empty spot. + message2.set_optional_int32(message1.optional_int32()); + message1.clear_optional_int32(); + + // This tests overwriting. + message2.set_optional_string(message1.optional_string()); + message1.set_optional_string("something else"); + + // This tests concatenating. + message2.add_repeated_int32(message1.repeated_int32(1)); + int32 i = message1.repeated_int32(0); + message1.clear_repeated_int32(); + message1.add_repeated_int32(i); + + message1.MergeFrom(message2); + + TestUtil::ExpectAllFieldsSet(message1); +} + + +// Test the generated SerializeWithCachedSizesToArray(), +TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToArray) { + UNITTEST::TestAllTypes message1, message2; + string data; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToArray) { + UNITTEST::TestPackedTypes packed_message1, packed_message2; + string packed_data; + TestUtil::SetPackedFields(&packed_message1); + int packed_size = packed_message1.ByteSizeLong(); + packed_data.resize(packed_size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&packed_data)); + uint8* end = packed_message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(packed_size, end - start); + EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); + TestUtil::ExpectPackedFieldsSet(packed_message2); +} + +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToStream) { + UNITTEST::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSizeLong(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToStream) { + UNITTEST::TestPackedTypes message1, message2; + TestUtil::SetPackedFields(&message1); + int size = message1.ByteSizeLong(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(message2); +} + + +TEST(GENERATED_MESSAGE_TEST_NAME, Required) { + // Test that IsInitialized() returns false if required fields are missing. + UNITTEST::TestRequired message; + + EXPECT_FALSE(message.IsInitialized()); + message.set_a(1); + EXPECT_FALSE(message.IsInitialized()); + message.set_b(2); + EXPECT_FALSE(message.IsInitialized()); + message.set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, RequiredForeign) { + // Test that IsInitialized() returns false if required fields in nested + // messages are missing. + UNITTEST::TestRequiredForeign message; + + EXPECT_TRUE(message.IsInitialized()); + + message.mutable_optional_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_optional_message()->set_a(1); + message.mutable_optional_message()->set_b(2); + message.mutable_optional_message()->set_c(3); + EXPECT_TRUE(message.IsInitialized()); + + message.add_repeated_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_repeated_message(0)->set_a(1); + message.mutable_repeated_message(0)->set_b(2); + message.mutable_repeated_message(0)->set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ForeignNested) { + // Test that TestAllTypes::NestedMessage can be embedded directly into + // another message. + UNITTEST::TestForeignNested message; + + // If this compiles and runs without crashing, it must work. We have + // nothing more to test. + UNITTEST::TestAllTypes::NestedMessage* nested = + message.mutable_foreign_nested(); + nested->set_bb(1); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ReallyLargeTagNumber) { + // Test that really large tag numbers don't break anything. + UNITTEST::TestReallyLargeTagNumber message1, message2; + string data; + + // For the most part, if this compiles and runs then we're probably good. + // (The most likely cause for failure would be if something were attempting + // to allocate a lookup table of some sort using tag numbers as the index.) + // We'll try serializing just for fun. + message1.set_a(1234); + message1.set_bb(5678); + message1.SerializeToString(&data); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1234, message2.a()); + EXPECT_EQ(5678, message2.bb()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, MutualRecursion) { + // Test that mutually-recursive message types work. + UNITTEST::TestMutualRecursionA message; + UNITTEST::TestMutualRecursionA* nested = message.mutable_bb()->mutable_a(); + UNITTEST::TestMutualRecursionA* nested2 = nested->mutable_bb()->mutable_a(); + + // Again, if the above compiles and runs, that's all we really have to + // test, but just for run we'll check that the system didn't somehow come + // up with a pointer loop... + EXPECT_NE(&message, nested); + EXPECT_NE(&message, nested2); + EXPECT_NE(nested, nested2); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, CamelCaseFieldNames) { + // This test is mainly checking that the following compiles, which verifies + // that the field names were coerced to lower-case. + // + // Protocol buffers standard style is to use lowercase-with-underscores for + // field names. Some old proto1 .protos unfortunately used camel-case field + // names. In proto1, these names were forced to lower-case. So, we do the + // same thing in proto2. + + UNITTEST::TestCamelCaseFieldNames message; + + message.set_primitivefield(2); + message.set_stringfield("foo"); + message.set_enumfield(UNITTEST::FOREIGN_FOO); + message.mutable_messagefield()->set_c(6); + + message.add_repeatedprimitivefield(8); + message.add_repeatedstringfield("qux"); + message.add_repeatedenumfield(UNITTEST::FOREIGN_BAR); + message.add_repeatedmessagefield()->set_c(15); + + EXPECT_EQ(2, message.primitivefield()); + EXPECT_EQ("foo", message.stringfield()); + EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.enumfield()); + EXPECT_EQ(6, message.messagefield().c()); + + EXPECT_EQ(8, message.repeatedprimitivefield(0)); + EXPECT_EQ("qux", message.repeatedstringfield(0)); + EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeatedenumfield(0)); + EXPECT_EQ(15, message.repeatedmessagefield(0).c()); +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_MESSAGE_TEST_NAME, TestOptimizedForSize) { + // We rely on the tests in reflection_ops_unittest and wire_format_unittest + // to really test that reflection-based methods work. Here we are mostly + // just making sure that TestOptimizedForSize actually builds and seems to + // function. + + UNITTEST::TestOptimizedForSize message, message2; + message.set_i(1); + message.mutable_msg()->set_c(2); + message2.CopyFrom(message); + EXPECT_EQ(1, message2.i()); + EXPECT_EQ(2, message2.msg().c()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestEmbedOptimizedForSize) { + // Verifies that something optimized for speed can contain something optimized + // for size. + + UNITTEST::TestEmbedOptimizedForSize message, message2; + message.mutable_optional_message()->set_i(1); + message.add_repeated_message()->mutable_msg()->set_c(2); + string data; + message.SerializeToString(&data); + ASSERT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1, message2.optional_message().i()); + EXPECT_EQ(2, message2.repeated_message(0).msg().c()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestSpaceUsed) { + UNITTEST::TestAllTypes message1; + // sizeof provides a lower bound on SpaceUsedLong(). + EXPECT_LE(sizeof(UNITTEST::TestAllTypes), message1.SpaceUsedLong()); + const size_t empty_message_size = message1.SpaceUsedLong(); + + // Setting primitive types shouldn't affect the space used. + message1.set_optional_int32(123); + message1.set_optional_int64(12345); + message1.set_optional_uint32(123); + message1.set_optional_uint64(12345); + EXPECT_EQ(empty_message_size, message1.SpaceUsedLong()); + + // On some STL implementations, setting the string to a small value should + // only increase SpaceUsedLong() by the size of a string object, though this + // is not true everywhere. + message1.set_optional_string("abc"); + EXPECT_LE(empty_message_size + message1.optional_string().size(), + message1.SpaceUsedLong()); + + // Setting a string to a value larger than the string object itself should + // increase SpaceUsedLong(), because it cannot store the value internally. + message1.set_optional_string(string(sizeof(string) + 1, 'x')); + int min_expected_increase = message1.optional_string().capacity(); + EXPECT_LE(empty_message_size + min_expected_increase, + message1.SpaceUsedLong()); + + size_t previous_size = message1.SpaceUsedLong(); + // Adding an optional message should increase the size by the size of the + // nested message type. NestedMessage is simple enough (1 int field) that it + // is equal to sizeof(NestedMessage) + message1.mutable_optional_nested_message(); + ASSERT_EQ(sizeof(UNITTEST::TestAllTypes::NestedMessage), + message1.optional_nested_message().SpaceUsedLong()); + EXPECT_EQ(previous_size + + sizeof(UNITTEST::TestAllTypes::NestedMessage), + message1.SpaceUsedLong()); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, TestOneofSpaceUsed) { + UNITTEST::TestOneof2 message1; + EXPECT_LE(sizeof(UNITTEST::TestOneof2), message1.SpaceUsedLong()); + + const size_t empty_message_size = message1.SpaceUsedLong(); + // Setting primitive types shouldn't affect the space used. + message1.set_foo_int(123); + message1.set_bar_int(12345); + EXPECT_EQ(empty_message_size, message1.SpaceUsedLong()); + + // Setting a string in oneof to a small value should only increase + // SpaceUsedLong() by the size of a string object. + message1.set_foo_string("abc"); + EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsedLong()); + + // Setting a string in oneof to a value larger than the string object itself + // should increase SpaceUsedLong(), because it cannot store the value + // internally. + message1.set_foo_string(string(sizeof(string) + 1, 'x')); + int min_expected_increase = message1.foo_string().capacity() + + sizeof(string); + EXPECT_LE(empty_message_size + min_expected_increase, + message1.SpaceUsedLong()); + + // Setting a message in oneof should delete the other fields and increase the + // size by the size of the nested message type. NestedMessage is simple enough + // that it is equal to sizeof(NestedMessage) + message1.mutable_foo_message(); + ASSERT_EQ(sizeof(UNITTEST::TestOneof2::NestedMessage), + message1.foo_message().SpaceUsedLong()); + EXPECT_EQ(empty_message_size + + sizeof(UNITTEST::TestOneof2::NestedMessage), + message1.SpaceUsedLong()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + + +TEST(GENERATED_MESSAGE_TEST_NAME, FieldConstantValues) { + UNITTEST::TestRequired message; + EXPECT_EQ(UNITTEST::TestAllTypes_NestedMessage::kBbFieldNumber, 1); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalInt32FieldNumber, 1); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalgroupFieldNumber, 16); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedMessageFieldNumber, 18); + EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedEnumFieldNumber, 21); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedInt32FieldNumber, 31); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedgroupFieldNumber, 46); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48); + EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, ExtensionConstantValues) { + EXPECT_EQ(UNITTEST::TestRequired::kSingleFieldNumber, 1000); + EXPECT_EQ(UNITTEST::TestRequired::kMultiFieldNumber, 1001); + EXPECT_EQ(UNITTEST::kOptionalInt32ExtensionFieldNumber, 1); + EXPECT_EQ(UNITTEST::kOptionalgroupExtensionFieldNumber, 16); + EXPECT_EQ(UNITTEST::kOptionalNestedMessageExtensionFieldNumber, 18); + EXPECT_EQ(UNITTEST::kOptionalNestedEnumExtensionFieldNumber, 21); + EXPECT_EQ(UNITTEST::kRepeatedInt32ExtensionFieldNumber, 31); + EXPECT_EQ(UNITTEST::kRepeatedgroupExtensionFieldNumber, 46); + EXPECT_EQ(UNITTEST::kRepeatedNestedMessageExtensionFieldNumber, 48); + EXPECT_EQ(UNITTEST::kRepeatedNestedEnumExtensionFieldNumber, 51); +} + +TEST(GENERATED_MESSAGE_TEST_NAME, 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(GENERATED_ENUM_TEST_NAME, EnumValuesAsSwitchCases) { + // Test that our nested enum values can be used as switch cases. This test + // doesn't actually do anything, the proof that it works is that it + // compiles. + int i =0; + UNITTEST::TestAllTypes::NestedEnum a = UNITTEST::TestAllTypes::BAR; + switch (a) { + case UNITTEST::TestAllTypes::FOO: + i = 1; + break; + case UNITTEST::TestAllTypes::BAR: + i = 2; + break; + case UNITTEST::TestAllTypes::BAZ: + i = 3; + break; + case UNITTEST::TestAllTypes::NEG: + i = -1; + break; + // no default case: We want to make sure the compiler recognizes that + // all cases are covered. (GCC warns if you do not cover all cases of + // an enum in a switch.) + } + + // Token check just for fun. + EXPECT_EQ(2, i); +} + +TEST(GENERATED_ENUM_TEST_NAME, IsValidValue) { + // Test enum IsValidValue. + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(1)); + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(2)); + EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(3)); + + EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(0)); + EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(4)); + + // Make sure it also works when there are dups. + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(1)); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(2)); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(3)); + + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(0)); + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(4)); +} + +TEST(GENERATED_ENUM_TEST_NAME, MinAndMax) { + EXPECT_EQ(UNITTEST::TestAllTypes::NEG, + UNITTEST::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, + UNITTEST::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_EQ(UNITTEST::FOREIGN_FOO, UNITTEST::ForeignEnum_MIN); + EXPECT_EQ(UNITTEST::FOREIGN_BAZ, UNITTEST::ForeignEnum_MAX); + EXPECT_EQ(7, UNITTEST::ForeignEnum_ARRAYSIZE); + + EXPECT_EQ(1, UNITTEST::TestEnumWithDupValue_MIN); + EXPECT_EQ(3, UNITTEST::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, UNITTEST::TestEnumWithDupValue_ARRAYSIZE); + + EXPECT_EQ(UNITTEST::SPARSE_E, UNITTEST::TestSparseEnum_MIN); + EXPECT_EQ(UNITTEST::SPARSE_C, UNITTEST::TestSparseEnum_MAX); + EXPECT_EQ(12589235, UNITTEST::TestSparseEnum_ARRAYSIZE); + + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* null_pointer = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MIN); + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MAX); + EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN and _MAX as switch cases. + switch (UNITTEST::SPARSE_A) { + case UNITTEST::TestSparseEnum_MIN: + case UNITTEST::TestSparseEnum_MAX: + break; + default: + break; + } +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GENERATED_ENUM_TEST_NAME, Name) { + // "Names" in the presence of dup values are a bit arbitrary. + EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO1)); + EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO2)); + + EXPECT_EQ("SPARSE_A", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_A)); + EXPECT_EQ("SPARSE_B", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_B)); + EXPECT_EQ("SPARSE_C", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_C)); + EXPECT_EQ("SPARSE_D", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_D)); + EXPECT_EQ("SPARSE_E", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_E)); + EXPECT_EQ("SPARSE_F", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_F)); + EXPECT_EQ("SPARSE_G", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_G)); +} + +TEST(GENERATED_ENUM_TEST_NAME, Parse) { + UNITTEST::TestEnumWithDupValue dup_value = UNITTEST::FOO1; + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO1", &dup_value)); + EXPECT_EQ(UNITTEST::FOO1, dup_value); + EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO2", &dup_value)); + EXPECT_EQ(UNITTEST::FOO2, dup_value); + EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_Parse("FOO", &dup_value)); +} + +TEST(GENERATED_ENUM_TEST_NAME, GetEnumDescriptor) { + EXPECT_EQ(UNITTEST::TestAllTypes::NestedEnum_descriptor(), + GetEnumDescriptor<UNITTEST::TestAllTypes::NestedEnum>()); + EXPECT_EQ(UNITTEST::ForeignEnum_descriptor(), + GetEnumDescriptor<UNITTEST::ForeignEnum>()); + EXPECT_EQ(UNITTEST::TestEnumWithDupValue_descriptor(), + GetEnumDescriptor<UNITTEST::TestEnumWithDupValue>()); + EXPECT_EQ(UNITTEST::TestSparseEnum_descriptor(), + GetEnumDescriptor<UNITTEST::TestSparseEnum>()); +} + +enum NonProtoEnum { + kFoo = 1, +}; + +TEST(GENERATED_ENUM_TEST_NAME, IsProtoEnumTypeTrait) { + EXPECT_TRUE(is_proto_enum<UNITTEST::TestAllTypes::NestedEnum>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::ForeignEnum>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::TestEnumWithDupValue>::value); + EXPECT_TRUE(is_proto_enum<UNITTEST::TestSparseEnum>::value); + + EXPECT_FALSE(is_proto_enum<int>::value); + EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value); +} + +#endif // PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Support code for testing services. +class GENERATED_SERVICE_TEST_NAME : public testing::Test { + protected: + class MockTestService : public UNITTEST::TestService { + public: + MockTestService() + : called_(false), + method_(""), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL) {} + + ~MockTestService() {} + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void Foo(RpcController* controller, + const UNITTEST::FooRequest* request, + UNITTEST::FooResponse* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Foo"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + void Bar(RpcController* controller, + const UNITTEST::BarRequest* request, + UNITTEST::BarResponse* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Bar"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + string method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + }; + + class MockRpcChannel : public RpcChannel { + public: + MockRpcChannel() + : called_(false), + method_(NULL), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL), + destroyed_(NULL) {} + + ~MockRpcChannel() { + if (destroyed_ != NULL) *destroyed_ = true; + } + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = method; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + const MethodDescriptor* method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + bool* destroyed_; + }; + + class MockController : public RpcController { + public: + void Reset() { + ADD_FAILURE() << "Reset() not expected during this test."; + } + bool Failed() const { + ADD_FAILURE() << "Failed() not expected during this test."; + return false; + } + string ErrorText() const { + ADD_FAILURE() << "ErrorText() not expected during this test."; + return ""; + } + void StartCancel() { + ADD_FAILURE() << "StartCancel() not expected during this test."; + } + void SetFailed(const string& reason) { + ADD_FAILURE() << "SetFailed() not expected during this test."; + } + bool IsCanceled() const { + ADD_FAILURE() << "IsCanceled() not expected during this test."; + return false; + } + void NotifyOnCancel(Closure* callback) { + ADD_FAILURE() << "NotifyOnCancel() not expected during this test."; + } + }; + + GENERATED_SERVICE_TEST_NAME() + : descriptor_(UNITTEST::TestService::descriptor()), + foo_(descriptor_->FindMethodByName("Foo")), + bar_(descriptor_->FindMethodByName("Bar")), + stub_(&mock_channel_), + done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {} + + virtual void SetUp() { + ASSERT_TRUE(foo_ != NULL); + ASSERT_TRUE(bar_ != NULL); + } + + const ServiceDescriptor* descriptor_; + const MethodDescriptor* foo_; + const MethodDescriptor* bar_; + + MockTestService mock_service_; + MockController mock_controller_; + + MockRpcChannel mock_channel_; + UNITTEST::TestService::Stub stub_; + + // Just so we don't have to re-define these with every test. + UNITTEST::FooRequest foo_request_; + UNITTEST::FooResponse foo_response_; + UNITTEST::BarRequest bar_request_; + UNITTEST::BarResponse bar_response_; + std::unique_ptr<Closure> done_; +}; + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetDescriptor) { + // Test that GetDescriptor() works. + + EXPECT_EQ(descriptor_, mock_service_.GetDescriptor()); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetChannel) { + EXPECT_EQ(&mock_channel_, stub_.channel()); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, OwnsChannel) { + MockRpcChannel* channel = new MockRpcChannel; + bool destroyed = false; + channel->destroyed_ = &destroyed; + + { + UNITTEST::TestService::Stub owning_stub(channel, + Service::STUB_OWNS_CHANNEL); + EXPECT_FALSE(destroyed); + } + + EXPECT_TRUE(destroyed); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethod) { + // Test that CallMethod() works. + + // Call Foo() via CallMethod(). + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + + EXPECT_EQ("Foo" , mock_service_.method_ ); + EXPECT_EQ(&mock_controller_, mock_service_.controller_); + EXPECT_EQ(&foo_request_ , mock_service_.request_ ); + EXPECT_EQ(&foo_response_ , mock_service_.response_ ); + EXPECT_EQ(done_.get() , mock_service_.done_ ); + + // Try again, but call Bar() instead. + mock_service_.Reset(); + mock_service_.CallMethod(bar_, &mock_controller_, + &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + EXPECT_EQ("Bar", mock_service_.method_); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethodTypeFailure) { + // Verify death if we call Foo() with Bar's message types. + +#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &bar_response_, done_.get()), + "dynamic_cast"); + + mock_service_.Reset(); + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &bar_request_, &foo_response_, done_.get()), + "dynamic_cast"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, GetPrototypes) { + // Test Get{Request,Response}Prototype() methods. + + EXPECT_EQ(&UNITTEST::FooRequest::default_instance(), + &mock_service_.GetRequestPrototype(foo_)); + EXPECT_EQ(&UNITTEST::BarRequest::default_instance(), + &mock_service_.GetRequestPrototype(bar_)); + + EXPECT_EQ(&UNITTEST::FooResponse::default_instance(), + &mock_service_.GetResponsePrototype(foo_)); + EXPECT_EQ(&UNITTEST::BarResponse::default_instance(), + &mock_service_.GetResponsePrototype(bar_)); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, Stub) { + // Test that the stub class works. + + // Call Foo() via the stub. + stub_.Foo(&mock_controller_, &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + + EXPECT_EQ(foo_ , mock_channel_.method_ ); + EXPECT_EQ(&mock_controller_, mock_channel_.controller_); + EXPECT_EQ(&foo_request_ , mock_channel_.request_ ); + EXPECT_EQ(&foo_response_ , mock_channel_.response_ ); + EXPECT_EQ(done_.get() , mock_channel_.done_ ); + + // Call Bar() via the stub. + mock_channel_.Reset(); + stub_.Bar(&mock_controller_, &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + EXPECT_EQ(bar_, mock_channel_.method_); +} + +TEST_F(GENERATED_SERVICE_TEST_NAME, NotImplemented) { + // Test that failing to implement a method of a service causes it to fail + // with a "not implemented" error message. + + // A service which doesn't implement any methods. + class UnimplementedService : public UNITTEST::TestService { + public: + UnimplementedService() {} + }; + + UnimplementedService unimplemented_service; + + // And a controller which expects to get a "not implemented" error. + class ExpectUnimplementedController : public MockController { + public: + ExpectUnimplementedController() : called_(false) {} + + void SetFailed(const string& reason) { + EXPECT_FALSE(called_); + called_ = true; + EXPECT_EQ("Method Foo() not implemented.", reason); + } + + bool called_; + }; + + ExpectUnimplementedController controller; + + // Call Foo. + unimplemented_service.Foo(&controller, &foo_request_, &foo_response_, + done_.get()); + + EXPECT_TRUE(controller.called_); +} + +// =================================================================== + +class OneofTest : public testing::Test { + protected: + virtual void SetUp() { + } + + void ExpectEnumCasesWork(const UNITTEST::TestOneof2 &message) { + switch (message.foo_case()) { + case UNITTEST::TestOneof2::kFooInt: + EXPECT_TRUE(message.has_foo_int()); + break; + 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; + case UNITTEST::TestOneof2::kFooEnum: + EXPECT_TRUE(message.has_foo_enum()); + break; + case UNITTEST::TestOneof2::kFooMessage: + EXPECT_TRUE(message.has_foo_message()); + break; + 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; + } + } +}; + +TEST_F(OneofTest, SettingOneFieldClearsOthers) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.set_foo_string("foo"); + EXPECT_TRUE(message.has_foo_string()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + + message.set_foo_bytes("qux"); + EXPECT_TRUE(message.has_foo_bytes()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + EXPECT_TRUE(message.has_foo_enum()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.mutable_foo_message()->set_qux_int(234); + EXPECT_TRUE(message.has_foo_message()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + message.mutable_foogroup()->set_a(345); + EXPECT_TRUE(message.has_foogroup()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); + + + // we repeat this because we didn't test if this properly clears other fields + // at the beginning. + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + TestUtil::ExpectAtMostOneFieldSetInOneof(message); +} + +TEST_F(OneofTest, EnumCases) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(123); + ExpectEnumCasesWork(message); + message.set_foo_string("foo"); + ExpectEnumCasesWork(message); + message.set_foo_bytes("qux"); + ExpectEnumCasesWork(message); + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + ExpectEnumCasesWork(message); + message.mutable_foo_message()->set_qux_int(234); + ExpectEnumCasesWork(message); + message.mutable_foogroup()->set_a(345); + ExpectEnumCasesWork(message); +} + +TEST_F(OneofTest, PrimitiveType) { + UNITTEST::TestOneof2 message; + // Unset field returns default value + EXPECT_EQ(message.foo_int(), 0); + + message.set_foo_int(123); + EXPECT_TRUE(message.has_foo_int()); + EXPECT_EQ(message.foo_int(), 123); + message.clear_foo_int(); + EXPECT_FALSE(message.has_foo_int()); +} + +TEST_F(OneofTest, EnumType) { + UNITTEST::TestOneof2 message; + // Unset field returns default value + EXPECT_EQ(message.foo_enum(), 1); + + message.set_foo_enum(UNITTEST::TestOneof2::FOO); + EXPECT_TRUE(message.has_foo_enum()); + EXPECT_EQ(message.foo_enum(), UNITTEST::TestOneof2::FOO); + message.clear_foo_enum(); + EXPECT_FALSE(message.has_foo_enum()); +} + +TEST_F(OneofTest, SetString) { + // Check that setting a string field in various ways works + UNITTEST::TestOneof2 message; + + // Unset field returns default value + EXPECT_EQ(message.foo_string(), ""); + + message.set_foo_string("foo"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "foo"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string(string("bar")); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "bar"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + + message.set_foo_string("qux", 3); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "qux"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.mutable_foo_string()->assign("quux"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "quux"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string("corge"); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "corge"); + message.clear_foo_string(); + EXPECT_FALSE(message.has_foo_string()); +} + +TEST_F(OneofTest, ReleaseString) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestOneof2 message; + + EXPECT_EQ(NULL, message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); + + message.set_foo_string("blah"); + EXPECT_TRUE(message.has_foo_string()); + std::unique_ptr<string> str(message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); + ASSERT_TRUE(str != NULL); + EXPECT_EQ("blah", *str); + + EXPECT_EQ(NULL, message.release_foo_string()); + EXPECT_FALSE(message.has_foo_string()); +} + +TEST_F(OneofTest, SetAllocatedString) { + // Check that set_allocated_foo() works for strings. + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_string()); + const string kHello("hello"); + message.set_foo_string(kHello); + EXPECT_TRUE(message.has_foo_string()); + + message.set_allocated_foo_string(NULL); + EXPECT_FALSE(message.has_foo_string()); + EXPECT_EQ("", message.foo_string()); + + message.set_allocated_foo_string(new string(kHello)); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(kHello, message.foo_string()); +} + + +TEST_F(OneofTest, SetMessage) { + // Check that setting a message field works + UNITTEST::TestOneof2 message; + + // Unset field returns default instance + EXPECT_EQ(&message.foo_message(), + &UNITTEST::TestOneof2_NestedMessage::default_instance()); + EXPECT_EQ(message.foo_message().qux_int(), 0); + + message.mutable_foo_message()->set_qux_int(234); + EXPECT_TRUE(message.has_foo_message()); + EXPECT_EQ(message.foo_message().qux_int(), 234); + message.clear_foo_message(); + EXPECT_FALSE(message.has_foo_message()); +} + +TEST_F(OneofTest, ReleaseMessage) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + UNITTEST::TestOneof2 message; + + EXPECT_EQ(NULL, message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); + + message.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message.has_foo_message()); + std::unique_ptr<UNITTEST::TestOneof2_NestedMessage> mes( + message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); + ASSERT_TRUE(mes != NULL); + EXPECT_EQ(1, mes->qux_int()); + + EXPECT_EQ(NULL, message.release_foo_message()); + EXPECT_FALSE(message.has_foo_message()); +} + +TEST_F(OneofTest, SetAllocatedMessage) { + // Check that set_allocated_foo() works for messages. + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_message()); + + message.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message.has_foo_message()); + + message.set_allocated_foo_message(NULL); + EXPECT_FALSE(message.has_foo_message()); + EXPECT_EQ(&message.foo_message(), + &UNITTEST::TestOneof2_NestedMessage::default_instance()); + + message.mutable_foo_message()->set_qux_int(1); + UNITTEST::TestOneof2_NestedMessage* mes = message.release_foo_message(); + ASSERT_TRUE(mes != NULL); + EXPECT_FALSE(message.has_foo_message()); + + message.set_allocated_foo_message(mes); + EXPECT_TRUE(message.has_foo_message()); + EXPECT_EQ(1, message.foo_message().qux_int()); +} + + +TEST_F(OneofTest, Clear) { + UNITTEST::TestOneof2 message; + + message.set_foo_int(1); + EXPECT_TRUE(message.has_foo_int()); + message.clear_foo_int(); + EXPECT_FALSE(message.has_foo_int()); +} + +TEST_F(OneofTest, Defaults) { + UNITTEST::TestOneof2 message; + + EXPECT_FALSE(message.has_foo_int()); + EXPECT_EQ(message.foo_int(), 0); + + EXPECT_FALSE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), ""); + + + EXPECT_FALSE(message.has_foo_bytes()); + EXPECT_EQ(message.foo_bytes(), ""); + + EXPECT_FALSE(message.has_foo_enum()); + EXPECT_EQ(message.foo_enum(), 1); + + EXPECT_FALSE(message.has_foo_message()); + EXPECT_EQ(message.foo_message().qux_int(), 0); + + EXPECT_FALSE(message.has_foogroup()); + EXPECT_EQ(message.foogroup().a(), 0); + + + EXPECT_FALSE(message.has_bar_int()); + EXPECT_EQ(message.bar_int(), 5); + + EXPECT_FALSE(message.has_bar_string()); + EXPECT_EQ(message.bar_string(), "STRING"); + + + EXPECT_FALSE(message.has_bar_bytes()); + EXPECT_EQ(message.bar_bytes(), "BYTES"); + + EXPECT_FALSE(message.has_bar_enum()); + EXPECT_EQ(message.bar_enum(), 2); +} + +TEST_F(OneofTest, SwapWithEmpty) { + UNITTEST::TestOneof2 message1, message2; + message1.set_foo_string("FOO"); + EXPECT_TRUE(message1.has_foo_string()); + message1.Swap(&message2); + EXPECT_FALSE(message1.has_foo_string()); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "FOO"); +} + +TEST_F(OneofTest, SwapWithSelf) { + UNITTEST::TestOneof2 message; + message.set_foo_string("FOO"); + EXPECT_TRUE(message.has_foo_string()); + message.Swap(&message); + EXPECT_TRUE(message.has_foo_string()); + EXPECT_EQ(message.foo_string(), "FOO"); +} + +TEST_F(OneofTest, SwapBothHasFields) { + UNITTEST::TestOneof2 message1, message2; + + message1.set_foo_string("FOO"); + EXPECT_TRUE(message1.has_foo_string()); + message2.mutable_foo_message()->set_qux_int(1); + EXPECT_TRUE(message2.has_foo_message()); + + message1.Swap(&message2); + EXPECT_FALSE(message1.has_foo_string()); + EXPECT_FALSE(message2.has_foo_message()); + EXPECT_TRUE(message1.has_foo_message()); + EXPECT_EQ(message1.foo_message().qux_int(), 1); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "FOO"); +} + +TEST_F(OneofTest, CopyConstructor) { + UNITTEST::TestOneof2 message1; + message1.set_foo_bytes("FOO"); + + UNITTEST::TestOneof2 message2(message1); + EXPECT_TRUE(message2.has_foo_bytes()); + EXPECT_EQ(message2.foo_bytes(), "FOO"); +} + +TEST_F(OneofTest, CopyFrom) { + UNITTEST::TestOneof2 message1, message2; + message1.set_foo_enum(UNITTEST::TestOneof2::BAR); + EXPECT_TRUE(message1.has_foo_enum()); + + message2.CopyFrom(message1); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR); +} + +TEST_F(OneofTest, CopyAssignmentOperator) { + UNITTEST::TestOneof2 message1; + message1.mutable_foo_message()->set_qux_int(123); + EXPECT_TRUE(message1.has_foo_message()); + + UNITTEST::TestOneof2 message2; + message2 = message1; + EXPECT_EQ(message2.foo_message().qux_int(), 123); + + // Make sure that self-assignment does something sane. + message2 = message2; + EXPECT_EQ(message2.foo_message().qux_int(), 123); +} + +TEST_F(OneofTest, UpcastCopyFrom) { + // Test the CopyFrom method that takes in the generic const Message& + // parameter. + UNITTEST::TestOneof2 message1, message2; + message1.mutable_foogroup()->set_a(123); + EXPECT_TRUE(message1.has_foogroup()); + + const Message* source = implicit_cast<const Message*>(&message1); + message2.CopyFrom(*source); + + EXPECT_TRUE(message2.has_foogroup()); + EXPECT_EQ(message2.foogroup().a(), 123); +} + +// Test the generated SerializeWithCachedSizesToArray(), +// This indirectly tests MergePartialFromCodedStream() +// We have to test each field type separately because we cannot set them at the +// same time +TEST_F(OneofTest, SerializationToArray) { + // Primitive type + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_int(123); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_int(), 123); + } + + // String + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_string("foo"); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_string(), "foo"); + } + + + // Bytes + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_bytes("qux"); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_bytes(), "qux"); + } + + // Enum + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + } + + // Message + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.mutable_foo_message()->set_qux_int(234); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + } + + // Group + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.mutable_foogroup()->set_a(345); + int size = message1.ByteSizeLong(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foogroup().a(), 345); + } + +} + +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +// This indirectly tests MergePartialFromCodedStream() +// We have to test each field type separately because we cannot set them at the +// same time +TEST_F(OneofTest, SerializationToStream) { + // Primitive type + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_int(123); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_int(), 123); + } + + // String + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_string("foo"); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_string(), "foo"); + } + + + // Bytes + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_bytes("qux"); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_bytes(), "qux"); + } + + // Enum + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + } + + // Message + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.mutable_foo_message()->set_qux_int(234); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + } + + // Group + { + UNITTEST::TestOneof2 message1, message2; + string data; + message1.mutable_foogroup()->set_a(345); + int size = message1.ByteSizeLong(); + data.resize(size); + + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(message2.foogroup().a(), 345); + } + +} + +TEST_F(OneofTest, MergeFrom) { + UNITTEST::TestOneof2 message1, message2; + + message1.set_foo_int(123); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_int()); + EXPECT_EQ(message2.foo_int(), 123); + + message1.set_foo_string("foo"); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_string()); + EXPECT_EQ(message2.foo_string(), "foo"); + + + message1.set_foo_bytes("qux"); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_bytes()); + EXPECT_EQ(message2.foo_bytes(), "qux"); + + message1.set_foo_enum(UNITTEST::TestOneof2::FOO); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_enum()); + EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO); + + message1.mutable_foo_message()->set_qux_int(234); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foo_message()); + EXPECT_EQ(message2.foo_message().qux_int(), 234); + + message1.mutable_foogroup()->set_a(345); + message2.MergeFrom(message1); + TestUtil::ExpectAtMostOneFieldSetInOneof(message2); + EXPECT_TRUE(message2.has_foogroup()); + EXPECT_EQ(message2.foogroup().a(), 345); + +} + +TEST(HELPERS_TEST_NAME, TestSCC) { + UNITTEST::TestMutualRecursionA a; + SCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor()); + std::vector<string> names; + for (int i = 0; i < scc->descriptors.size(); i++) { + names.push_back(scc->descriptors[i]->full_name()); + } + string package = a.GetDescriptor()->file()->package(); + ASSERT_EQ(names.size(), 4); + std::sort(names.begin(), names.end()); + EXPECT_EQ(names[0], package + ".TestMutualRecursionA"); + EXPECT_EQ(names[1], package + ".TestMutualRecursionA.SubGroup"); + EXPECT_EQ(names[2], package + ".TestMutualRecursionA.SubMessage"); + EXPECT_EQ(names[3], package + ".TestMutualRecursionB"); + + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, true); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, true); // TestAllTypes + EXPECT_EQ(result.contains_extension, false); // TestAllTypes +} + +TEST(HELPERS_TEST_NAME, TestSCCAnalysis) { + { + UNITTEST::TestRecursiveMessage msg; + SCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, true); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, false); + } + { + UNITTEST::TestAllExtensions msg; + SCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, false); + EXPECT_EQ(result.contains_required, false); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, true); + } + { + UNITTEST::TestRequired msg; + SCCAnalyzer scc_analyzer((Options())); + const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); + MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); + EXPECT_EQ(result.is_recursive, false); + EXPECT_EQ(result.contains_required, true); + EXPECT_EQ(result.contains_cord, false); + EXPECT_EQ(result.contains_extension, false); + } +} + +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GENERATED_SERVICE_TEST_NAME, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension(no_generic_services_test::test_extension, 123); + no_generic_services_test::TestEnum e = no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + no_generic_services_test::TestMessage::descriptor()->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +// This test must run last. It verifies that descriptors were or were not +// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. +// When this is defined, we skip all tests which are expected to trigger +// descriptor initialization. This verifies that everything else still works +// if descriptors are not initialized. +TEST(DESCRIPTOR_INIT_TEST_NAME, Initialized) { +#ifdef PROTOBUF_TEST_NO_DESCRIPTORS + bool should_have_descriptors = false; +#else + bool should_have_descriptors = true; +#endif + + EXPECT_EQ(should_have_descriptors, + DescriptorPool::generated_pool()->InternalIsFileLoaded( + UNITTEST_PROTO_PATH)); +} + +} // namespace cpp_unittest + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index d1bb3194..2ad4edd2 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -29,9 +29,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_generator.h> @@ -72,9 +69,7 @@ class CppMetadataTest : public ::testing::Test { TestTempDir(); const bool result = - atu::CaptureMetadata(filename, cpp_out, - /* meta_file_suffix */ "", &cli, file, - /* outputs */ NULL); + atu::RunProtoCompiler(filename, cpp_out, &cli, file); if (!result) { return result; |