diff options
author | Paul Yang <TeBoring@users.noreply.github.com> | 2016-10-10 13:58:39 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-10 13:58:39 -0700 |
commit | fd046f6263fb17383cafdbb25c361e3451c31105 (patch) | |
tree | 5879fa426bd0cf22df5a7ee39d25b8ece7c117f8 /src/google/protobuf/compiler | |
parent | 337a028bb65ccca4dda768695950b5aba53ae2c9 (diff) | |
parent | daba6653f1289b58873c2ae993afcdb82035d2fb (diff) | |
download | protobuf-fd046f6263fb17383cafdbb25c361e3451c31105.tar.gz protobuf-fd046f6263fb17383cafdbb25c361e3451c31105.tar.bz2 protobuf-fd046f6263fb17383cafdbb25c361e3451c31105.zip |
Merge pull request #2234 from TeBoring/master
Merge 3.1.x branch into master.
Diffstat (limited to 'src/google/protobuf/compiler')
40 files changed, 1933 insertions, 1167 deletions
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 473eb4e6..f6ff1e5d 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -36,6 +36,7 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/descriptor.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -43,6 +44,33 @@ namespace protobuf { namespace compiler { CodeGenerator::~CodeGenerator() {} + +bool CodeGenerator::GenerateAll( + const vector<const FileDescriptor*>& files, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + // Default implemenation is just to call the per file method, and prefix any + // error string with the file to provide context. + bool succeeded = true; + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + succeeded = Generate(file, parameter, generator_context, error); + if (!succeeded && error && error->empty()) { + *error = "Code generator returned false but provided no error " + "description."; + } + if (error && !error->empty()) { + *error = file->name() + ": " + *error; + break; + } + if (!succeeded) { + break; + } + } + return succeeded; +} + GeneratorContext::~GeneratorContext() {} io::ZeroCopyOutputStream* diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index b989f151..642bbfad 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -66,11 +66,11 @@ class LIBPROTOC_EXPORT CodeGenerator { // Generates code for the given proto file, generating one or more files in // the given output directory. // - // A parameter to be passed to the generator can be specified on the - // command line. This is intended to be used by Java and similar languages - // to specify which specific class from the proto file is to be generated, - // though it could have other uses as well. It is empty if no parameter was - // given. + // A parameter to be passed to the generator can be specified on the command + // line. This is intended to be used to pass generator specific parameters. + // It is empty if no parameter was given. ParseGeneratorParameter (below), + // can be used to accept multiple parameters within the single parameter + // command line flag. // // Returns true if successful. Otherwise, sets *error to a description of // the problem (e.g. "invalid parameter") and returns false. @@ -79,18 +79,11 @@ class LIBPROTOC_EXPORT CodeGenerator { GeneratorContext* generator_context, string* error) const = 0; - // Generates code for all given proto files, generating one or more files in - // the given output directory. - // - // This method should be called instead of |Generate()| when - // |HasGenerateAll()| returns |true|. It is used to emulate legacy semantics - // when more than one `.proto` file is specified on one compiler invocation. + // Generates code for all given proto files. // - // WARNING: Please do not use unless legacy semantics force the code generator - // to produce a single output file for all input files, or otherwise require - // an examination of all input files first. The canonical code generator - // design produces one output file per input .proto file, and we do not wish - // to encourage alternate designs. + // WARNING: The canonical code generator design produces one or two output + // files per input .proto file, and we do not wish to encourage alternate + // designs. // // A parameter is given as passed on the command line, as in |Generate()| // above. @@ -100,15 +93,13 @@ class LIBPROTOC_EXPORT CodeGenerator { virtual bool GenerateAll(const vector<const FileDescriptor*>& files, const string& parameter, GeneratorContext* generator_context, - string* error) const { - *error = "Unimplemented GenerateAll() method."; - return false; - } - - // Returns true if the code generator expects to receive all FileDescriptors - // at once (via |GenerateAll()|), rather than one at a time (via - // |Generate()|). This is required to implement legacy semantics. - virtual bool HasGenerateAll() const { return false; } + string* error) const; + + // This is no longer used, but this class is part of the opensource protobuf + // library, so it has to remain to keep vtables the same for the current + // version of the library. When protobufs does a api breaking change, the + // method can be removed. + virtual bool HasGenerateAll() const { return true; } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index bb781b0a..79d2dd66 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -704,6 +704,7 @@ CommandLineInterface::CommandLineInterface() : mode_(MODE_COMPILE), print_mode_(PRINT_NONE), error_format_(ERROR_FORMAT_GCC), + direct_dependencies_explicitly_set_(false), imports_in_descriptor_set_(false), source_info_in_descriptor_set_(false), disallow_services_(false), @@ -784,6 +785,24 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { "--disallow_services was used." << endl; return 1; } + + // Enforce --direct_dependencies + if (direct_dependencies_explicitly_set_) { + bool indirect_imports = false; + for (int i = 0; i < parsed_file->dependency_count(); i++) { + if (direct_dependencies_.find(parsed_file->dependency(i)->name()) == + direct_dependencies_.end()) { + indirect_imports = true; + cerr << parsed_file->name() + << ": File is imported but not declared in " + << "--direct_dependencies: " + << parsed_file->dependency(i)->name() << std::endl; + } + } + if (indirect_imports) { + return 1; + } + } } // We construct a separate GeneratorContext for each output location. Note @@ -897,6 +916,7 @@ void CommandLineInterface::Clear() { executable_name_.clear(); proto_path_.clear(); input_files_.clear(); + direct_dependencies_.clear(); output_directives_.clear(); codec_type_.clear(); descriptor_set_name_.clear(); @@ -907,6 +927,7 @@ void CommandLineInterface::Clear() { imports_in_descriptor_set_ = false; source_info_in_descriptor_set_ = false; disallow_services_ = false; + direct_dependencies_explicitly_set_ = false; } bool CommandLineInterface::MakeInputsBeProtoPathRelative( @@ -1154,6 +1175,19 @@ CommandLineInterface::InterpretArgument(const string& name, proto_path_.push_back(pair<string, string>(virtual_path, disk_path)); } + } else if (name == "--direct_dependencies") { + if (direct_dependencies_explicitly_set_) { + std::cerr << name << " may only be passed once. To specify multiple " + "direct dependencies, pass them all as a single " + "parameter separated by ':'." << std::endl; + return PARSE_ARGUMENT_FAIL; + } + + direct_dependencies_explicitly_set_ = true; + vector<string> direct = Split(value, ":", true); + GOOGLE_DCHECK(direct_dependencies_.empty()); + direct_dependencies_.insert(direct.begin(), direct.end()); + } else if (name == "-o" || name == "--descriptor_set_out") { if (!descriptor_set_name_.empty()) { std::cerr << name << " may only be passed once." << std::endl; @@ -1447,24 +1481,11 @@ bool CommandLineInterface::GenerateOutput( } parameters.append(generator_parameters_[output_directive.name]); } - if (output_directive.generator->HasGenerateAll()) { - if (!output_directive.generator->GenerateAll( - parsed_files, parameters, generator_context, &error)) { - // Generator returned an error. - std::cerr << output_directive.name << ": " - << ": " << error << std::endl; - return false; - } - } else { - for (int i = 0; i < parsed_files.size(); i++) { - if (!output_directive.generator->Generate(parsed_files[i], parameters, - generator_context, &error)) { - // Generator returned an error. - std::cerr << output_directive.name << ": " << parsed_files[i]->name() - << ": " << error << std::endl; - return false; - } - } + if (!output_directive.generator->GenerateAll( + parsed_files, parameters, generator_context, &error)) { + // Generator returned an error. + std::cerr << output_directive.name << ": " << error << std::endl; + return false; } } diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index 32084567..c38e65a3 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -352,6 +352,11 @@ class LIBPROTOC_EXPORT CommandLineInterface { vector<pair<string, string> > proto_path_; // Search path for proto files. vector<string> input_files_; // Names of the input proto files. + // Names of proto files which are allowed to be imported. Used by build + // systems to enforce depend-on-what-you-import. + set<string> direct_dependencies_; + bool direct_dependencies_explicitly_set_; + // output_directives_ lists all the files we are supposed to output and what // generator to use for each. struct OutputDirective { diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index dee438c6..56a07dbf 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -871,6 +871,92 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } +TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo { optional Bar bar = 1; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies= foo.proto"); + + ExpectErrorText( + "foo.proto: File is imported but not declared in --direct_dependencies: " + "bar.proto\n"); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "import \"bla.proto\";\n" + "message Foo { optional Bar bar = 1; optional Bla bla = 2; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + CreateTempFile("bla.proto", + "syntax = \"proto2\";\n" + "message Bla { optional int64 number = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bla.proto foo.proto"); + + ExpectErrorText( + "foo.proto: File is imported but not declared in --direct_dependencies: " + "bar.proto\n"); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "message Foo { optional Bar bar = 1; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto foo.proto"); + + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation_MultiImports) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "import \"bar.proto\";\n" + "import \"bla.proto\";\n" + "message Foo { optional Bar bar = 1; optional Bla bla = 2; }"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar { optional string text = 1; }"); + CreateTempFile("bla.proto", + "syntax = \"proto2\";\n" + "message Bla { optional int64 number = 1; }"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto:bla.proto foo.proto"); + + ExpectNoErrors(); +} + +TEST_F(CommandLineInterfaceTest, DirectDependencies_ProvidedMultipleTimes) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n"); + + Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir " + "--direct_dependencies=bar.proto --direct_dependencies=bla.proto " + "foo.proto"); + + ExpectErrorText( + "--direct_dependencies may only be passed once. To specify multiple " + "direct dependencies, pass them all as a single parameter separated by " + "':'.\n"); +} + TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { // Test that we can accept working-directory-relative input files. diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 77451ab1..deef290b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -99,7 +99,6 @@ class MockGeneratorContext : public GeneratorContext { &actual_contents, true)); EXPECT_TRUE(actual_contents == *expected_contents) << physical_filename << " needs to be regenerated. Please run " - "google/protobuf/compiler/release_compiler.sh and " "generate_descriptor_proto.sh. Then add this file " "to your CL."; } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 62b7ed4e..6ced26bc 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -260,7 +260,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { printer->Print(vars, "bool $classname$_IsValid(int value) {\n" - " switch(value) {\n"); + " switch (value) {\n"); // Multiple values may have the same number. Make sure we only cover // each number once by first constructing a set containing all valid diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index ffd81529..c3dfa817 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -83,13 +83,13 @@ void EnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$() const {\n" + "$inline$$type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_);\n" "}\n" - "$inline$ void $classname$::set_$name$($type$ value) {\n"); + "$inline$void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables, " assert($type$_IsValid(value));\n"); @@ -187,16 +187,16 @@ void EnumOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$() const {\n" + "$inline$$type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return static_cast< $type$ >($oneof_prefix$$name$_);\n" " }\n" " return static_cast< $type$ >($default$);\n" "}\n" - "$inline$ void $classname$::set_$name$($type$ value) {\n"); + "$inline$void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables, " assert($type$_IsValid(value));\n"); @@ -263,13 +263,13 @@ void RepeatedEnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$(int index) const {\n" + "$inline$$type$ $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" - "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"); + "$inline$void $classname$::set_$name$(int index, $type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables, " assert($type$_IsValid(value));\n"); @@ -278,7 +278,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $name$_.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::add_$name$($type$ value) {\n"); + "$inline$void $classname$::add_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables, " assert($type$_IsValid(value));\n"); @@ -288,12 +288,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n"); printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedField<int>&\n" + "$inline$const ::google::protobuf::RepeatedField<int>&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ ::google::protobuf::RepeatedField<int>*\n" + "$inline$::google::protobuf::RepeatedField<int>*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -311,6 +311,11 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: +GenerateUnsafeMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); +} + +void RepeatedEnumFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } @@ -475,10 +480,11 @@ void RepeatedEnumFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, "{\n" - " int data_size = 0;\n"); + " size_t data_size = 0;\n" + " unsigned int count = this->$name$_size();"); printer->Indent(); printer->Print(variables_, - "for (int i = 0; i < this->$name$_size(); i++) {\n" + "for (unsigned int i = 0; i < count; i++) {\n" " data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n" " this->$name$(i));\n" "}\n"); @@ -489,13 +495,14 @@ GenerateByteSize(io::Printer* printer) const { " total_size += $tag_size$ +\n" " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" "}\n" + "int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n" "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_$name$_cached_byte_size_ = data_size;\n" + "_$name$_cached_byte_size_ = cached_size;\n" "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "total_size += data_size;\n"); } else { printer->Print(variables_, - "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); + "total_size += ($tag_size$UL * count) + data_size;\n"); } printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index fe21c575..57ffeec5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -101,6 +101,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; + void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index c42f1627..4554c72c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -178,28 +178,30 @@ void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { switch (descriptor_->cpp_type()) { case FieldDescriptor::CPPTYPE_ENUM: - printer->Print(vars, - "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" - " &$extendee$::default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + vars, + "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" + " $extendee$::internal_default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); printer->Print( " &$type$_IsValid);\n", "type", ClassName(descriptor_->enum_type(), true)); break; case FieldDescriptor::CPPTYPE_MESSAGE: - printer->Print(vars, - "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" - " &$extendee$::default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); printer->Print( - " &$type$::default_instance());\n", - "type", ClassName(descriptor_->message_type(), true)); + vars, + "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" + " $extendee$::internal_default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print(" $type$::internal_default_instance());\n", "type", + ClassName(descriptor_->message_type(), true)); break; default: - printer->Print(vars, - "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" - " &$extendee$::default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); + printer->Print( + vars, + "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" + " $extendee$::internal_default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); break; } } diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 3b012527..fdd338a6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -136,6 +136,13 @@ class FieldGenerator { // GenerateMergeFrom method. virtual void GenerateMergingCode(io::Printer* printer) const = 0; + // The same, but the generated code may or may not check the possibility that + // the two objects being merged have the same address. To be safe, callers + // should avoid calling this unless they know the objects are different. + virtual void GenerateUnsafeMergingCode(io::Printer* printer) const { + GenerateMergingCode(printer); + } + // Generate lines of code (statements, not declarations) which swaps // this field and the corresponding field of another message, which // is stored in the generated code variable "other". This is used to diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index b3eca660..369497ce 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -89,7 +89,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) new ExtensionGenerator(file->extension(i), options)); } - SplitStringUsing(file_->package(), ".", &package_parts_); + package_parts_ = Split(file_->package(), ".", true); } FileGenerator::~FileGenerator() {} @@ -336,6 +336,20 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // Generate classes. for (int i = 0; i < file_->message_type_count(); i++) { + if (i == 0 && HasGeneratedMethods(file_, options_)) { + printer->Print( + "\n" + "namespace {\n" + "\n" + "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD" + " GOOGLE_ATTRIBUTE_NORETURN;\n" + "static void MergeFromFail(int line) {\n" + " ::google::protobuf::internal::MergeFromFail(__FILE__, line);\n" + "}\n" + "\n" + "} // namespace\n" + "\n"); + } printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); @@ -449,6 +463,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors() // and we only use AddDescriptors() to allocate default instances. + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" @@ -500,15 +515,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. printer->Print( - "namespace {\n" - "\n" - "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" - "inline void protobuf_AssignDescriptorsOnce() {\n" - " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" - " &$assigndescriptorsname$);\n" - "}\n" - "\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + "namespace {\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "void protobuf_AssignDescriptorsOnce() {\n" + " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" + " &$assigndescriptorsname$);\n" + "}\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); // protobuf_RegisterTypes(): Calls // MessageFactory::InternalRegisterGeneratedType() for each message type. @@ -548,44 +563,68 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // ----------------------------------------------------------------- - // Now generate the AddDescriptors() function. - PrintHandlingOptionalStaticInitializers( - file_, options_, printer, - // With static initializers. - // Note that we don't need any special synchronization in the following - // code - // because it is called at static init time before any threads exist. - "void $adddescriptorsname$() GOOGLE_ATTRIBUTE_COLD;\n" - "void $adddescriptorsname$() {\n" - " static bool already_here = false;\n" - " if (already_here) return;\n" - " already_here = true;\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n", - // Without. - "void $adddescriptorsname$_impl() {\n" + // Now generate the InitDefaults() function. + printer->Print( + "void $initdefaultsname$_impl() {\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" "\n", // Vars. - "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + "initdefaultsname", GlobalInitDefaultsName(file_->name())); printer->Indent(); - // Call the AddDescriptors() methods for all of our dependencies, to make + // Call the InitDefaults() methods for all of our dependencies, to make // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. string add_desc_name = QualifiedFileLevelSymbol( - dependency->package(), GlobalAddDescriptorsName(dependency->name())); + dependency->package(), GlobalInitDefaultsName(dependency->name())); // Call its AddDescriptors function. printer->Print( "$name$();\n", "name", add_desc_name); } + // Allocate and initialize default instances. This can't be done lazily + // since default instances are returned by simple accessors and are used with + // extensions. Speaking of which, we also register extensions at this time. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } + printer->Outdent(); + printer->Print( + "}\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE($initdefaultsname$_once_);\n" + "void $initdefaultsname$() {\n" + " ::google::protobuf::GoogleOnceInit(&$initdefaultsname$_once_,\n" + " &$initdefaultsname$_impl);\n" + "}\n", + "initdefaultsname", GlobalInitDefaultsName(file_->name())); + + // ----------------------------------------------------------------- + + // Now generate the AddDescriptors() function. + printer->Print( + "void $adddescriptorsname$_impl() {\n" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n" + " $initdefaultsname$();\n", + // Vars. + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "initdefaultsname", GlobalInitDefaultsName(file_->name())); + + printer->Indent(); if (HasDescriptorMethods(file_, options_)) { - // Embed the descriptor. We simply serialize the entire FileDescriptorProto + // Embed the descriptor. We simply serialize the entire + // FileDescriptorProto // and embed it as a string literal, which is parsed and built into real // descriptors at initialization time. FileDescriptorProto file_proto; @@ -655,30 +694,37 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "filename", file_->name()); } - // Allocate and initialize default instances. This can't be done lazily - // since default instances are returned by simple accessors and are used with - // extensions. Speaking of which, we also register extensions at this time. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDefaultInstanceAllocator(printer); - } - for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_[i]->GenerateRegistration(printer); - } - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + // Call the AddDescriptors() methods for all of our dependencies, to make + // sure they get added first. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dependency = file_->dependency(i); + // Print the namespace prefix for the dependency. + string add_desc_name = QualifiedFileLevelSymbol( + dependency->package(), GlobalAddDescriptorsName(dependency->name())); + // Call its AddDescriptors function. + printer->Print("$adddescriptorsname$();\n", "adddescriptorsname", + add_desc_name); } printer->Print( - "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n", - "shutdownfilename", GlobalShutdownFileName(file_->name())); + "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n", + "shutdownfilename", GlobalShutdownFileName(file_->name())); printer->Outdent(); printer->Print( - "}\n" - "\n"); + "}\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" + "void $adddescriptorsname$() {\n" + " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" + " &$adddescriptorsname$_impl);\n" + "}\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); - PrintHandlingOptionalStaticInitializers( - file_, options_, printer, + if (!StaticInitializersForced(file_, options_)) { + printer->Print("#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"); + } + printer->Print( // With static initializers. "// Force AddDescriptors() to be called at static initialization time.\n" "struct StaticDescriptorInitializer_$filename$ {\n" @@ -686,15 +732,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { " $adddescriptorsname$();\n" " }\n" "} static_descriptor_initializer_$filename$_;\n", - // Without. - "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" - "void $adddescriptorsname$() {\n" - " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" - " &$adddescriptorsname$_impl);\n" - "}\n", // Vars. "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename", FilenameIdentifier(file_->name())); + if (!StaticInitializersForced(file_, options_)) { + printer->Print("#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"); + } } void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { @@ -892,12 +935,14 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile // functions, so that we can declare them to be friends of each class. printer->Print( - "\n" - "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$$adddescriptorsname$();\n", - "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + "\n" + "// Internal implementation detail -- do not call these.\n" + "void $dllexport_decl$$adddescriptorsname$();\n" + "void $dllexport_decl$$initdefaultsname$();\n", + "initdefaultsname", GlobalInitDefaultsName(file_->name()), + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); printer->Print( // Note that we don't put dllexport_decl on these because they are only diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 2ad4d36a..6d844cc2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -415,7 +415,8 @@ string DefaultValue(const FieldDescriptor* field) { CEscape(field->default_value_string())) + "\""; case FieldDescriptor::CPPTYPE_MESSAGE: - return FieldMessageTypeName(field) + "::default_instance()"; + return "*" + FieldMessageTypeName(field) + + "::internal_default_instance()"; } // Can't actually get here; make compiler happy. (We could add a default // case above but then we wouldn't get the nice compiler warning when a @@ -444,6 +445,10 @@ string GlobalAddDescriptorsName(const string& filename) { return "protobuf_AddDesc_" + FilenameIdentifier(filename); } +string GlobalInitDefaultsName(const string& filename) { + return "protobuf_InitDefaults_" + FilenameIdentifier(filename); +} + // Return the name of the AssignDescriptors() function for a given file. string GlobalAssignDescriptorsName(const string& filename) { return "protobuf_AssignDesc_" + FilenameIdentifier(filename); @@ -500,40 +505,6 @@ bool StaticInitializersForced(const FileDescriptor* file, return false; } -void PrintHandlingOptionalStaticInitializers( - const FileDescriptor* file, const Options& options, io::Printer* printer, - const char* with_static_init, const char* without_static_init, - const char* var1, const string& val1, const char* var2, - const string& val2) { - map<string, string> vars; - if (var1) { - vars[var1] = val1; - } - if (var2) { - vars[var2] = val2; - } - PrintHandlingOptionalStaticInitializers( - vars, file, options, printer, with_static_init, without_static_init); -} - -void PrintHandlingOptionalStaticInitializers(const map<string, string>& vars, - const FileDescriptor* file, - const Options& options, - io::Printer* printer, - const char* with_static_init, - const char* without_static_init) { - if (StaticInitializersForced(file, options)) { - printer->Print(vars, with_static_init); - } else { - printer->Print(vars, (string( - "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") + - without_static_init + - "#else\n" + - with_static_init + - "#endif\n").c_str()); - } -} - static bool HasMapFields(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); ++i) { diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 018acfca..3a0c0388 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -147,6 +147,9 @@ string FilenameIdentifier(const string& filename); // Return the name of the AddDescriptors() function for a given file. string GlobalAddDescriptorsName(const string& filename); +// Return the name of the InitDefaults() function for a given file. +string GlobalInitDefaultsName(const string& filename); + // Return the name of the AssignDescriptors() function for a given file. string GlobalAssignDescriptorsName(const string& filename); @@ -223,22 +226,6 @@ inline bool HasFastArraySerialization(const FileDescriptor* file, bool StaticInitializersForced(const FileDescriptor* file, const Options& options); -// Prints 'with_static_init' if static initializers have to be used for the -// provided file. Otherwise emits both 'with_static_init' and -// 'without_static_init' using #ifdef. -void PrintHandlingOptionalStaticInitializers( - const FileDescriptor* file, const Options& options, io::Printer* printer, - const char* with_static_init, const char* without_static_init, - const char* var1 = NULL, const string& val1 = "", const char* var2 = NULL, - const string& val2 = ""); - -void PrintHandlingOptionalStaticInitializers(const map<string, string>& vars, - const FileDescriptor* file, - const Options& options, - io::Printer* printer, - const char* with_static_init, - const char* without_static_init); - inline bool IsMapEntryMessage(const Descriptor* descriptor) { return descriptor->options().map_entry(); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0588e34e..31ac9ca7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -399,7 +399,8 @@ void MapFieldGenerator::GenerateSerializeWithCachedSizes( void MapFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * this->$name$_size();\n" + "total_size += $tag_size$ *\n" + " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 1f1a0f1c..efc56ddc 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -85,14 +85,13 @@ struct FieldOrderingByNumber { // Sort the fields of the given Descriptor by number into a new[]'d array // and return it. -const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { - const FieldDescriptor** fields = - new const FieldDescriptor*[descriptor->field_count()]; +std::vector<const FieldDescriptor*> SortFieldsByNumber( + const Descriptor* descriptor) { + std::vector<const FieldDescriptor*> fields(descriptor->field_count()); for (int i = 0; i < descriptor->field_count(); i++) { fields[i] = descriptor->field(i); } - std::sort(fields, fields + descriptor->field_count(), - FieldOrderingByNumber()); + std::sort(fields.begin(), fields.end(), FieldOrderingByNumber()); return fields; } @@ -227,59 +226,150 @@ class FieldGroup { // used in a vector. }; +// Helper for the code that emits the Clear() method. +bool CanInitializeByZeroing(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case internal::WireFormatLite::CPPTYPE_ENUM: + return field->default_value_enum()->number() == 0; + case internal::WireFormatLite::CPPTYPE_INT32: + return field->default_value_int32() == 0; + case internal::WireFormatLite::CPPTYPE_INT64: + return field->default_value_int64() == 0; + case internal::WireFormatLite::CPPTYPE_UINT32: + return field->default_value_uint32() == 0; + case internal::WireFormatLite::CPPTYPE_UINT64: + return field->default_value_uint64() == 0; + case internal::WireFormatLite::CPPTYPE_FLOAT: + return field->default_value_float() == 0; + case internal::WireFormatLite::CPPTYPE_DOUBLE: + return field->default_value_double() == 0; + case internal::WireFormatLite::CPPTYPE_BOOL: + return field->default_value_bool() == false; + default: + return false; + } +} + // Reorder 'fields' so that if the fields are output into a c++ class in the new -// order, the alignment padding is minimized. We try to do this while keeping -// each field as close as possible to its original position so that we don't -// reduce cache locality much for function that access each field in order. +// order, fields of similiar family (see below) are together and within each +// family, alignment padding is minimized. +// +// We try to do this while keeping each field as close as possible to its +// declaration order (from the .proto file) so that we don't reduce cache +// locality much for function that access each field in order. This is also the +// only (weak) signal we have for author intent concerning field layout. +// +// TODO(ckennelly): Update these functions to use the optimized layout order +// for their access patterns. +// +// TODO(ckennelly): If/when we have profiles available for the compiler, use +// those rather than respect declaration order. +// +// We classify each field into a particular "family" of fields, that we perform +// the same operation on in our generated functions. +// +// REPEATED is placed first, as the C++ compiler automatically initializes +// these fields in layout order. +// +// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and +// calls ArenaStringPtr::Destroy on each. +// +// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls +// delete on each. We initialize these fields with a NULL pointer (see +// MessageFieldGenerator::GenerateConstructorCode). +// TODO(ckennelly): memset these in SharedCtor. +// +// ZERO_INITIALIZABLE is memset in Clear/SharedCtor +// +// OTHER these fields are initialized one-by-one. void OptimizePadding(vector<const FieldDescriptor*>* fields) { + // The sorted numeric order of Family determines the declaration order in the + // memory layout. + enum Family { + REPEATED = 0, + STRING = 1, + MESSAGE = 2, + ZERO_INITIALIZABLE = 3, + OTHER = 4, + kMaxFamily + }; + // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. - vector<FieldGroup> aligned_to_1, aligned_to_4, aligned_to_8; + vector<FieldGroup> aligned_to_1[kMaxFamily]; + vector<FieldGroup> aligned_to_4[kMaxFamily]; + vector<FieldGroup> aligned_to_8[kMaxFamily]; for (int i = 0; i < fields->size(); ++i) { - switch (EstimateAlignmentSize((*fields)[i])) { - case 1: aligned_to_1.push_back(FieldGroup(i, (*fields)[i])); break; - case 4: aligned_to_4.push_back(FieldGroup(i, (*fields)[i])); break; - case 8: aligned_to_8.push_back(FieldGroup(i, (*fields)[i])); break; - default: - GOOGLE_LOG(FATAL) << "Unknown alignment size."; + const FieldDescriptor* field = (*fields)[i]; + + Family f = OTHER; + if (field->is_repeated()) { + f = REPEATED; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + f = STRING; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + f = MESSAGE; + } else if (CanInitializeByZeroing(field)) { + f = ZERO_INITIALIZABLE; } - } - // Now group fields aligned to 1 byte into sets of 4, and treat those like a - // single field aligned to 4 bytes. - for (int i = 0; i < aligned_to_1.size(); i += 4) { - FieldGroup field_group; - for (int j = i; j < aligned_to_1.size() && j < i + 4; ++j) { - field_group.Append(aligned_to_1[j]); + switch (EstimateAlignmentSize(field)) { + case 1: aligned_to_1[f].push_back(FieldGroup(i, field)); break; + case 4: aligned_to_4[f].push_back(FieldGroup(i, field)); break; + case 8: aligned_to_8[f].push_back(FieldGroup(i, field)); break; + default: + GOOGLE_LOG(FATAL) << "Unknown alignment size."; } - aligned_to_4.push_back(field_group); } - // Sort by preferred location to keep fields as close to their original - // location as possible. Using stable_sort ensures that the output is - // consistent across runs. - std::stable_sort(aligned_to_4.begin(), aligned_to_4.end()); - // Now group fields aligned to 4 bytes (or the 4-field groups created above) - // into pairs, and treat those like a single field aligned to 8 bytes. - for (int i = 0; i < aligned_to_4.size(); i += 2) { - FieldGroup field_group; - for (int j = i; j < aligned_to_4.size() && j < i + 2; ++j) { - field_group.Append(aligned_to_4[j]); - } - if (i == aligned_to_4.size() - 1) { - // Move incomplete 4-byte block to the end. - field_group.SetPreferredLocation(fields->size() + 1); + // For each family, group fields to optimize padding. + for (int f = 0; f < kMaxFamily; f++) { + // Now group fields aligned to 1 byte into sets of 4, and treat those like a + // single field aligned to 4 bytes. + for (int i = 0; i < aligned_to_1[f].size(); i += 4) { + FieldGroup field_group; + for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) { + field_group.Append(aligned_to_1[f][j]); + } + aligned_to_4[f].push_back(field_group); + } + // Sort by preferred location to keep fields as close to their declaration + // order as possible. Using stable_sort ensures that the output is + // consistent across runs. + std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end()); + + // Now group fields aligned to 4 bytes (or the 4-field groups created above) + // into pairs, and treat those like a single field aligned to 8 bytes. + for (int i = 0; i < aligned_to_4[f].size(); i += 2) { + FieldGroup field_group; + for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) { + field_group.Append(aligned_to_4[f][j]); + } + if (i == aligned_to_4[f].size() - 1) { + if (f == OTHER) { + // Move incomplete 4-byte block to the beginning. This is done to + // pair with the (possible) leftover blocks from the + // ZERO_INITIALIZABLE family. + field_group.SetPreferredLocation(-1); + } else { + // Move incomplete 4-byte block to the end. + field_group.SetPreferredLocation(fields->size() + 1); + } + } + aligned_to_8[f].push_back(field_group); } - aligned_to_8.push_back(field_group); + // Sort by preferred location. + std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end()); } - // Sort by preferred location. - std::stable_sort(aligned_to_8.begin(), aligned_to_8.end()); // Now pull out all the FieldDescriptors in order. fields->clear(); - for (int i = 0; i < aligned_to_8.size(); ++i) { - fields->insert(fields->end(), - aligned_to_8[i].fields().begin(), - aligned_to_8[i].fields().end()); + for (int f = 0; f < kMaxFamily; ++f) { + for (int i = 0; i < aligned_to_8[f].size(); ++i) { + fields->insert(fields->end(), + aligned_to_8[f][i].fields().begin(), + aligned_to_8[f][i].fields().end()); + } } } @@ -337,6 +427,20 @@ bool HasHasMethod(const FieldDescriptor* field) { return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE; } +size_t HasBitsSize(const Descriptor* descriptor) { + // TODO(jieluo) - Optimize _has_bits_ for repeated and oneof fields. + size_t sizeof_has_bits = (descriptor->field_count() + 31) / 32 * 4; + if (descriptor->field_count() == 0) { + // Zero-size arrays aren't technically allowed, and MSVC in particular + // doesn't like them. We still need to declare these arrays to make + // other code compile. Since this is an uncommon case, we'll just declare + // them with size 1 and waste some space. Oh well. + sizeof_has_bits = 4; + } + + return sizeof_has_bits; +} + // Collects map entry message type information. void CollectMapInfo(const Descriptor* descriptor, map<string, string>* variables) { @@ -389,6 +493,15 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, ExtensionGenerator>[descriptor->extension_count()]), use_dependent_base_(false) { + // Compute optimized field order to be used for layout and initialization + // purposes. + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + optimized_order_.push_back(descriptor_->field(i)); + } + } + OptimizePadding(&optimized_order_); + for (int i = 0; i < descriptor->nested_type_count(); i++) { nested_generators_[i].reset( new MessageGenerator(descriptor->nested_type(i), options)); @@ -644,11 +757,12 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field, " return !$name$_.IsCleared();\n" "}\n"); } else { - printer->Print(vars, - "$inline$" - "bool $classname$::has_$name$() const {\n" - " return !_is_default_instance_ && $name$_ != NULL;\n" - "}\n"); + printer->Print( + vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return this != internal_default_instance() && $name$_ != NULL;\n" + "}\n"); } } } @@ -805,31 +919,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { } } -// Helper for the code that emits the Clear() method. -static bool CanClearByZeroing(const FieldDescriptor* field) { - if (field->is_repeated() || field->is_extension()) return false; - switch (field->cpp_type()) { - case internal::WireFormatLite::CPPTYPE_ENUM: - return field->default_value_enum()->number() == 0; - case internal::WireFormatLite::CPPTYPE_INT32: - return field->default_value_int32() == 0; - case internal::WireFormatLite::CPPTYPE_INT64: - return field->default_value_int64() == 0; - case internal::WireFormatLite::CPPTYPE_UINT32: - return field->default_value_uint32() == 0; - case internal::WireFormatLite::CPPTYPE_UINT64: - return field->default_value_uint64() == 0; - case internal::WireFormatLite::CPPTYPE_FLOAT: - return field->default_value_float() == 0; - case internal::WireFormatLite::CPPTYPE_DOUBLE: - return field->default_value_double() == 0; - case internal::WireFormatLite::CPPTYPE_BOOL: - return field->default_value_bool() == false; - default: - return false; - } -} - void MessageGenerator:: GenerateDependentBaseClassDefinition(io::Printer* printer) { if (!use_dependent_base_) { @@ -1009,19 +1098,11 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (!StaticInitializersForced(descriptor_->file(), options_)) { - printer->Print(vars, - "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" - "// Returns the internal default instance pointer. This function can\n" - "// return NULL thus should not be used by the user. This is intended\n" - "// for Protobuf internal code. Please use default_instance() declared\n" - "// above instead.\n" - "static inline const $classname$* internal_default_instance() {\n" - " return default_instance_;\n" - "}\n" - "#endif\n" + // TODO(gerbens) make this private, while still granting other protos access. + printer->Print( + vars, + "static const $classname$* internal_default_instance();\n" "\n"); - } if (SupportsArenas(descriptor_)) { @@ -1068,7 +1149,7 @@ GenerateClassDefinition(io::Printer* printer) { "void Clear();\n" "bool IsInitialized() const;\n" "\n" - "int ByteSize() const;\n" + "size_t ByteSizeLong() const;\n" "bool MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input);\n" "void SerializeWithCachedSizes(\n" @@ -1131,7 +1212,8 @@ GenerateClassDefinition(io::Printer* printer) { "void SharedCtor();\n" "void SharedDtor();\n" "void SetCachedSize(int size) const;\n" - "void InternalSwap($classname$* other);\n", + "void InternalSwap($classname$* other);\n" + "void UnsafeMergeFrom(const $classname$& from);\n", "classname", classname_); if (SupportsArenas(descriptor_)) { printer->Print( @@ -1260,8 +1342,8 @@ GenerateClassDefinition(io::Printer* printer) { !descriptor_->options().message_set_wire_format() && num_required_fields_ > 1) { printer->Print( - "// helper for ByteSize()\n" - "int RequiredFieldsByteSizeFallback() const;\n\n"); + "// helper for ByteSizeLong()\n" + "size_t RequiredFieldsByteSizeFallback() const;\n\n"); } // Prepare decls for _cached_size_ and _has_bits_. Their position in the @@ -1271,18 +1353,10 @@ GenerateClassDefinition(io::Printer* printer) { // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it. const string cached_size_decl = "mutable int _cached_size_;\n"; - // TODO(jieluo) - Optimize _has_bits_ for repeated and oneof fields. - size_t sizeof_has_bits = (descriptor_->field_count() + 31) / 32 * 4; - if (descriptor_->field_count() == 0) { - // Zero-size arrays aren't technically allowed, and MSVC in particular - // doesn't like them. We still need to declare these arrays to make - // other code compile. Since this is an uncommon case, we'll just declare - // them with size 1 and waste some space. Oh well. - sizeof_has_bits = 4; - } + const size_t sizeof_has_bits = HasBitsSize(descriptor_); const string has_bits_decl = sizeof_has_bits == 0 ? "" : - "::google::protobuf::uint32 _has_bits_[" + SimpleItoa(sizeof_has_bits / 4) + "];\n"; - + "::google::protobuf::internal::HasBits<" + SimpleItoa(sizeof_has_bits / 4) + + "> _has_bits_;\n"; // To minimize padding, data members are divided into three sections: // (1) members assumed to align to 8 bytes @@ -1326,45 +1400,27 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(cached_size_decl.c_str()); need_to_emit_cached_size = false; } - } else { - // Without field presence, we need another way to disambiguate the default - // instance, because the default instance's submessage fields (if any) store - // pointers to the default instances of the submessages even when they - // aren't present. Alternatives to this approach might be to (i) use a - // tagged pointer on all message fields, setting a tag bit for "not really - // present, just default instance"; or (ii) comparing |this| against the - // return value from GeneratedMessageFactory::GetPrototype() in all - // has_$field$() calls. However, both of these options are much more - // expensive (in code size and CPU overhead) than just checking a field in - // the message. Long-term, the best solution would be to rearchitect the - // default instance design not to store pointers to submessage default - // instances, and have reflection get those some other way; but that change - // would have too much impact on proto2. - printer->Print( - "bool _is_default_instance_;\n"); } // Field members: // List fields which doesn't belong to any oneof - vector<const FieldDescriptor*> fields; hash_map<string, int> fieldname_to_chunk; for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { const FieldDescriptor* field = descriptor_->field(i); - fields.push_back(field); fieldname_to_chunk[FieldName(field)] = i / 8; } } - OptimizePadding(&fields); + // Emit some private and static members runs_of_fields_ = vector< vector<string> >(1); - for (int i = 0; i < fields.size(); ++i) { - const FieldDescriptor* field = fields[i]; + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; const FieldGenerator& generator = field_generators_.get(field); generator.GenerateStaticMembers(printer); generator.GeneratePrivateMembers(printer); - if (CanClearByZeroing(field)) { + if (CanInitializeByZeroing(field)) { const string& fieldname = FieldName(field); if (!runs_of_fields_.back().empty() && (fieldname_to_chunk[runs_of_fields_.back().back()] != @@ -1424,15 +1480,15 @@ GenerateClassDefinition(io::Printer* printer) { // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as // friends so that they can access private static variables like // default_instance_ and reflection_. - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - "friend void $dllexport_decl$ $adddescriptorsname$();\n", - // Without. - "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n", - // Vars. - "dllexport_decl", options_.dllexport_decl, "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + printer->Print("friend void $dllexport_decl$ $initdefaultsname$_impl();\n", + // Vars. + "dllexport_decl", options_.dllexport_decl, "initdefaultsname", + GlobalInitDefaultsName(descriptor_->file()->name())); + printer->Print("friend void $dllexport_decl$ $adddescriptorsname$_impl();\n", + // Vars. + "dllexport_decl", options_.dllexport_decl, + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); printer->Print( "friend void $assigndescriptorsname$();\n" @@ -1443,12 +1499,22 @@ GenerateClassDefinition(io::Printer* printer) { "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name())); printer->Print( - "void InitAsDefaultInstance();\n" - "static $classname$* default_instance_;\n", - "classname", classname_); + "void InitAsDefaultInstance();\n", + "classname", classname_); printer->Outdent(); - printer->Print(vars, "};"); + printer->Print("};\n"); + + // This should ideally be put into the class scope, but Visual Studio just + // refuses to compile it and complains about "use of undefined XXX": + // https://ci.appveyor.com/project/protobuf/protobuf/build/1.0.2673/job/nrdf4tb9dau0sck5 + // A program as simple as "struct X { enum { value = sizeof(X) }; };" will + // trigger the same error. + printer->Print( + "extern ::google::protobuf::internal::ExplicitlyConstructed<$classname$> " + "$classname$_default_instance_;\n", + "classname", classname_); + GOOGLE_DCHECK(!need_to_emit_cached_size); } @@ -1499,6 +1565,12 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) { "_oneof_case_[$oneof_index$]);\n" "}\n"); } + + printer->Print( + "inline const $classname$* $classname$::internal_default_instance() {\n" + " return &$classname$_default_instance_.get();\n" + "}\n", + "classname", classname_); } void MessageGenerator:: @@ -1578,18 +1650,18 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { "::NewGeneratedMessageReflection"; // Construct the reflection object. printer->Print(vars, - "$classname$_reflection_ =\n" - " $fn$(\n" - " $classname$_descriptor_,\n" - " $classname$::default_instance_,\n" - " $classname$_offsets_,\n"); + "$classname$_reflection_ =\n" + " $fn$(\n" + " $classname$_descriptor_,\n" + " $classname$::internal_default_instance(),\n" + " $classname$_offsets_,\n"); if (!HasFieldPresence(descriptor_->file())) { // If we don't have field presence, then _has_bits_ does not exist. printer->Print(vars, " -1,\n"); } else { printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n"); + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_),\n"); } // Unknown field offset: either points to the unknown field set if embedded @@ -1637,22 +1709,12 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { // not (because e.g. we don't have an unknown field set). if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _internal_metadata_),\n"); - } else { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _arena_),\n"); - } - - // is_default_instance_ offset. - if (HasFieldPresence(descriptor_->file())) { - printer->Print(vars, - " -1);\n"); + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _internal_metadata_));\n"); } else { printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _is_default_instance_));\n"); + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _arena_));\n"); } // Handle nested types. @@ -1670,11 +1732,11 @@ GenerateTypeRegistrations(io::Printer* printer) { // Register this message type with the message factory. if (!IsMapEntryMessage(descriptor_)) { printer->Print( - "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" - " $classname$_descriptor_, &$classname$::default_instance());\n", - "classname", classname_); - } - else { + "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" + " $classname$_descriptor_, " + "$classname$::internal_default_instance());\n", + "classname", classname_); + } else { map<string, string> vars; CollectMapInfo(descriptor_, &vars); vars["classname"] = classname_; @@ -1708,6 +1770,12 @@ GenerateTypeRegistrations(io::Printer* printer) { void MessageGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) { + // Force initialization of primitive values we depend on. + printer->Print( + StrCat( + uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "") + .c_str()); + // Construct the default instances of all fields, as they will be used // when creating the default instance of the entire message. for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1720,9 +1788,8 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { // Construct the default instance. We can't call InitAsDefaultInstance() yet // because we need to make sure all default instances that this one might // depend on are constructed first. - printer->Print( - "$classname$::default_instance_ = new $classname$();\n", - "classname", classname_); + printer->Print("$classname$_default_instance_.DefaultConstruct();\n", + "classname", classname_); if ((descriptor_->oneof_decl_count() > 0) && HasDescriptorMethods(descriptor_->file(), options_)) { @@ -1741,8 +1808,9 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { void MessageGenerator:: GenerateDefaultInstanceInitializer(io::Printer* printer) { printer->Print( - "$classname$::default_instance_->InitAsDefaultInstance();\n", - "classname", classname_); + "$classname$_default_instance_.get_mutable()->InitAsDefaultInstance();" + "\n", + "classname", classname_); // Register extensions. for (int i = 0; i < descriptor_->extension_count(); i++) { @@ -1762,9 +1830,8 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { void MessageGenerator:: GenerateShutdownCode(io::Printer* printer) { printer->Print( - "delete $classname$::default_instance_;\n", - "classname", classname_); - + "$classname$_default_instance_.Shutdown();\n", + "classname", classname_); if (HasDescriptorMethods(descriptor_->file(), options_)) { if (descriptor_->oneof_decl_count() > 0) { printer->Print( @@ -1894,6 +1961,12 @@ GenerateClassMethods(io::Printer* printer) { GenerateIsInitialized(printer); printer->Print("\n"); + } else { + printer->Print( + "void $classname$::UnsafeMergeFrom(const $classname$& from) {\n" + " MergeFrom(from);\n" + "}\n", + "classname", classname_); } GenerateSwap(printer); @@ -1966,15 +2039,15 @@ GenerateSharedConstructorCode(io::Printer* printer) { "classname", classname_); printer->Indent(); - if (!HasFieldPresence(descriptor_->file())) { - printer->Print( - " _is_default_instance_ = false;\n"); + 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(descriptor_) % 8) != 0) { + printer->Print("_cached_size_ = 0;\n"); + need_to_clear_cached_size = false; } - printer->Print(StrCat( - uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", - "_cached_size_ = 0;\n").c_str()); - if (PreserveUnknownFields(descriptor_) && !UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( @@ -1982,16 +2055,52 @@ GenerateSharedConstructorCode(io::Printer* printer) { " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); } - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateConstructorCode(printer); + const FieldDescriptor* last_start = NULL; + // RunMap maps from fields that start each run to the number of fields in that + // run. This is optimized for the common case that there are very few runs in + // a message and that most of the eligible fields appear together. + typedef hash_map<const FieldDescriptor*, size_t> RunMap; + RunMap runs; + + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; + // TODO(ckennelly): Scalar messages (raw pointers) can be initialized by + // zero as well. + if (CanInitializeByZeroing(field)) { + if (last_start == NULL) { + last_start = field; + } + + runs[last_start]++; + } else { + last_start = NULL; } } - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; + RunMap::const_iterator it = runs.find(field); + + // We only apply the memset technique to runs of more than one field, as + // assignment is better than memset for generated code clarity. + if (it != runs.end() && it->second > 1) { + // Use a memset, then skip run_length fields. + const size_t run_length = it->second; + const string first_field_name = FieldName(field); + const string last_field_name = + FieldName(optimized_order_[i + run_length - 1]); + + printer->Print( + "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n", + "first", first_field_name, + "last", last_field_name); + + i += run_length - 1; + // ++i at the top of the loop. + } else { + field_generators_.get(field).GenerateConstructorCode(printer); + } } for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { @@ -2000,6 +2109,10 @@ 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"); } @@ -2013,7 +2126,8 @@ GenerateSharedDestructorCode(io::Printer* printer) { if (SupportsArenas(descriptor_)) { // Do nothing when the message is allocated in an arena. printer->Print( - "if (GetArenaNoVirtual() != NULL) {\n" + "::google::protobuf::Arena* arena = GetArenaNoVirtual();\n" + "if (arena != NULL) {\n" " return;\n" "}\n" "\n"); @@ -2026,7 +2140,7 @@ GenerateSharedDestructorCode(io::Printer* printer) { printer->Print( "_unknown_fields_.Destroy(\n" " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" - " GetArenaNoVirtual());\n"); + " arena);\n"); } else { printer->Print( "_unknown_fields_.DestroyNoArena(\n" @@ -2035,11 +2149,10 @@ GenerateSharedDestructorCode(io::Printer* printer) { } // Write the destructors for each field except oneof members. - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateDestructorCode(printer); - } + // optimized_order_ does not contain oneof fields. + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + field_generators_.get(field).GenerateDestructorCode(printer); } // Generate code to destruct oneofs. Clearing should do the work. @@ -2051,17 +2164,11 @@ GenerateSharedDestructorCode(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - "if (this != default_instance_) {\n", - // Without. - "if (this != &default_instance()) {\n"); - // We need to delete all embedded messages. // TODO(kenton): If we make unset messages point at default instances // instead of NULL, then it would make sense to move this code into // MessageFieldGenerator::GenerateDestructorCode(). + bool need_delete_message_field = false; for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); @@ -2069,16 +2176,25 @@ GenerateSharedDestructorCode(io::Printer* printer) { field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // Skip oneof members if (!field->containing_oneof()) { - printer->Print( - " delete $name$_;\n", - "name", FieldName(field)); + if (!need_delete_message_field) { + need_delete_message_field = true; + printer->Print( + "if (this != &$classname$_default_instance_.get()) {\n", + "classname", classname_); + printer->Indent(); + } + printer->Print("delete $name$_;\n", "name", FieldName(field)); } } } + if (need_delete_message_field) { + printer->Outdent(); + printer->Print( + "}\n"); + } printer->Outdent(); printer->Print( - " }\n" "}\n" "\n"); } @@ -2151,16 +2267,18 @@ GenerateStructors(io::Printer* printer) { } // Initialize member variables with arena constructor. - for (int i = 0; i < descriptor_->field_count(); i++) { - bool has_arena_constructor = descriptor_->field(i)->is_repeated(); + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + + bool has_arena_constructor = field->is_repeated(); if (has_arena_constructor) { initializer_with_arena += string(",\n ") + - FieldName(descriptor_->field(i)) + string("_(arena)"); + FieldName(field) + string("_(arena)"); } } if (IsAnyMessage(descriptor_)) { - initializer_with_arena += ",\n _any_metadata_(&type_url, &value_)"; + initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)"; } string initializer_null; @@ -2173,27 +2291,31 @@ GenerateStructors(io::Printer* printer) { printer->Print( "$classname$::$classname$()\n" " : $superclass$()$initializer$ {\n" + " if (this != internal_default_instance()) $initdefaultsname$();\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name(), - "initializer", initializer_null); + "classname", classname_, "superclass", superclass, "full_name", + descriptor_->full_name(), "initializer", initializer_null, + "initdefaultsname", GlobalInitDefaultsName(descriptor_->file()->name())); if (SupportsArenas(descriptor_)) { printer->Print( - "\n" "$classname$::$classname$(::google::protobuf::Arena* arena)\n" " : $initializer$ {\n" + // When arenas are used it's safe to assume we have finished + // static init time (protos with arenas are unsafe during static init) + "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" + " $initdefaultsname$();\n" + "#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" "}\n", - "initializer", initializer_with_arena, - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name()); + "initializer", initializer_with_arena, "classname", classname_, + "superclass", superclass, "full_name", descriptor_->full_name(), + "initdefaultsname", + GlobalInitDefaultsName(descriptor_->file()->name())); } printer->Print( @@ -2201,11 +2323,6 @@ GenerateStructors(io::Printer* printer) { "void $classname$::InitAsDefaultInstance() {\n", "classname", classname_); - if (!HasFieldPresence(descriptor_->file())) { - printer->Print( - " _is_default_instance_ = true;\n"); - } - // The default instance needs all of its embedded message pointers // cross-linked to other default instances. We can't do this initialization // in the constructor because some other default instances may not have been @@ -2224,11 +2341,7 @@ GenerateStructors(io::Printer* printer) { name = classname_ + "_default_oneof_instance_->"; } name += FieldName(field); - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", - // Without. + printer->Print( " $name$_ = const_cast< $type$*>(\n" " $type$::internal_default_instance());\n", // Vars. @@ -2262,7 +2375,7 @@ GenerateStructors(io::Printer* printer) { printer->Print(" {\n"); printer->Print( " SharedCtor();\n" - " MergeFrom(from);\n" + " UnsafeMergeFrom(from);\n" " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" "}\n" "\n", @@ -2304,37 +2417,29 @@ GenerateStructors(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( - "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" - " protobuf_AssignDescriptorsOnce();\n" - " return $classname$_descriptor_;\n" - "}\n" - "\n", - "classname", classname_, - "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return $classname$_descriptor_;\n" + "}\n" + "\n", + "classname", classname_, "initdefaultsname", + GlobalInitDefaultsName(descriptor_->file()->name())); } printer->Print( - "const $classname$& $classname$::default_instance() {\n", - "classname", classname_); - - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - " if (default_instance_ == NULL) $adddescriptorsname$();\n", - // Without. - " $adddescriptorsname$();\n", - // Vars. - "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + "const $classname$& $classname$::default_instance() {\n" + " $initdefaultsname$();\n" + " return *internal_default_instance();\n" + "}\n", + "classname", classname_, "initdefaultsname", + GlobalInitDefaultsName(descriptor_->file()->name())); printer->Print( - " return *default_instance_;\n" - "}\n" - "\n" - "$classname$* $classname$::default_instance_ = NULL;\n" - "\n", - "classname", classname_); + "\n" + "::google::protobuf::internal::ExplicitlyConstructed<$classname$> " + "$classname$_default_instance_;\n" + "\n", + "classname", classname_); if (SupportsArenas(descriptor_)) { printer->Print( @@ -2463,7 +2568,7 @@ GenerateClear(io::Printer* printer) { int count = popcnt(mask); GOOGLE_DCHECK_GE(count, 1); if (count == 1 || - (count <= 4 && count == memset_field_count_for_chunk[i / 8])) { + count == memset_field_count_for_chunk[i / 8]) { // No "if" here because the chunk is trivial. } else { if (HasFieldPresence(descriptor_->file())) { @@ -2540,8 +2645,7 @@ GenerateClear(io::Printer* printer) { if (HasFieldPresence(descriptor_->file())) { // Step 5: Everything else. - printer->Print( - "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + printer->Print("_has_bits_.Clear();\n"); } if (PreserveUnknownFields(descriptor_)) { @@ -2584,7 +2688,7 @@ GenerateOneofClear(io::Printer* printer) { "$full_name$)\n"); printer->Indent(); printer->Print(oneof_vars, - "switch($oneofname$_case()) {\n"); + "switch ($oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -2639,7 +2743,7 @@ GenerateSwap(io::Printer* printer) { " InternalSwap(other);\n" " } else {\n" " $classname$ temp;\n" - " temp.MergeFrom(*this);\n" + " temp.UnsafeMergeFrom(*this);\n" " CopyFrom(*other);\n" " other->CopyFrom(temp);\n" " }\n" @@ -2715,9 +2819,7 @@ GenerateMergeFrom(io::Printer* printer) { "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" "// @@protoc_insertion_point(generalized_merge_from_start:" "$full_name$)\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) {\n" - " ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);\n" - " }\n", + " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); @@ -2726,7 +2828,7 @@ GenerateMergeFrom(io::Printer* printer) { // system, as the GOOGLE_CHECK above ensured that we have the same descriptor // for each message. printer->Print( - "const $classname$* source = \n" + "const $classname$* source =\n" " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n" " &from);\n" "if (source == NULL) {\n" @@ -2736,7 +2838,7 @@ GenerateMergeFrom(io::Printer* printer) { "} else {\n" "// @@protoc_insertion_point(generalized_merge_from_cast_success:" "$full_name$)\n" - " MergeFrom(*source);\n" + " UnsafeMergeFrom(*source);\n" "}\n", "classname", classname_, "full_name", descriptor_->full_name()); @@ -2758,9 +2860,15 @@ GenerateMergeFrom(io::Printer* printer) { "void $classname$::MergeFrom(const $classname$& from) {\n" "// @@protoc_insertion_point(class_specific_merge_from_start:" "$full_name$)\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) {\n" - " ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);\n" - " }\n", + " if (GOOGLE_PREDICT_TRUE(&from != this)) {\n" + " UnsafeMergeFrom(from);\n" + " } else {\n" + " MergeFromFail(__LINE__);\n" + " }\n" + "}\n" + "\n" + "void $classname$::UnsafeMergeFrom(const $classname$& from) {\n" + " GOOGLE_DCHECK(&from != this);\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); @@ -2770,7 +2878,7 @@ GenerateMergeFrom(io::Printer* printer) { const FieldDescriptor* field = descriptor_->field(i); if (field->is_repeated()) { - field_generators_.get(field).GenerateMergingCode(printer); + field_generators_.get(field).GenerateUnsafeMergingCode(printer); } } @@ -2865,7 +2973,8 @@ GenerateMergeFrom(io::Printer* printer) { if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (from._internal_metadata_.have_unknown_fields()) {\n" - " mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n" + " ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(\n" + " from.unknown_fields(), &_internal_metadata_);\n" "}\n"); } else { printer->Print( @@ -2911,7 +3020,7 @@ GenerateCopyFrom(io::Printer* printer) { printer->Print( "if (&from == this) return;\n" "Clear();\n" - "MergeFrom(from);\n"); + "UnsafeMergeFrom(from);\n"); printer->Outdent(); printer->Print("}\n"); @@ -2926,13 +3035,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) { " ::google::protobuf::io::CodedInputStream* input) {\n", "classname", classname_); - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - " return _extensions_.ParseMessageSet(input, default_instance_,\n" - " mutable_unknown_fields());\n", - // Without. - " return _extensions_.ParseMessageSet(input, &default_instance(),\n" + printer->Print( + " return _extensions_.ParseMessageSet(input, " + "internal_default_instance(),\n" " mutable_unknown_fields());\n", // Vars. "classname", classname_); @@ -2971,8 +3076,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("for (;;) {\n"); printer->Indent(); - google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields( - SortFieldsByNumber(descriptor_)); + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); uint32 maxtag = descriptor_->field_count() == 0 ? 0 : WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]); const int kCutoff0 = 127; // fits in 1-byte varint @@ -3000,7 +3105,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // Find repeated messages and groups now, to simplify what follows. hash_set<int> fields_with_parse_loop; - for (int i = 0; i < descriptor_->field_count(); i++) { + for (int i = 0; i < ordered_fields.size(); i++) { const FieldDescriptor* field = ordered_fields[i]; if (field->is_repeated() && (field->type() == FieldDescriptor::TYPE_MESSAGE || @@ -3012,7 +3117,13 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // need_label is true if we generated "goto parse_$name$" while handling the // previous field. bool need_label = false; - for (int i = 0; i < descriptor_->field_count(); i++) { + // Pay attention to whether we are in a run of fields from the same oneof. + // Motivation: it would be unusual to parse multiple values for a single + // oneof, since only the last would be used. + const FieldDescriptor* last_of_current_oneof = NULL; + // The following is valid iff last_of_current_oneof is non-NULL. + int index_of_last_of_current_oneof = -1; + for (int i = 0; i < ordered_fields.size(); i++) { const FieldDescriptor* field = ordered_fields[i]; const bool loops = fields_with_parse_loop.count(i) > 0; const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0; @@ -3111,21 +3222,53 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "input->UnsafeDecrementRecursionDepth();\n"); } - // If there are more fields, expect the next one. + // If there are more fields, expect the next one, unless we just parsed + // a oneof and the next field would be from the same oneof. (There's no + // reason to expect something that makes what we just read irrelevant, + // so guess something after the current string of fields from this oneof.) need_label = false; if (!emitted_goto_next_tag) { - if (i + 1 == descriptor_->field_count()) { + // delta is the distance in ordered_fields[] from the current field to + // the field we'll guess is next. + int delta = last_of_current_oneof == NULL + ? 1 + : std::max(index_of_last_of_current_oneof - i, 1); + if (i == index_of_last_of_current_oneof) { + printer->Outdent(); + printer->Print( + " after_$last$:\n", + "last", FieldName(last_of_current_oneof)); + printer->Indent(); + last_of_current_oneof = NULL; + } else if (last_of_current_oneof == NULL) { + delta = 1; + // Check for the unlikely case that delta > 1 is better. + if (field->containing_oneof() != NULL) { + while (i + delta < ordered_fields.size() && + ordered_fields[i + delta]->containing_oneof() == + field->containing_oneof()) { + index_of_last_of_current_oneof = i + delta; + last_of_current_oneof = ordered_fields[i + delta]; + ++delta; + } + } + } + if (delta > 1) { + printer->Print( + "goto after_$last$;\n", + "last", FieldName(last_of_current_oneof)); + } else if (i + delta == descriptor_->field_count()) { // Expect EOF. // TODO(kenton): Expect group end-tag? printer->Print( "if (input->ExpectAtEnd()) goto success;\n"); } else { - const FieldDescriptor* next_field = ordered_fields[i + 1]; + const FieldDescriptor* next_field = ordered_fields[i + delta]; printer->Print( "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), "next_name", next_field->name()); - need_label = true; + need_label = delta == 1; } } @@ -3179,31 +3322,21 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print(") {\n"); if (PreserveUnknownFields(descriptor_)) { if (UseUnknownFieldSet(descriptor_->file(), options_)) { - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " mutable_unknown_fields()));\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + printer->Print( + " DO_(_extensions_.ParseField(tag, input, " + "internal_default_instance(),\n" " mutable_unknown_fields()));\n"); } else { - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " &unknown_fields_stream));\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + printer->Print( + " DO_(_extensions_.ParseField(tag, input, " + "internal_default_instance(),\n" " &unknown_fields_stream));\n"); } } else { - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), options_, printer, + printer->Print( // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); + " DO_(_extensions_.ParseField(tag, input, " + "internal_default_instance());\n"); } printer->Print( " continue;\n" @@ -3248,6 +3381,43 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "}\n", "full_name", descriptor_->full_name()); } +void MessageGenerator::GenerateSerializeOneofFields( + io::Printer* printer, const vector<const FieldDescriptor*>& fields, + bool to_array) { + GOOGLE_CHECK(!fields.empty()); + if (fields.size() == 1) { + GenerateSerializeOneField(printer, fields[0], to_array); + return; + } + // We have multiple mutually exclusive choices. Emit a switch statement. + const OneofDescriptor* oneof = fields[0]->containing_oneof(); + printer->Print( + "switch ($oneofname$_case()) {\n", + "oneofname", oneof->name()); + printer->Indent(); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + printer->Print( + "case k$field_name$:\n", + "field_name", UnderscoresToCamelCase(field->name(), true)); + printer->Indent(); + if (to_array) { + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( + printer); + } else { + field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + } + printer->Print( + "break;\n"); + printer->Outdent(); + } + printer->Outdent(); + // Doing nothing is an option. + printer->Print( + " default: ;\n" + "}\n"); +} + void MessageGenerator::GenerateSerializeOneField( io::Printer* printer, const FieldDescriptor* field, bool to_array) { PrintFieldComment(printer, field); @@ -3382,10 +3552,61 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { void MessageGenerator:: GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { - google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields( - SortFieldsByNumber(descriptor_)); + // If there are multiple fields in a row from the same oneof then we + // coalesce them and emit a switch statement. This is more efficient + // because it lets the C++ compiler know this is a "at most one can happen" + // situation. If we emitted "if (has_x()) ...; if (has_y()) ..." the C++ + // compiler's emitted code might check has_y() even when has_x() is true. + class LazySerializerEmitter { + public: + LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer, + bool to_array) + : mg_(mg), + printer_(printer), + to_array_(to_array), + eager_(!HasFieldPresence(mg->descriptor_->file())) {} + + ~LazySerializerEmitter() { Flush(); } + + // If conditions allow, try to accumulate a run of fields from the same + // oneof, and handle them at the next Flush(). + void Emit(const FieldDescriptor* field) { + if (eager_ || MustFlush(field)) { + Flush(); + } + if (field->containing_oneof() == NULL) { + mg_->GenerateSerializeOneField(printer_, field, to_array_); + } else { + v_.push_back(field); + } + } + + void Flush() { + if (!v_.empty()) { + mg_->GenerateSerializeOneofFields(printer_, v_, to_array_); + v_.clear(); + } + } - vector<const Descriptor::ExtensionRange*> sorted_extensions; + private: + // If we have multiple fields in v_ then they all must be from the same + // oneof. Would adding field to v_ break that invariant? + bool MustFlush(const FieldDescriptor* field) { + return !v_.empty() && + v_[0]->containing_oneof() != field->containing_oneof(); + } + + MessageGenerator* mg_; + io::Printer* printer_; + const bool to_array_; + const bool eager_; + vector<const FieldDescriptor*> v_; + }; + + std::vector<const FieldDescriptor*> ordered_fields = + SortFieldsByNumber(descriptor_); + + std::vector<const Descriptor::ExtensionRange*> sorted_extensions; for (int i = 0; i < descriptor_->extension_range_count(); ++i) { sorted_extensions.push_back(descriptor_->extension_range(i)); } @@ -3393,22 +3614,26 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { ExtensionRangeSorter()); // Merge the fields and the extension ranges, both sorted by field number. - int i, j; - for (i = 0, j = 0; - i < descriptor_->field_count() || j < sorted_extensions.size(); - ) { - if (i == descriptor_->field_count()) { - GenerateSerializeOneExtensionRange(printer, - sorted_extensions[j++], - to_array); - } else if (j == sorted_extensions.size()) { - GenerateSerializeOneField(printer, ordered_fields[i++], to_array); - } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) { - GenerateSerializeOneField(printer, ordered_fields[i++], to_array); - } else { - GenerateSerializeOneExtensionRange(printer, - sorted_extensions[j++], - to_array); + { + LazySerializerEmitter e(this, printer, to_array); + int i, j; + for (i = 0, j = 0; + i < ordered_fields.size() || j < sorted_extensions.size();) { + if (i == descriptor_->field_count()) { + e.Flush(); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); + } else if (j == sorted_extensions.size()) { + e.Emit(ordered_fields[i++]); + } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) { + e.Emit(ordered_fields[i++]); + } else { + e.Flush(); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); + } } } @@ -3480,9 +3705,9 @@ GenerateByteSize(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. printer->Print( - "int $classname$::ByteSize() const {\n" + "size_t $classname$::ByteSizeLong() const {\n" "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " int total_size = _extensions_.MessageSetByteSize();\n", + " size_t total_size = _extensions_.MessageSetByteSize();\n", "classname", classname_, "full_name", descriptor_->full_name()); GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( @@ -3491,8 +3716,9 @@ GenerateByteSize(io::Printer* printer) { " ComputeUnknownMessageSetItemsSize(unknown_fields());\n" "}\n"); printer->Print( + " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - " _cached_size_ = total_size;\n" + " _cached_size_ = cached_size;\n" " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" " return total_size;\n" "}\n"); @@ -3503,12 +3729,12 @@ GenerateByteSize(io::Printer* printer) { // Emit a function (rarely used, we hope) that handles the required fields // by checking for each one individually. printer->Print( - "int $classname$::RequiredFieldsByteSizeFallback() const {\n" + "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" "$full_name$)\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); - printer->Print("int total_size = 0;\n"); + printer->Print("size_t total_size = 0;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->is_required()) { @@ -3529,12 +3755,12 @@ GenerateByteSize(io::Printer* printer) { } printer->Print( - "int $classname$::ByteSize() const {\n" + "size_t $classname$::ByteSizeLong() const {\n" "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( - "int total_size = 0;\n" + "size_t total_size = 0;\n" "\n"); // Handle required fields (if any). We expect all of them to be @@ -3727,8 +3953,9 @@ GenerateByteSize(io::Printer* printer) { // exact same value, it works on all common processors. In a future version // of C++, _cached_size_ should be made into an atomic<int>. printer->Print( + "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_cached_size_ = total_size;\n" + "_cached_size_ = cached_size;\n" "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "return total_size;\n"); @@ -3804,7 +4031,9 @@ GenerateIsInitialized(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { printer->Print( "\n" - "if (!_extensions_.IsInitialized()) return false;\n"); + "if (!_extensions_.IsInitialized()) {\n" + " return false;\n" + "}\n"); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index b1e3fe21..3bdc0ed3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -165,6 +165,11 @@ class MessageGenerator { void GenerateSerializeOneField(io::Printer* printer, const FieldDescriptor* field, bool unbounded); + // Generate a switch statement to serialize 2+ fields from the same oneof. + // Or, if fields.size() == 1, just call GenerateSerializeOneField(). + void GenerateSerializeOneofFields( + io::Printer* printer, const vector<const FieldDescriptor*>& fields, + bool to_array); void GenerateSerializeOneExtensionRange( io::Printer* printer, const Descriptor::ExtensionRange* range, bool unbounded); @@ -189,6 +194,11 @@ class MessageGenerator { string classname_; Options options_; FieldGeneratorMap field_generators_; + // optimized_order_ is the order we layout the message's fields in the class. + // This is reused to initialize the fields in-order for cache efficiency. + // + // optimized_order_ excludes oneof fields. + vector<const FieldDescriptor *> optimized_order_; vector< vector<string> > runs_of_fields_; // that might be trivially cleared google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index d021035d..ca7bae02 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -161,8 +161,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " if ($name$_ == NULL) {\n" " return NULL;\n" " } else {\n" - " $type$* temp = new $type$;\n" - " temp->MergeFrom(*$name$_);\n" + " $type$* temp = new $type$(*$name$_);\n" " $name$_ = NULL;\n" " return temp;\n" " }\n" @@ -346,23 +345,29 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + if (dependent_field_) { + // for dependent fields we cannot access its internal_default_instance, + // because the type is incomplete. + // TODO(gerbens) deprecate dependent base class. + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline " : ""; + printer->Print(variables, + "$inline$const $type$& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_ != NULL ? *$name$_\n" + " : *internal_default_instance()->$name$_;\n" + "}\n"); + return; + } + map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n"); - - PrintHandlingOptionalStaticInitializers( - variables, descriptor_->file(), options_, printer, - // With static initializers. - " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", - // Without. - " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); - printer->Print(variables, "}\n"); - - if (dependent_field_) { - return; - } + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_ != NULL ? *$name$_\n" + " : *$type$::internal_default_instance();\n" + "}\n"); if (SupportsArenas(descriptor_)) { printer->Print(variables, @@ -663,8 +668,8 @@ InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, " if ($this_message$GetArenaNoVirtual() != NULL) {\n" // N.B.: safe to use the underlying field pointer here because we are sure // that it is non-NULL (because has_$name$() returned true). - " $dependent_typename$* temp = new $dependent_typename$;\n" - " temp->MergeFrom(*$field_member$);\n" + " $dependent_typename$* temp = " + "new $dependent_typename$(*$field_member$);\n" " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" @@ -1041,12 +1046,18 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * this->$name$_size();\n" - "for (int i = 0; i < this->$name$_size(); i++) {\n" + "{\n" + " unsigned int count = this->$name$_size();\n"); + printer->Indent(); + printer->Print(variables_, + "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$SizeNoVirtual(\n" " this->$name$(i));\n" "}\n"); + printer->Outdent(); + printer->Print("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 650f0381..54b3d24a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -123,13 +123,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$() const {\n" + "$inline$$type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ void $classname$::set_$name$($type$ value) {\n" + "$inline$void $classname$::set_$name$($type$ value) {\n" " $set_hasbit$\n" " $name$_ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" @@ -159,10 +159,10 @@ GenerateConstructorCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, + "$set_hasbit$\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " $type$, $wire_format_field_type$>(\n" - " input, &$name$_)));\n" - "$set_hasbit$\n"); + " input, &$name$_)));\n"); } void PrimitiveFieldGenerator:: @@ -207,16 +207,16 @@ PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} void PrimitiveOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$() const {\n" + "$inline$$type$ $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_;\n" " }\n" " return $default$;\n" "}\n" - "$inline$ void $classname$::set_$name$($type$ value) {\n" + "$inline$void $classname$::set_$name$($type$ value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -298,27 +298,27 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ $type$ $classname$::$name$(int index) const {\n" + "$inline$$type$ $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.Get(index);\n" "}\n" - "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n" + "$inline$void $classname$::set_$name$(int index, $type$ value) {\n" " $name$_.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::add_$name$($type$ value) {\n" + "$inline$void $classname$::add_$name$($type$ value) {\n" " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n"); printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n" + "$inline$const ::google::protobuf::RepeatedField< $type$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n" + "$inline$::google::protobuf::RepeatedField< $type$ >*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -336,6 +336,11 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: +GenerateUnsafeMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } @@ -420,18 +425,19 @@ void RepeatedPrimitiveFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, "{\n" - " int data_size = 0;\n"); + " size_t data_size = 0;\n" + " unsigned int count = this->$name$_size();\n"); printer->Indent(); int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { printer->Print(variables_, - "for (int i = 0; i < this->$name$_size(); i++) {\n" + "for (unsigned int i = 0; i < count; i++) {\n" " data_size += ::google::protobuf::internal::WireFormatLite::\n" " $declared_type$Size(this->$name$(i));\n" "}\n"); } else { printer->Print(variables_, - "data_size = $fixed_size$ * this->$name$_size();\n"); + "data_size = $fixed_size$UL * count;\n"); } if (descriptor_->is_packed()) { @@ -440,13 +446,16 @@ GenerateByteSize(io::Printer* printer) const { " total_size += $tag_size$ +\n" " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" "}\n" + "int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n" "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_$name$_cached_byte_size_ = data_size;\n" + "_$name$_cached_byte_size_ = cached_size;\n" "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "total_size += data_size;\n"); } else { printer->Print(variables_, - "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); + "total_size += $tag_size$ *\n" + " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" + "total_size += data_size;\n"); } printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 655ebde4..23cc697e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -103,6 +103,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; + virtual void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 1d743457..aee3d1ea 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -166,25 +166,25 @@ void StringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; if (SupportsArenas(descriptor_)) { printer->Print(variables, - "$inline$ const ::std::string& $classname$::$name$() const {\n" + "$inline$const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.Get($default_variable$);\n" "}\n" - "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" " $set_hasbit$\n" " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::set_$name$(const char* value) {\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" " $set_hasbit$\n" " $name$_.Set($default_variable$, $string_piece$(value),\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "$inline$ " + "$inline$" "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" " $set_hasbit$\n" @@ -192,24 +192,24 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::mutable_$name$() {\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\n" - "$inline$ ::std::string* $classname$::$release_name$() {\n" + "$inline$::std::string* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" "}\n" - "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " $clear_hasbit$\n" " return $name$_.UnsafeArenaRelease($default_variable$,\n" " GetArenaNoVirtual());\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -219,7 +219,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n" + "$inline$void $classname$::unsafe_arena_set_allocated_$name$(\n" " ::std::string* $name$) {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if ($name$ != NULL) {\n" @@ -235,21 +235,21 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, } else { // No-arena case. printer->Print(variables, - "$inline$ const ::std::string& $classname$::$name$() const {\n" + "$inline$const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.GetNoArena($default_variable$);\n" "}\n" - "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::set_$name$(const char* value) {\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "$inline$ " + "$inline$" "void $classname$::set_$name$(const $pointer_type$* value, " "size_t size) {\n" " $set_hasbit$\n" @@ -257,17 +257,17 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $string_piece$(reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::mutable_$name$() {\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.MutableNoArena($default_variable$);\n" "}\n" - "$inline$ ::std::string* $classname$::$release_name$() {\n" + "$inline$::std::string* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " return $name$_.ReleaseNoArena($default_variable$);\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -339,8 +339,10 @@ GenerateConstructorCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { + // The variable |arena| is defined by the enclosing code. + // See MessageGenerator::GenerateSharedDestructorCode. printer->Print(variables_, - "$name$_.Destroy($default_variable$, GetArenaNoVirtual());\n"); + "$name$_.Destroy($default_variable$, arena);\n"); } else { printer->Print(variables_, "$name$_.DestroyNoArena($default_variable$);\n"); @@ -426,17 +428,17 @@ void StringOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; if (SupportsArenas(descriptor_)) { printer->Print(variables, - "$inline$ const ::std::string& $classname$::$name$() const {\n" + "$inline$const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_.Get($default_variable$);\n" " }\n" " return *$default_variable$;\n" "}\n" - "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -446,7 +448,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::set_$name$(const char* value) {\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -456,7 +458,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $string_piece$(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "$inline$ " + "$inline$" "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" " if (!has_$name$()) {\n" @@ -469,7 +471,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::mutable_$name$() {\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -479,7 +481,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::$release_name$() {\n" + "$inline$::std::string* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -489,7 +491,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return NULL;\n" " }\n" "}\n" - "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (has_$name$()) {\n" @@ -500,7 +502,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return NULL;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" @@ -512,7 +514,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" + "$inline$void $classname$::unsafe_arena_set_allocated_$name$(" "::std::string* $name$) {\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (!has_$name$()) {\n" @@ -530,14 +532,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, } else { // No-arena case. printer->Print(variables, - "$inline$ const ::std::string& $classname$::$name$() const {\n" + "$inline$const ::std::string& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n" " }\n" " return *$default_variable$;\n" "}\n" - "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -547,7 +549,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "$inline$ void $classname$::set_$name$(const char* value) {\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -557,7 +559,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "$inline$ " + "$inline$" "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -568,7 +570,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::mutable_$name$() {\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -577,7 +579,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" "}\n" - "$inline$ ::std::string* $classname$::$release_name$() {\n" + "$inline$::std::string* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -586,7 +588,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return NULL;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" " if (!has_$name$()) {\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" @@ -732,55 +734,55 @@ void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ const ::std::string& $classname$::$name$(int index) const {\n" + "$inline$const ::std::string& $classname$::$name$(int index) const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.$cppget$(index);\n" "}\n" - "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n" + "$inline$::std::string* $classname$::mutable_$name$(int index) {\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable(index);\n" "}\n" - "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n" + "$inline$void $classname$::set_$name$(int index, const ::std::string& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " $name$_.Mutable(index)->assign(value);\n" "}\n" - "$inline$ void $classname$::set_$name$(int index, const char* value) {\n" + "$inline$void $classname$::set_$name$(int index, const char* value) {\n" " $name$_.Mutable(index)->assign(value);\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" - "$inline$ void " + "$inline$void " "$classname$::set_$name$" "(int index, const $pointer_type$* value, size_t size) {\n" " $name$_.Mutable(index)->assign(\n" " reinterpret_cast<const char*>(value), size);\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "$inline$ ::std::string* $classname$::add_$name$() {\n" + "$inline$::std::string* $classname$::add_$name$() {\n" " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" " return $name$_.Add();\n" "}\n" - "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n" + "$inline$void $classname$::add_$name$(const ::std::string& value) {\n" " $name$_.Add()->assign(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n" - "$inline$ void $classname$::add_$name$(const char* value) {\n" + "$inline$void $classname$::add_$name$(const char* value) {\n" " $name$_.Add()->assign(value);\n" " // @@protoc_insertion_point(field_add_char:$full_name$)\n" "}\n" - "$inline$ void " + "$inline$void " "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" "}\n"); printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" + "$inline$const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n" + "$inline$::google::protobuf::RepeatedPtrField< ::std::string>*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" " return &$name$_;\n" @@ -798,6 +800,11 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: +GenerateUnsafeMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); +} + +void RepeatedStringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } @@ -858,7 +865,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * this->$name$_size();\n" + "total_size += $tag_size$ *\n" + " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" "for (int i = 0; i < this->$name$_size(); i++) {\n" " total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" " this->$name$(i));\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index cb4e8772..1dea7663 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -110,6 +110,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; + void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index b7b6039a..d214ef0a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -129,12 +129,12 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) { // Test that descriptors are generated correctly by converting them to // FileDescriptorProtos and comparing. - FileDescriptorProto generated_decsriptor_proto, parsed_descriptor_proto; - generated_descriptor->CopyTo(&generated_decsriptor_proto); + 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_decsriptor_proto.DebugString()); + generated_descriptor_proto.DebugString()); } #if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 5e387285..3cbc530e 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -189,8 +189,6 @@ void MaybeRestartJavaMethod(io::Printer* printer, *bytecode_estimate = 0; } } - - } // namespace FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options, diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 16c5bec5..07aa3565 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -92,7 +92,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, const JavaType valueJavaType = GetJavaType(value); (*variables)["key_type"] = TypeName(key, name_resolver, false); - (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true); + string boxed_key_type = TypeName(key, name_resolver, true); + (*variables)["boxed_key_type"] = boxed_key_type; + // Used for calling the serialization function. + (*variables)["short_key_type"] = + boxed_key_type.substr(boxed_key_type.rfind('.') + 1); (*variables)["key_wire_type"] = WireType(key); (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ? @@ -147,6 +151,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, name_resolver->GetImmutableClassName(descriptor->file()) + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + "_descriptor, "; + (*variables)["ver"] = GeneratedCodeVersionSuffix(); } } // namespace @@ -661,21 +666,23 @@ GenerateParsingCode(io::Printer* printer) const { variables_, "com.google.protobuf.ByteString bytes = input.readBytes();\n" "com.google.protobuf.MapEntry<$type_parameters$>\n" - "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); + "$name$__ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, - "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n" + "if ($value_enum_type$.forNumber($name$__.getValue()) == null) {\n" " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" - " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" + " $name$_.getMutableMap().put(\n" + " $name$__.getKey(), $name$__.getValue());\n" "}\n"); } else { printer->Print( variables_, "com.google.protobuf.MapEntry<$type_parameters$>\n" - "$name$ = input.readMessage(\n" + "$name$__ = input.readMessage(\n" " $default_entry$.getParserForType(), extensionRegistry);\n" - "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"); + "$name$_.getMutableMap().put(\n" + " $name$__.getKey(), $name$__.getValue());\n"); } } @@ -688,15 +695,12 @@ void ImmutableMapFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print( variables_, - "for (java.util.Map.Entry<$type_parameters$> entry\n" - " : internalGet$capitalized_name$().getMap().entrySet()) {\n" - " com.google.protobuf.MapEntry<$type_parameters$>\n" - " $name$ = $default_entry$.newBuilderForType()\n" - " .setKey(entry.getKey())\n" - " .setValue(entry.getValue())\n" - " .build();\n" - " output.writeMessage($number$, $name$);\n" - "}\n"); + "com.google.protobuf.GeneratedMessage$ver$\n" + " .serialize$short_key_type$MapTo(\n" + " output,\n" + " internalGet$capitalized_name$(),\n" + " $default_entry$,\n" + " $number$);\n"); } void ImmutableMapFieldGenerator:: @@ -706,12 +710,12 @@ GenerateSerializedSizeCode(io::Printer* printer) const { "for (java.util.Map.Entry<$type_parameters$> entry\n" " : internalGet$capitalized_name$().getMap().entrySet()) {\n" " com.google.protobuf.MapEntry<$type_parameters$>\n" - " $name$ = $default_entry$.newBuilderForType()\n" + " $name$__ = $default_entry$.newBuilderForType()\n" " .setKey(entry.getKey())\n" " .setValue(entry.getValue())\n" " .build();\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeMessageSize($number$, $name$);\n" + " .computeMessageSize($number$, $name$__);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index 0d3bea17..5f102e07 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -765,14 +765,14 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print( variables_, "com.google.protobuf.ByteString bytes = input.readBytes();\n" - "java.util.Map.Entry<$type_parameters$> $name$ =\n" + "java.util.Map.Entry<$type_parameters$> $name$__ =\n" " $default_entry$.parseEntry(bytes, extensionRegistry);\n"); printer->Print( variables_, - "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n" + "if ($value_enum_type$.forNumber($name$__.getValue()) == null) {\n" " super.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" - " $name$_.put($name$);\n" + " $name$_.put($name$__);\n" "}\n"); } else { printer->Print( diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 6c80d070..68d28b05 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -928,7 +928,7 @@ void ImmutableMessageGenerator::GenerateIsInitialized( case FieldDescriptor::LABEL_REPEATED: if (IsMapEntry(field->message_type())) { printer->Print( - "for ($type$ item : get$name$().values()) {\n" + "for ($type$ item : get$name$Map().values()) {\n" " if (!item.isInitialized()) {\n" " memoizedIsInitialized = 0;\n" " return false;\n" diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc index 42154694..cd82c51a 100644 --- a/src/google/protobuf/compiler/java/java_message_builder.cc +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -184,6 +184,11 @@ Generate(io::Printer* printer) { "}\n" "\n"); } else { + // Override methods declared in GeneratedMessage to return the concrete + // generated type so callsites won't depend on GeneratedMessage. This + // is needed to keep binary compatibility when we change generated code + // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release + // we changed all generated code to subclass GeneratedMessageV3). printer->Print( "public final Builder setUnknownFields(\n" " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" @@ -456,6 +461,11 @@ GenerateCommonBuilderMethods(io::Printer* printer) { "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); + // Override methods declared in GeneratedMessage to return the concrete + // generated type so callsites won't depend on GeneratedMessage. This + // is needed to keep binary compatibility when we change generated code + // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release + // we changed all generated code to subclass GeneratedMessageV3). printer->Print( "public Builder clone() {\n" " return (Builder) super.clone();\n" @@ -596,7 +606,6 @@ GenerateCommonBuilderMethods(io::Printer* printer) { " return this;\n" "}\n" "\n"); - } } @@ -690,7 +699,7 @@ void MessageBuilderGenerator::GenerateIsInitialized( case FieldDescriptor::LABEL_REPEATED: if (IsMapEntry(field->message_type())) { printer->Print( - "for ($type$ item : get$name$().values()) {\n" + "for ($type$ item : get$name$Map().values()) {\n" " if (!item.isInitialized()) {\n" " return false;\n" " }\n" diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 14281816..cba18360 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -145,6 +145,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableMessageFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, "private $type$ $name$_;\n"); PrintExtraFieldInfo(variables_, printer); diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 7c8c4a03..0c5a1f8a 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -179,6 +179,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { MaybePrintGeneratedAnnotation(context_, printer, descriptor_, /* immutable = */ true); + // The builder_type stores the super type name of the nested Builder class. string builder_type; if (descriptor_->extension_range_count() > 0) { @@ -203,7 +204,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { } printer->Indent(); - GenerateConstructor(printer); // Nested types @@ -748,7 +748,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( case FieldDescriptor::LABEL_REPEATED: if (IsMapEntry(field->message_type())) { printer->Print( - "for ($type$ item : get$name$().values()) {\n" + "for ($type$ item : get$name$Map().values()) {\n" " if (!item.isInitialized()) {\n" " if (shouldMemoize) {\n" " memoizedIsInitialized = 0;\n" diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 9f34f010..cfa8295d 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -184,6 +184,10 @@ void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { } } +string ImmutableServiceGenerator::GetOutput(const MethodDescriptor* method) { + return name_resolver_->GetImmutableClassName(method->output_type()); +} + void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) { printer->Print( "\n" @@ -209,8 +213,7 @@ void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) { vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName( method->input_type()); - vars["output"] = name_resolver_->GetImmutableClassName( - method->output_type()); + vars["output"] = GetOutput(method); printer->Print(vars, "case $index$:\n" " this.$method$(controller, ($input$)request,\n" @@ -257,8 +260,7 @@ void ImmutableServiceGenerator::GenerateCallBlockingMethod( vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName( method->input_type()); - vars["output"] = name_resolver_->GetImmutableClassName( - method->output_type()); + vars["output"] = GetOutput(method); printer->Print(vars, "case $index$:\n" " return impl.$method$(controller, ($input$)request);\n"); @@ -353,8 +355,7 @@ void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); - vars["output"] = name_resolver_->GetImmutableClassName( - method->output_type()); + vars["output"] = GetOutput(method); printer->Print(vars, "channel.callMethod(\n" " getDescriptor().getMethods().get($index$),\n" @@ -418,8 +419,7 @@ void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); - vars["output"] = name_resolver_->GetImmutableClassName( - method->output_type()); + vars["output"] = GetOutput(method); printer->Print(vars, "return ($output$) channel.callBlockingMethod(\n" " getDescriptor().getMethods().get($index$),\n" @@ -443,7 +443,7 @@ void ImmutableServiceGenerator::GenerateMethodSignature(io::Printer* printer, map<string, string> vars; vars["name"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); - vars["output"] = name_resolver_->GetImmutableClassName(method->output_type()); + vars["output"] = GetOutput(method); vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; printer->Print(vars, "public $abstract$ void $name$(\n" @@ -458,7 +458,7 @@ void ImmutableServiceGenerator::GenerateBlockingMethodSignature( map<string, string> vars; vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); - vars["output"] = name_resolver_->GetImmutableClassName(method->output_type()); + vars["output"] = GetOutput(method); printer->Print(vars, "\n" "public $output$ $method$(\n" diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h index 5fc9e2f6..12b3f942 100644 --- a/src/google/protobuf/compiler/java/java_service.h +++ b/src/google/protobuf/compiler/java/java_service.h @@ -122,6 +122,9 @@ class ImmutableServiceGenerator : public ServiceGenerator { void GenerateBlockingMethodSignature(io::Printer* printer, const MethodDescriptor* method); + // Return the output type of the method. + string GetOutput(const MethodDescriptor* method); + Context* context_; ClassNameResolver* name_resolver_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableServiceGenerator); diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc index 52893721..18bf1f51 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -119,7 +119,6 @@ void SharedCodeGenerator::Generate(GeneratorContext* context, } } - void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { // Embed the descriptor. We simply serialize the entire FileDescriptorProto // and embed it as a string literal, which is parsed and built into real @@ -134,7 +133,6 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { FileDescriptorProto file_proto; file_->CopyTo(&file_proto); - string file_data; file_proto.SerializeToString(&file_data); diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index 58c77d00..58597b4c 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -153,8 +153,8 @@ string StripProto(const string& filename) { // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript // file foo/bar/baz.js. -string GetJSFilename(const string& filename) { - return StripProto(filename) + "_pb.js"; +string GetJSFilename(const GeneratorOptions& options, const string& filename) { + return StripProto(filename) + options.GetFileNameExtension(); } // Given a filename like foo/bar/baz.proto, returns the root directory @@ -208,28 +208,28 @@ string GetPath(const GeneratorOptions& options, } } -// Forward declare, so that GetPrefix can call this method, -// which in turn, calls GetPrefix. -string GetPath(const GeneratorOptions& options, - const Descriptor* descriptor); +// Returns the name of the message with a leading dot and taking into account +// nesting, for example ".OuterMessage.InnerMessage", or returns empty if +// descriptor is null. This function does not handle namespacing, only message +// nesting. +string GetNestedMessageName(const Descriptor* descriptor) { + if (descriptor == NULL) { + return ""; + } + return StripPrefixString(descriptor->full_name(), + descriptor->file()->package()); +} // Returns the path prefix for a message or enumeration that // lives under the given file and containing type. string GetPrefix(const GeneratorOptions& options, const FileDescriptor* file_descriptor, const Descriptor* containing_type) { - string prefix = ""; - - if (containing_type == NULL) { - prefix = GetPath(options, file_descriptor); - } else { - prefix = GetPath(options, containing_type); - } - + string prefix = GetPath(options, file_descriptor) + + GetNestedMessageName(containing_type); if (!prefix.empty()) { prefix += "."; } - return prefix; } @@ -273,11 +273,13 @@ string GetPath(const GeneratorOptions& options, string MaybeCrossFileRef(const GeneratorOptions& options, const FileDescriptor* from_file, const Descriptor* to_message) { - if (options.import_style == GeneratorOptions::IMPORT_COMMONJS && + if (options.import_style == GeneratorOptions::kImportCommonJs && from_file != to_message->file()) { // Cross-file ref in CommonJS needs to use the module alias instead of // the global name. - return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); + return ModuleAlias(to_message->file()->name()) + + GetNestedMessageName(to_message->containing_type()) + + "." + to_message->name(); } else { // Within a single file we use a full name. return GetPath(options, to_message); @@ -405,21 +407,24 @@ string ToFileName(const string& input) { // that top-level extensions should go in. string GetExtensionFileName(const GeneratorOptions& options, const FileDescriptor* file) { - return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js"; + return options.output_dir + "/" + ToFileName(GetPath(options, file)) + + options.GetFileNameExtension(); } // When we're generating one output file per type name, this is the filename // that a top-level message should go in. string GetMessageFileName(const GeneratorOptions& options, const Descriptor* desc) { - return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; + return options.output_dir + "/" + ToFileName(desc->name()) + + options.GetFileNameExtension(); } // When we're generating one output file per type name, this is the filename // that a top-level message should go in. string GetEnumFileName(const GeneratorOptions& options, const EnumDescriptor* desc) { - return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; + return options.output_dir + "/" + ToFileName(desc->name()) + + options.GetFileNameExtension(); } // Returns the message/response ID, if set. @@ -444,9 +449,19 @@ bool IgnoreField(const FieldDescriptor* field) { } +// Used inside Google only -- do not remove. +bool ShouldTreatMapsAsRepeatedFields(const FileDescriptor& descriptor) { + return false; +} + // Do we ignore this message type? bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) { - return d->options().map_entry(); + return d->options().map_entry() && + !ShouldTreatMapsAsRepeatedFields(*d->file()); +} + +bool IsMap(const GeneratorOptions& options, const FieldDescriptor* field) { + return field->is_map() && !ShouldTreatMapsAsRepeatedFields(*field->file()); } // Does JSPB ignore this entire oneof? True only if all fields are ignored. @@ -459,10 +474,8 @@ bool IgnoreOneof(const OneofDescriptor* oneof) { return true; } -string JSIdent(const GeneratorOptions& options, - const FieldDescriptor* field, - bool is_upper_camel, - bool is_map) { +string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field, + bool is_upper_camel, bool is_map, bool drop_list) { string result; if (field->type() == FieldDescriptor::TYPE_GROUP) { result = is_upper_camel ? @@ -473,10 +486,10 @@ string JSIdent(const GeneratorOptions& options, ToUpperCamel(ParseLowerUnderscore(field->name())) : ToLowerCamel(ParseLowerUnderscore(field->name())); } - if (is_map || (field->is_map())) { + if (is_map || IsMap(options, field)) { // JSPB-style or proto3-style map. result += "Map"; - } else if (field->is_repeated()) { + } else if (!drop_list && field->is_repeated()) { // Repeated field. result += "List"; } @@ -485,11 +498,10 @@ string JSIdent(const GeneratorOptions& options, string JSObjectFieldName(const GeneratorOptions& options, const FieldDescriptor* field) { - string name = JSIdent( - options, - field, - /* is_upper_camel = */ false, - /* is_map = */ false); + string name = JSIdent(options, field, + /* is_upper_camel = */ false, + /* is_map = */ false, + /* drop_list = */ false); if (IsReserved(name)) { name = "pb_" + name; } @@ -514,10 +526,11 @@ string JSByteGetterSuffix(BytesMode bytes_mode) { // name, e.g. MyField for .getMyField(). string JSGetterName(const GeneratorOptions& options, const FieldDescriptor* field, - BytesMode bytes_mode = BYTES_DEFAULT) { + BytesMode bytes_mode = BYTES_DEFAULT, + bool drop_list = false) { string name = JSIdent(options, field, /* is_upper_camel = */ true, - /* is_map = */ false); + /* is_map = */ false, drop_list); if (field->type() == FieldDescriptor::TYPE_BYTES) { string suffix = JSByteGetterSuffix(bytes_mode); if (!suffix.empty()) { @@ -535,7 +548,8 @@ string JSMapGetterName(const GeneratorOptions& options, const FieldDescriptor* field) { return JSIdent(options, field, /* is_upper_camel = */ true, - /* is_map = */ true); + /* is_map = */ true, + /* drop_list = */ false); } @@ -768,6 +782,10 @@ string MaybeNumberString(const FieldDescriptor* field, const string& orig) { } string JSFieldDefault(const FieldDescriptor* field) { + if (field->is_repeated()) { + return "[]"; + } + switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: return MaybeNumberString( @@ -909,20 +927,91 @@ string JSTypeName(const GeneratorOptions& options, } } -bool HasFieldPresence(const FieldDescriptor* field); +bool UseBrokenPresenceSemantics(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + return options.broken_proto3_semantics; + } else if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2) { + return false; + } else { + GOOGLE_LOG(FATAL) << "We can only handle syntax=proto2 and syntax=proto3."; + return false; + } +} + +// Returns true for fields that return "null" from accessors when they are +// unset. This should normally only be true for non-repeated submessages, but +// we have legacy users who relied on old behavior where accessors behaved this +// way. +bool ReturnsNullWhenUnset(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + field->is_optional()) { + return true; + } + + // TODO(haberman): remove this case and unconditionally return false. + return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() && + !field->has_default_value(); +} + +// In a sane world, this would be the same as ReturnsNullWhenUnset(). But in +// the status quo, some fields declare that they never return null/undefined +// even though they actually do: +// * required fields +// * optional enum fields +// * proto3 primitive fields. +bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) { + return false; + } + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + return false; + } + + return ReturnsNullWhenUnset(options, field); +} + +bool SetterAcceptsUndefined(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (ReturnsNullWhenUnset(options, field)) { + return true; + } + + // Broken presence semantics always accepts undefined for setters. + return UseBrokenPresenceSemantics(options, field); +} + +bool SetterAcceptsNull(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (ReturnsNullWhenUnset(options, field)) { + return true; + } + + // With broken presence semantics, fields with defaults accept "null" for + // setters, but other fields do not. This is a strange quirk of the old + // codegen. + return UseBrokenPresenceSemantics(options, field) && + field->has_default_value(); +} + +// Returns types which are known to by non-nullable by default. +// The style guide requires that we omit "!" in this case. +bool IsPrimitive(const string& type) { + return type == "undefined" || type == "string" || type == "number" || + type == "boolean"; +} string JSFieldTypeAnnotation(const GeneratorOptions& options, const FieldDescriptor* field, - bool force_optional, + bool is_setter_argument, bool force_present, bool singular_if_not_packed, BytesMode bytes_mode = BYTES_DEFAULT) { - bool is_primitive = - (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && - field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && - (field->type() != FieldDescriptor::TYPE_BYTES || - bytes_mode == BYTES_B64)); - + GOOGLE_CHECK(!(is_setter_argument && force_present)); string jstype = JSTypeName(options, field, bytes_mode); if (field->is_repeated() && @@ -931,27 +1020,35 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options, bytes_mode == BYTES_DEFAULT) { jstype = "(Array<!Uint8Array>|Array<string>)"; } else { - if (!is_primitive) { + if (!IsPrimitive(jstype)) { jstype = "!" + jstype; } jstype = "Array.<" + jstype + ">"; } - if (!force_optional) { - jstype = "!" + jstype; - } } - if (field->is_optional() && is_primitive && - force_optional && !force_present) { - jstype += "?"; - } else if (field->is_required() && !is_primitive && !force_optional) { - jstype = "!" + jstype; - } + bool is_null_or_undefined = false; + + if (is_setter_argument) { + if (SetterAcceptsNull(options, field)) { + jstype = "?" + jstype; + is_null_or_undefined = true; + } - if (force_optional && HasFieldPresence(field)) { - jstype += "|undefined"; + if (SetterAcceptsUndefined(options, field)) { + jstype += "|undefined"; + is_null_or_undefined = true; + } + } else if (force_present) { + // Don't add null or undefined. + } else { + if (DeclaredReturnTypeIsNullable(options, field)) { + jstype = "?" + jstype; + is_null_or_undefined = true; + } } - if (force_present && jstype[0] != '!' && !is_primitive) { + + if (!is_null_or_undefined && !IsPrimitive(jstype)) { jstype = "!" + jstype; } @@ -1007,9 +1104,10 @@ string JSReturnDoc(const GeneratorOptions& options, return ""; } -bool HasRepeatedFields(const Descriptor* desc) { +bool HasRepeatedFields(const GeneratorOptions& options, + const Descriptor* desc) { for (int i = 0; i < desc->field_count(); i++) { - if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { + if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { return true; } } @@ -1020,8 +1118,9 @@ static const char* kRepeatedFieldArrayName = ".repeatedFields_"; string RepeatedFieldsArrayName(const GeneratorOptions& options, const Descriptor* desc) { - return HasRepeatedFields(desc) ? - (GetPath(options, desc) + kRepeatedFieldArrayName) : "null"; + return HasRepeatedFields(options, desc) + ? (GetPath(options, desc) + kRepeatedFieldArrayName) + : "null"; } bool HasOneofFields(const Descriptor* desc) { @@ -1041,10 +1140,11 @@ string OneofFieldsArrayName(const GeneratorOptions& options, (GetPath(options, desc) + kOneofGroupArrayName) : "null"; } -string RepeatedFieldNumberList(const Descriptor* desc) { +string RepeatedFieldNumberList(const GeneratorOptions& options, + const Descriptor* desc) { std::vector<string> numbers; for (int i = 0; i < desc->field_count(); i++) { - if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { + if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { numbers.push_back(JSFieldIndex(desc->field(i))); } } @@ -1108,7 +1208,7 @@ string JSExtensionsObjectName(const GeneratorOptions& options, const FileDescriptor* from_file, const Descriptor* desc) { if (desc->full_name() == "google.protobuf.bridge.MessageSet") { - // TODO(haberman): fix this for the IMPORT_COMMONJS case. + // TODO(haberman): fix this for the kImportCommonJs case. return "jspb.Message.messageSetExtensions"; } else { return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; @@ -1130,7 +1230,7 @@ const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) { string FieldDefinition(const GeneratorOptions& options, const FieldDescriptor* field) { - if (field->is_map()) { + if (IsMap(options, field)) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); string key_type = ProtoTypeName(options, key_field); @@ -1254,47 +1354,24 @@ string GetPivot(const Descriptor* desc) { return SimpleItoa(pivot); } -// Returns true for fields that represent "null" as distinct from the default -// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. -bool HasFieldPresence(const FieldDescriptor* field) { - if (field->is_repeated()) { +// Whether this field represents presence. For fields with presence, we +// generate extra methods (clearFoo() and hasFoo()) for this field. +bool HasFieldPresence(const GeneratorOptions& options, + const FieldDescriptor* field) { + if (field->is_repeated() || field->is_map()) { + // We say repeated fields and maps don't have presence, but we still do + // generate clearFoo() methods for them through a special case elsewhere. return false; } - return - (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || - (field->containing_oneof() != NULL) || - (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3); -} - -// For proto3 fields without presence, returns a string representing the default -// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more -// information. -string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - case FieldDescriptor::CPPTYPE_INT64: - case FieldDescriptor::CPPTYPE_UINT32: - case FieldDescriptor::CPPTYPE_UINT64: { - return "0"; - } - - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_FLOAT: - case FieldDescriptor::CPPTYPE_DOUBLE: - return "0"; - - case FieldDescriptor::CPPTYPE_BOOL: - return "false"; - - case FieldDescriptor::CPPTYPE_STRING: // includes BYTES - return "\"\""; - - default: - // MESSAGE is handled separately. - assert(false); - return ""; + if (UseBrokenPresenceSemantics(options, field)) { + // Proto3 files with broken presence semantics have field presence. + return true; } + + return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->containing_oneof() != NULL || + field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2; } // We use this to implement the semantics that same file can be generated @@ -1524,8 +1601,19 @@ void Generator::GenerateProvides(const GeneratorOptions& options, std::set<string>* provided) const { for (std::set<string>::iterator it = provided->begin(); it != provided->end(); ++it) { - printer->Print("goog.provide('$name$');\n", - "name", *it); + if (options.import_style == GeneratorOptions::kImportClosure) { + printer->Print("goog.provide('$name$');\n", "name", *it); + } else { + // We aren't using Closure's import system, but we use goog.exportSymbol() + // to construct the expected tree of objects, eg. + // + // goog.exportSymbol('foo.bar.Baz', null, this); + // + // // Later generated code expects foo.bar = {} to exist: + // foo.bar.Baz = function() { /* ... */ } + printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", + *it); + } } } @@ -1548,7 +1636,7 @@ void Generator::GenerateRequiresForLibrary( const GeneratorOptions& options, io::Printer* printer, const vector<const FileDescriptor*>& files, std::set<string>* provided) const { - GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE); + GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure); // For Closure imports we need to import every message type individually. std::set<string> required; std::set<string> forwards; @@ -1623,6 +1711,10 @@ void Generator::GenerateRequiresImpl(const GeneratorOptions& options, } } if (require_extension) { + if (options.binary) { + printer->Print( + "goog.require('jspb.ExtensionFieldBinaryInfo');\n"); + } printer->Print( "goog.require('jspb.ExtensionFieldInfo');\n"); } @@ -1755,14 +1847,13 @@ void Generator::GenerateClass(const GeneratorOptions& options, GenerateClassDeserializeBinary(options, printer, desc); GenerateClassSerializeBinary(options, printer, desc); } - GenerateClassClone(options, printer, desc); GenerateClassRegistration(options, printer, desc); GenerateClassFields(options, printer, desc); if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") { GenerateClassExtensionFieldInfo(options, printer, desc); } - if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) { + if (options.import_style != GeneratorOptions::kImportClosure) { for (int i = 0; i < desc->extension_count(); i++) { GenerateExtension(options, printer, desc->extension(i)); } @@ -1820,7 +1911,7 @@ void Generator::GenerateClassConstructor(const GeneratorOptions& options, void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const { - if (HasRepeatedFields(desc)) { + if (HasRepeatedFields(options, desc)) { printer->Print( "/**\n" " * List of repeated fields within this message type.\n" @@ -1831,7 +1922,7 @@ void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, "\n", "classname", GetPath(options, desc), "rptfieldarray", kRepeatedFieldArrayName, - "rptfields", RepeatedFieldNumberList(desc)); + "rptfields", RepeatedFieldNumberList(options, desc)); } if (HasOneofFields(desc)) { @@ -2000,14 +2091,59 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options, "classname", GetPath(options, desc)); } +void Generator::GenerateFieldValueExpression(io::Printer* printer, + const char *obj_reference, + const FieldDescriptor* field, + bool use_default) const { + bool is_float_or_double = + field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || + field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE; + if (use_default) { + if (is_float_or_double) { + // Coerce "Nan" and "Infinity" to actual float values. + // + // This will change null to 0, but that doesn't matter since we're getting + // with a default. + printer->Print("+"); + } + + printer->Print( + "jspb.Message.getFieldWithDefault($obj$, $index$, $default$)", + "obj", obj_reference, + "index", JSFieldIndex(field), + "default", JSFieldDefault(field)); + } else { + if (is_float_or_double) { + if (field->is_required()) { + // Use "+" to convert all fields to numeric (including null). + printer->Print( + "+jspb.Message.getField($obj$, $index$)", + "index", JSFieldIndex(field), + "obj", obj_reference); + } else { + // Converts "NaN" and "Infinity" while preserving null. + printer->Print( + "jspb.Message.get$cardinality$FloatingPointField($obj$, $index$)", + "cardinality", field->is_repeated() ? "Repeated" : "Optional", + "index", JSFieldIndex(field), + "obj", obj_reference); + } + } else { + printer->Print("jspb.Message.getField($obj$, $index$)", + "index", JSFieldIndex(field), + "obj", obj_reference); + } + } +} + void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { printer->Print("$fieldname$: ", "fieldname", JSObjectFieldName(options, field)); - if (field->is_map()) { - printer->Print("(f = msg.get$name$(true)) ? f.toArray() : []", + if (IsMap(options, field)) { + printer->Print("(f = msg.get$name$()) ? f.toArray() : []", "name", JSGetterName(options, field)); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // Message field. @@ -2024,40 +2160,29 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, "getter", JSGetterName(options, field), "type", SubmessageTypeRef(options, field)); } + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + // For bytes fields we want to always return the B64 data. + printer->Print("msg.get$getter$()", + "getter", JSGetterName(options, field, BYTES_B64)); } else { - // Simple field (singular or repeated). - if ((!HasFieldPresence(field) && !field->is_repeated()) || - field->type() == FieldDescriptor::TYPE_BYTES) { - // Delegate to the generated get<field>() method in order not to duplicate - // the proto3-field-default-value or byte-coercion logic here. - printer->Print("msg.get$getter$()", - "getter", JSGetterName(options, field, BYTES_B64)); - } else { - if (field->has_default_value()) { - printer->Print("!msg.has$name$() ? $defaultValue$ : ", - "name", JSGetterName(options, field), - "defaultValue", JSFieldDefault(field)); - } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || - field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { - if (field->is_repeated()) { - printer->Print("jspb.Message.getRepeatedFloatingPointField(" - "msg, $index$)", - "index", JSFieldIndex(field)); - } else if (field->is_optional() && !field->has_default_value()) { - printer->Print("jspb.Message.getOptionalFloatingPointField(" - "msg, $index$)", - "index", JSFieldIndex(field)); - } else { - // Convert "NaN" to NaN. - printer->Print("+jspb.Message.getField(msg, $index$)", - "index", JSFieldIndex(field)); - } - } else { - printer->Print("jspb.Message.getField(msg, $index$)", - "index", JSFieldIndex(field)); - } + bool use_default = field->has_default_value(); + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + // Repeated fields get initialized to their default in the constructor + // (why?), so we emit a plain getField() call for them. + !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) { + // Proto3 puts all defaults (including implicit defaults) in toObject(). + // But for proto2 we leave the existing semantics unchanged: unset fields + // without default are unset. + use_default = true; } + + // We don't implement this by calling the accessors, because the semantics + // of the accessors are changing independently of the toObject() semantics. + // We are migrating the accessors to return defaults instead of null, but + // it may take longer to migrate toObject (or we might not want to do it at + // all). So we want to generate independent code. + GenerateFieldValueExpression(printer, "msg", field, use_default); } } @@ -2091,8 +2216,7 @@ void Generator::GenerateClassFieldFromObject( const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { - - if (field->is_map()) { + if (IsMap(options, field)) { // `msg` is a newly-constructed message object that has not yet built any // map containers wrapping underlying arrays, so we can simply directly set // the array here without fear of a stale wrapper. @@ -2133,21 +2257,6 @@ void Generator::GenerateClassFieldFromObject( } } -void Generator::GenerateClassClone(const GeneratorOptions& options, - io::Printer* printer, - const Descriptor* desc) const { - printer->Print( - "/**\n" - " * Creates a deep clone of this proto. No data is shared with the " - "original.\n" - " * @return {!$name$} The clone.\n" - " */\n" - "$name$.prototype.cloneMessage = function() {\n" - " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n" - "};\n\n\n", - "name", GetPath(options, desc)); -} - void Generator::GenerateClassRegistration(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const { @@ -2175,12 +2284,11 @@ void GenerateBytesWrapper(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field, BytesMode bytes_mode) { - string type = - JSFieldTypeAnnotation(options, field, - /* force_optional = */ false, - /* force_present = */ !HasFieldPresence(field), - /* singular_if_not_packed = */ false, - bytes_mode); + string type = JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, bytes_mode); printer->Print( "/**\n" " * $fielddef$\n" @@ -2208,20 +2316,20 @@ void GenerateBytesWrapper(const GeneratorOptions& options, void Generator::GenerateClassField(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { - if (field->is_map()) { + if (IsMap(options, field)) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); // Map field: special handling to instantiate the map object on demand. string key_type = JSFieldTypeAnnotation( options, key_field, - /* force_optional = */ false, + /* is_setter_argument = */ false, /* force_present = */ true, /* singular_if_not_packed = */ false); string value_type = JSFieldTypeAnnotation( options, value_field, - /* force_optional = */ false, + /* is_setter_argument = */ false, /* force_present = */ true, /* singular_if_not_packed = */ false); @@ -2275,7 +2383,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "fielddef", FieldDefinition(options, field), "comment", FieldComments(field, BYTES_DEFAULT), "type", JSFieldTypeAnnotation(options, field, - /* force_optional = */ false, + /* is_setter_argument = */ false, /* force_present = */ false, /* singular_if_not_packed = */ false)); printer->Print( @@ -2289,7 +2397,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "class", GetPath(options, field->containing_type()), "name", JSGetterName(options, field), "type", JSFieldTypeAnnotation(options, field, - /* force_optional = */ false, + /* is_setter_argument = */ false, /* force_present = */ false, /* singular_if_not_packed = */ false), "rpt", (field->is_repeated() ? "Repeated" : ""), @@ -2298,12 +2406,12 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : "")); printer->Print( - "/** @param {$optionaltype$} value $returndoc$ */\n" + "/** @param {$optionaltype$} value$returndoc$ */\n" "$class$.prototype.set$name$ = function(value) {\n" " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", "optionaltype", JSFieldTypeAnnotation(options, field, - /* force_optional = */ true, + /* is_setter_argument = */ true, /* force_present = */ false, /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field), @@ -2322,16 +2430,9 @@ void Generator::GenerateClassField(const GeneratorOptions& options, (", " + JSOneofArray(options, field)) : ""), "returnvalue", JSReturnClause(field)); - printer->Print( - "$class$.prototype.clear$name$ = function() {\n" - " this.set$name$($clearedvalue$);$returnvalue$\n" - "};\n" - "\n" - "\n", - "class", GetPath(options, field->containing_type()), - "name", JSGetterName(options, field), - "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), - "returnvalue", JSReturnClause(field)); + if (field->is_repeated()) { + GenerateRepeatedMessageHelperMethods(options, printer, field); + } } else { bool untyped = @@ -2345,12 +2446,12 @@ void Generator::GenerateClassField(const GeneratorOptions& options, BytesMode bytes_mode = field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? BYTES_B64 : BYTES_DEFAULT; - string typed_annotation = - JSFieldTypeAnnotation(options, field, - /* force_optional = */ false, - /* force_present = */ !HasFieldPresence(field), - /* singular_if_not_packed = */ false, - /* bytes_mode = */ bytes_mode); + string typed_annotation = JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, + /* bytes_mode = */ bytes_mode); if (untyped) { printer->Print( "/**\n" @@ -2382,36 +2483,21 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "type", typed_annotation); } - // For proto3 fields without presence, use special getters that will return - // defaults when the field is unset, possibly constructing a value if - // required. - if (!HasFieldPresence(field) && !field->is_repeated()) { - printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)", - "index", JSFieldIndex(field), - "default", Proto3PrimitiveFieldDefault(field)); - } else { - if (!field->is_repeated()) { - printer->Print("!this.has$name$() ? $defaultValue$ : ", - "name", JSGetterName(options, field), - "defaultValue", JSFieldDefault(field)); - } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || - field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { - if (field->is_repeated()) { - printer->Print("jspb.Message.getRepeatedFloatingPointField(" - "this, $index$)", - "index", JSFieldIndex(field)); - } else { - // Convert "NaN" to NaN. - printer->Print("+jspb.Message.getField(this, $index$)", - "index", JSFieldIndex(field)); - } - } else { - printer->Print("jspb.Message.getField(this, $index$)", - "index", JSFieldIndex(field)); - } + bool use_default = !ReturnsNullWhenUnset(options, field); + + // Raw fields with no default set should just return undefined. + if (untyped && !field->has_default_value()) { + use_default = false; + } + + // Repeated fields get initialized to their default in the constructor + // (why?), so we emit a plain getField() call for them. + if (field->is_repeated()) { + use_default = false; } + GenerateFieldValueExpression(printer, "this", field, use_default); + if (untyped) { printer->Print( ";\n" @@ -2434,17 +2520,17 @@ void Generator::GenerateClassField(const GeneratorOptions& options, if (untyped) { printer->Print( "/**\n" - " * @param {*} value $returndoc$\n" + " * @param {*} value$returndoc$\n" " */\n", "returndoc", JSReturnDoc(options, field)); } else { printer->Print( - "/** @param {$optionaltype$} value $returndoc$ */\n", - "optionaltype", - JSFieldTypeAnnotation(options, field, - /* force_optional = */ true, - /* force_present = */ !HasFieldPresence(field), - /* singular_if_not_packed = */ false), + "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype", + JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ true, + /* force_present = */ false, + /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field)); } printer->Print( @@ -2471,36 +2557,70 @@ void Generator::GenerateClassField(const GeneratorOptions& options, if (untyped) { printer->Print( "/**\n" - " * Clears the value. $returndoc$\n" + " * Clears the value.$returndoc$\n" " */\n", "returndoc", JSReturnDoc(options, field)); } - if (HasFieldPresence(field) || field->is_repeated()) { - printer->Print( - "$class$.prototype.clear$name$ = function() {\n" - " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ", - "class", GetPath(options, field->containing_type()), - "name", JSGetterName(options, field), - "oneoftag", (field->containing_oneof() ? "Oneof" : ""), - "oneofgroup", (field->containing_oneof() ? - (", " + JSOneofArray(options, field)) : ""), - "index", JSFieldIndex(field)); - printer->Print( - "$clearedvalue$);$returnvalue$\n" - "};\n" - "\n" - "\n", - "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), - "returnvalue", JSReturnClause(field)); + + if (field->is_repeated()) { + GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped); } } - if (HasFieldPresence(field)) { + // Generate clearFoo() method for map fields, repeated fields, and other + // fields with presence. + if (IsMap(options, field)) { + printer->Print( + "$class$.prototype.clear$name$ = function() {\n" + " this.get$name$().clear();$returnvalue$\n" + "};\n" + "\n" + "\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(options, field), + "returnvalue", JSReturnClause(field)); + } else if (field->is_repeated() || + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_required())) { + // Fields where we can delegate to the regular setter. + printer->Print( + "$class$.prototype.clear$name$ = function() {\n" + " this.set$name$($clearedvalue$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(options, field), + "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), + "returnvalue", JSReturnClause(field)); + } else if (HasFieldPresence(options, field)) { + // Fields where we can't delegate to the regular setter because it doesn't + // accept "undefined" as an argument. + printer->Print( + "$class$.prototype.clear$name$ = function() {\n" + " jspb.Message.set$maybeoneof$Field(this, " + "$index$$maybeoneofgroup$, ", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(options, field), + "maybeoneof", (field->containing_oneof() ? "Oneof" : ""), + "maybeoneofgroup", (field->containing_oneof() ? + (", " + JSOneofArray(options, field)) : ""), + "index", JSFieldIndex(field)); + printer->Print( + "$clearedvalue$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), + "returnvalue", JSReturnClause(field)); + } + + if (HasFieldPresence(options, field)) { printer->Print( "/**\n" " * Returns whether this field is set.\n" - " * @return{!boolean}\n" + " * @return {!boolean}\n" " */\n" "$class$.prototype.has$name$ = function() {\n" " return jspb.Message.getField(this, $index$) != null;\n" @@ -2513,6 +2633,59 @@ void Generator::GenerateClassField(const GeneratorOptions& options, } } +void Generator::GenerateRepeatedPrimitiveHelperMethods( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field, bool untyped) const { + printer->Print( + "/**\n" + " * @param {!$optionaltype$} value\n" + " * @param {number=} opt_index\n" + " */\n" + "$class$.prototype.add$name$ = function(value, opt_index) {\n" + " jspb.Message.addToRepeatedField(this, $index$", + "class", GetPath(options, field->containing_type()), "name", + JSGetterName(options, field, BYTES_DEFAULT, + /* drop_list = */ true), + "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "index", + JSFieldIndex(field)); + printer->Print( + "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, opt_index);\n" + "};\n" + "\n" + "\n", + "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", + (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), + "rptvalueinit", ""); +} + +void Generator::GenerateRepeatedMessageHelperMethods( + const GeneratorOptions& options, io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print( + "/**\n" + " * @param {!$optionaltype$=} opt_value\n" + " * @param {number=} opt_index\n" + " * @return {!$optionaltype$}\n" + " */\n" + "$class$.prototype.add$name$ = function(opt_value, opt_index) {\n" + " return jspb.Message.addTo$repeatedtag$WrapperField(", + "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class", + GetPath(options, field->containing_type()), "name", + JSGetterName(options, field, BYTES_DEFAULT, + /* drop_list = */ true), + "repeatedtag", (field->is_repeated() ? "Repeated" : "")); + + printer->Print( + "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n" + "};\n" + "\n" + "\n", + "index", JSFieldIndex(field), "oneofgroup", + (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), + "ctor", GetPath(options, field->message_type())); +} + void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const { @@ -2554,7 +2727,7 @@ void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, "so that it\n" " * works in OPTIMIZED mode.\n" " *\n" - " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" + " * @type {!Object.<number, jspb.ExtensionFieldBinaryInfo>}\n" " */\n" "$class$.extensionsBinary = {};\n" "\n", @@ -2636,7 +2809,7 @@ void Generator::GenerateClassDeserializeBinaryField( printer->Print(" case $num$:\n", "num", SimpleItoa(field->number())); - if (field->is_map()) { + if (IsMap(options, field)) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); printer->Print( @@ -2679,13 +2852,9 @@ void Generator::GenerateClassDeserializeBinaryField( } if (field->is_repeated() && !field->is_packed()) { - // Repeated fields receive a |value| one at at a time; append to array - // returned by get$name$(). Annoyingly, we have to call 'set' after - // changing the array. - printer->Print(" msg.get$name$().push(value);\n", "name", - JSGetterName(options, field)); - printer->Print(" msg.set$name$(msg.get$name$());\n", "name", - JSGetterName(options, field)); + printer->Print( + " msg.add$name$(value);\n", "name", + JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true)); } else { // Singular fields, and packed repeated fields, receive a |value| either // as the field's value or as the array of all the field's values; set @@ -2757,11 +2926,18 @@ void Generator::GenerateClassSerializeBinaryField( const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { - if (HasFieldPresence(field) && + if (HasFieldPresence(options, field) && field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + string typed_annotation = JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, + /* bytes_mode = */ BYTES_DEFAULT); printer->Print( - " f = jspb.Message.getField(this, $index$);\n", - "index", JSFieldIndex(field)); + " f = /** @type {$type$} */ (jspb.Message.getField(this, $index$));\n", + "index", JSFieldIndex(field), + "type", typed_annotation); } else { printer->Print( " f = this.get$name$($nolazy$);\n", @@ -2770,17 +2946,16 @@ void Generator::GenerateClassSerializeBinaryField( "nolazy", (field->is_map()) ? "true" : ""); } - // Print an `if (condition)` statement that evaluates to true if the field // goes on the wire. - if (field->is_map()) { + if (IsMap(options, field)) { printer->Print( " if (f && f.getLength() > 0) {\n"); } else if (field->is_repeated()) { printer->Print( " if (f.length > 0) {\n"); } else { - if (HasFieldPresence(field)) { + if (HasFieldPresence(options, field)) { printer->Print( " if (f != null) {\n"); } else { @@ -2820,7 +2995,7 @@ void Generator::GenerateClassSerializeBinaryField( } // Write the field on the wire. - if (field->is_map()) { + if (IsMap(options, field)) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); printer->Print( @@ -2845,7 +3020,7 @@ void Generator::GenerateClassSerializeBinaryField( "index", SimpleItoa(field->number())); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !(field->is_map())) { + !IsMap(options, field)) { printer->Print( ",\n" " $submsg$.serializeBinaryToWriter\n", @@ -2907,7 +3082,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "class", extension_scope, "extensionType", JSFieldTypeAnnotation( options, field, - /* force_optional = */ false, + /* is_setter_argument = */ false, /* force_present = */ true, /* singular_if_not_packed = */ false)); printer->Print( @@ -2946,11 +3121,11 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "binaryMessageSerializeFn", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? (SubmessageTypeRef(options, field) + - ".serializeBinaryToWriter") : "null", + ".serializeBinaryToWriter") : "undefined", "binaryMessageDeserializeFn", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? (SubmessageTypeRef(options, field) + - ".deserializeBinaryFromReader") : "null"); + ".deserializeBinaryFromReader") : "undefined"); printer->Print( " $isPacked$);\n", @@ -3005,17 +3180,31 @@ bool GeneratorOptions::ParseFromOptions( library = options[i].second; } else if (options[i].first == "import_style") { if (options[i].second == "closure") { - import_style = IMPORT_CLOSURE; + import_style = kImportClosure; } else if (options[i].second == "commonjs") { - import_style = IMPORT_COMMONJS; + import_style = kImportCommonJs; } else if (options[i].second == "browser") { - import_style = IMPORT_BROWSER; + import_style = kImportBrowser; } else if (options[i].second == "es6") { - import_style = IMPORT_ES6; + import_style = kImportEs6; } else { *error = "Unknown import style " + options[i].second + ", expected " + "one of: closure, commonjs, browser, es6."; } + } else if (options[i].first == "extension") { + extension = options[i].second; + } else if (options[i].first == "one_output_file_per_input_file") { + if (!options[i].second.empty()) { + *error = "Unexpected option value for one_output_file_per_input_file"; + return false; + } + one_output_file_per_input_file = true; + } else if (options[i].first == "broken_proto3_semantics") { + if (!options[i].second.empty()) { + *error = "Unexpected option value for broken_proto3_semantics"; + return false; + } + broken_proto3_semantics = true; } else { // Assume any other option is an output directory, as long as it is a bare // `key` rather than a `key=value` option. @@ -3027,14 +3216,37 @@ bool GeneratorOptions::ParseFromOptions( } } - if (!library.empty() && import_style != IMPORT_CLOSURE) { - *error = "The library option should only be used for " - "import_style=closure"; + if (import_style != kImportClosure && + (add_require_for_enums || testonly || !library.empty() || + error_on_name_conflict || broken_proto3_semantics || + extension != ".js" || one_output_file_per_input_file)) { + *error = + "The add_require_for_enums, testonly, library, error_on_name_conflict, " + "broken_proto3_semantics, extension, and " + "one_output_file_per_input_file options should only be used for " + "import_style=closure"; + return false; } return true; } +GeneratorOptions::OutputMode GeneratorOptions::output_mode() const { + // We use one output file per input file if we are not using Closure or if + // this is explicitly requested. + if (import_style != kImportClosure || one_output_file_per_input_file) { + return kOneOutputFilePerInputFile; + } + + // If a library name is provided, we put everything in that one file. + if (!library.empty()) { + return kEverythingInOneFile; + } + + // Otherwise, we create one output file per type. + return kOneOutputFilePerType; +} + void Generator::GenerateFilesInDepOrder( const GeneratorOptions& options, io::Printer* printer, @@ -3081,7 +3293,7 @@ void Generator::GenerateFile(const GeneratorOptions& options, GenerateHeader(options, printer); // Generate "require" statements. - if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + if (options.import_style == GeneratorOptions::kImportCommonJs) { printer->Print("var jspb = require('google-protobuf');\n"); printer->Print("var goog = jspb;\n"); printer->Print("var global = Function('return this')();\n\n"); @@ -3091,42 +3303,43 @@ void Generator::GenerateFile(const GeneratorOptions& options, printer->Print( "var $alias$ = require('$file$');\n", "alias", ModuleAlias(name), - "file", GetRootPath(file->name(), name) + GetJSFilename(name)); + "file", GetRootPath(file->name(), name) + GetJSFilename(options, name)); } } - // We aren't using Closure's import system, but we use goog.exportSymbol() - // to construct the expected tree of objects, eg. - // - // goog.exportSymbol('foo.bar.Baz', null, this); - // - // // Later generated code expects foo.bar = {} to exist: - // foo.bar.Baz = function() { /* ... */ } set<string> provided; - - // Cover the case where this file declares extensions but no messages. - // This will ensure that the file-level object will be declared to hold - // the extensions. + set<const FieldDescriptor*> extensions; for (int i = 0; i < file->extension_count(); i++) { - provided.insert(file->extension(i)->full_name()); + // We honor the jspb::ignore option here only when working with + // Closure-style imports. Use of this option is discouraged and so we want + // to avoid adding new support for it. + if (options.import_style == GeneratorOptions::kImportClosure && + IgnoreField(file->extension(i))) { + continue; + } + provided.insert(GetPath(options, file) + "." + + JSObjectFieldName(options, file->extension(i))); + extensions.insert(file->extension(i)); } FindProvidesForFile(options, printer, file, &provided); - for (std::set<string>::iterator it = provided.begin(); - it != provided.end(); ++it) { - printer->Print("goog.exportSymbol('$name$', null, global);\n", - "name", *it); + GenerateProvides(options, printer, &provided); + vector<const FileDescriptor*> files; + files.push_back(file); + if (options.import_style == GeneratorOptions::kImportClosure) { + GenerateRequiresForLibrary(options, printer, files, &provided); } GenerateClassesAndEnums(options, printer, file); - // Extensions nested inside messages are emitted inside - // GenerateClassesAndEnums(). - for (int i = 0; i < file->extension_count(); i++) { - GenerateExtension(options, printer, file->extension(i)); + // Generate code for top-level extensions. Extensions nested inside messages + // are emitted inside GenerateClassesAndEnums(). + for (set<const FieldDescriptor*>::const_iterator it = extensions.begin(); + it != extensions.end(); ++it) { + GenerateExtension(options, printer, *it); } - if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + if (options.import_style == GeneratorOptions::kImportCommonJs) { printer->Print("goog.object.extend(exports, $package$);\n", "package", GetPath(options, file)); } @@ -3144,15 +3357,10 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, } - // There are three schemes for where output files go: - // - // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file - // - import_style = IMPORT_CLOSURE, library empty: one output file per type - // - import_style != IMPORT_CLOSURE: one output file per .proto file - if (options.import_style == GeneratorOptions::IMPORT_CLOSURE && - options.library != "") { + if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) { // All output should go in a single file. - string filename = options.output_dir + "/" + options.library + ".js"; + string filename = options.output_dir + "/" + options.library + + options.GetFileNameExtension(); google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); GOOGLE_CHECK(output.get()); io::Printer printer(output.get(), '$'); @@ -3187,7 +3395,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, if (printer.failed()) { return false; } - } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { + } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) { set<const void*> allowed_set; if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { return false; @@ -3279,13 +3487,14 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, } } } - } else { + } else /* options.output_mode() == kOneOutputFilePerInputFile */ { // Generate one output file per input (.proto) file. for (int i = 0; i < files.size(); i++) { const google::protobuf::FileDescriptor* file = files[i]; - string filename = options.output_dir + "/" + GetJSFilename(file->name()); + string filename = + options.output_dir + "/" + GetJSFilename(options, file->name()); google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); GOOGLE_CHECK(output.get()); io::Printer printer(output.get(), '$'); diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h index 056c9897..4ca3493c 100755 --- a/src/google/protobuf/compiler/js/js_generator.h +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -36,6 +36,8 @@ #include <string> #include <set> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/code_generator.h> namespace google { @@ -53,43 +55,74 @@ namespace compiler { namespace js { struct GeneratorOptions { - // Add a `goog.requires()` call for each enum type used. If not set, a forward - // declaration with `goog.forwardDeclare` is produced instead. - bool add_require_for_enums; - // Set this as a test-only module via `goog.setTestOnly();`. - bool testonly; // Output path. string output_dir; // Namespace prefix. string namespace_prefix; - // Create a library with name <name>_lib.js rather than a separate .js file - // per type? - string library; - // Error if there are two types that would generate the same output file? - bool error_on_name_conflict; // Enable binary-format support? bool binary; // What style of imports should be used. enum ImportStyle { - IMPORT_CLOSURE, // goog.require() - IMPORT_COMMONJS, // require() - IMPORT_BROWSER, // no import statements - IMPORT_ES6, // import { member } from '' + kImportClosure, // goog.require() + kImportCommonJs, // require() + kImportBrowser, // no import statements + kImportEs6, // import { member } from '' } import_style; GeneratorOptions() - : add_require_for_enums(false), - testonly(false), - output_dir("."), + : output_dir("."), namespace_prefix(""), + binary(false), + import_style(kImportClosure), + add_require_for_enums(false), + testonly(false), library(""), error_on_name_conflict(false), - binary(false), - import_style(IMPORT_CLOSURE) {} + broken_proto3_semantics(false), + extension(".js"), + one_output_file_per_input_file(false) {} bool ParseFromOptions( const vector< pair< string, string > >& options, string* error); + + // Returns the file name extension to use for generated code. + string GetFileNameExtension() const { + return import_style == kImportClosure ? extension : "_pb.js"; + } + + enum OutputMode { + // Create an output file for each input .proto file. + kOneOutputFilePerInputFile, + // Create an output file for each type. + kOneOutputFilePerType, + // Put everything in a single file named by the library option. + kEverythingInOneFile, + }; + + // Indicates how to output the generated code based on the provided options. + OutputMode output_mode() const; + + // The remaining options are only relevant when we are using kImportClosure. + + // Add a `goog.requires()` call for each enum type used. If not set, a + // forward declaration with `goog.forwardDeclare` is produced instead. + bool add_require_for_enums; + // Set this as a test-only module via `goog.setTestOnly();`. + bool testonly; + // Create a library with name <name>_lib.js rather than a separate .js file + // per type? + string library; + // Error if there are two types that would generate the same output file? + bool error_on_name_conflict; + // Preserve the broken proto3 semantics from the old codegen? This amounts + // to using proto2 field presence semantics even for proto3 files. DO NOT + // USE except for migrating legacy code. + bool broken_proto3_semantics; + // The extension to use for output file names. + string extension; + // Create a separate output file for each input file? + bool one_output_file_per_input_file; }; // CodeGenerator implementation which generates a JavaScript source file and @@ -207,6 +240,11 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { io::Printer* printer, const FileDescriptor* file) const; + void GenerateFieldValueExpression(io::Printer* printer, + const char* obj_reference, + const FieldDescriptor* field, + bool use_default) const; + // Generate definition for one class. void GenerateClass(const GeneratorOptions& options, io::Printer* printer, @@ -276,6 +314,17 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { io::Printer* printer, const FieldDescriptor* field) const; + // Generate addFoo() method for repeated primitive fields. + void GenerateRepeatedPrimitiveHelperMethods(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field, + bool untyped) const; + + // Generate addFoo() method for repeated message fields. + void GenerateRepeatedMessageHelperMethods(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); }; diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index b83b8f32..aca2a5b9 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -32,14 +32,20 @@ #include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/compiler/cpp/cpp_generator.h> + +#ifndef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> +#endif // ! OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP + +#ifndef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP #include <google/protobuf/compiler/javanano/javanano_generator.h> #include <google/protobuf/compiler/php/php_generator.h> #include <google/protobuf/compiler/ruby/ruby_generator.h> #include <google/protobuf/compiler/csharp/csharp_generator.h> #include <google/protobuf/compiler/objectivec/objectivec_generator.h> #include <google/protobuf/compiler/js/js_generator.h> +#endif // ! OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP int main(int argc, char* argv[]) { @@ -51,12 +57,15 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator, "Generate C++ header and source."); +#ifndef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP // Proto2 Java google::protobuf::compiler::java::JavaGenerator java_generator; cli.RegisterGenerator("--java_out", &java_generator, "Generate Java source file."); +#endif // !OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP +#ifndef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP // Proto2 Python google::protobuf::compiler::python::Generator py_generator; cli.RegisterGenerator("--python_out", &py_generator, @@ -91,6 +100,7 @@ int main(int argc, char* argv[]) { google::protobuf::compiler::js::Generator js_generator; cli.RegisterGenerator("--js_out", &js_generator, "Generate JavaScript source."); +#endif // !OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index 2ff50f61..e1087601 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -118,35 +118,16 @@ bool GenerateCode(const CodeGeneratorRequest& request, GeneratorResponseContext context(response, parsed_files); - if (generator.HasGenerateAll()) { - string error; - bool succeeded = generator.GenerateAll( - parsed_files, request.parameter(), &context, &error); - - if (!succeeded && error.empty()) { - error = "Code generator returned false but provided no error " - "description."; - } - if (!error.empty()) { - response->set_error(error); - } - } else { - for (int i = 0; i < parsed_files.size(); i++) { - const FileDescriptor* file = parsed_files[i]; - - string error; - bool succeeded = generator.Generate( - file, request.parameter(), &context, &error); - - if (!succeeded && error.empty()) { - error = "Code generator returned false but provided no error " - "description."; - } - if (!error.empty()) { - response->set_error(file->name() + ": " + error); - break; - } - } + string error; + bool succeeded = generator.GenerateAll( + parsed_files, request.parameter(), &context, &error); + + if (!succeeded && error.empty()) { + error = "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response->set_error(error); } return true; diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 5247f9a2..a4d4a530 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -52,14 +52,13 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorRequest_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( CodeGeneratorRequest_descriptor_, - CodeGeneratorRequest::default_instance_, + CodeGeneratorRequest::internal_default_instance(), CodeGeneratorRequest_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_), -1, -1, sizeof(CodeGeneratorRequest), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_), - -1); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_)); CodeGeneratorResponse_descriptor_ = file->message_type(1); static const int CodeGeneratorResponse_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), @@ -68,14 +67,13 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorResponse_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( CodeGeneratorResponse_descriptor_, - CodeGeneratorResponse::default_instance_, + CodeGeneratorResponse::internal_default_instance(), CodeGeneratorResponse_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_), -1, -1, sizeof(CodeGeneratorResponse), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_), - -1); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_)); CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); static const int CodeGeneratorResponse_File_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), @@ -85,20 +83,19 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorResponse_File_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( CodeGeneratorResponse_File_descriptor_, - CodeGeneratorResponse_File::default_instance_, + CodeGeneratorResponse_File::internal_default_instance(), CodeGeneratorResponse_File_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_), -1, -1, sizeof(CodeGeneratorResponse_File), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_), - -1); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_)); } namespace { GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { +void protobuf_AssignDescriptorsOnce() { ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, &protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto); } @@ -107,32 +104,48 @@ void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; void protobuf_RegisterTypes(const ::std::string&) { protobuf_AssignDescriptorsOnce(); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance()); + CodeGeneratorRequest_descriptor_, CodeGeneratorRequest::internal_default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance()); + CodeGeneratorResponse_descriptor_, CodeGeneratorResponse::internal_default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance()); + CodeGeneratorResponse_File_descriptor_, CodeGeneratorResponse_File::internal_default_instance()); } } // namespace void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { - delete CodeGeneratorRequest::default_instance_; + CodeGeneratorRequest_default_instance_.Shutdown(); delete CodeGeneratorRequest_reflection_; - delete CodeGeneratorResponse::default_instance_; + CodeGeneratorResponse_default_instance_.Shutdown(); delete CodeGeneratorResponse_reflection_; - delete CodeGeneratorResponse_File::default_instance_; + CodeGeneratorResponse_File_default_instance_.Shutdown(); delete CodeGeneratorResponse_File_reflection_; } -void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; +void protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl() { GOOGLE_PROTOBUF_VERIFY_VERSION; - ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + ::google::protobuf::protobuf_InitDefaults_google_2fprotobuf_2fdescriptor_2eproto(); + ::google::protobuf::internal::GetEmptyString(); + CodeGeneratorRequest_default_instance_.DefaultConstruct(); + ::google::protobuf::internal::GetEmptyString(); + CodeGeneratorResponse_default_instance_.DefaultConstruct(); + ::google::protobuf::internal::GetEmptyString(); + CodeGeneratorResponse_File_default_instance_.DefaultConstruct(); + CodeGeneratorRequest_default_instance_.get_mutable()->InitAsDefaultInstance(); + CodeGeneratorResponse_default_instance_.get_mutable()->InitAsDefaultInstance(); + CodeGeneratorResponse_File_default_instance_.get_mutable()->InitAsDefaultInstance(); +} + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once_); +void protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once_, + &protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl); +} +void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n%google/protobuf/compiler/plugin.proto\022" "\030google.protobuf.compiler\032 google/protob" @@ -148,15 +161,15 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { "rotosZ\tplugin_go", 456); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes); - CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest(); - CodeGeneratorResponse::default_instance_ = new CodeGeneratorResponse(); - CodeGeneratorResponse_File::default_instance_ = new CodeGeneratorResponse_File(); - CodeGeneratorRequest::default_instance_->InitAsDefaultInstance(); - CodeGeneratorResponse::default_instance_->InitAsDefaultInstance(); - CodeGeneratorResponse_File::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto); } +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once_); +void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once_, + &protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl); +} // Force AddDescriptors() to be called at static initialization time. struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto { StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { @@ -164,6 +177,16 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto } } static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_; +namespace { + +static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN; +static void MergeFromFail(int line) { + ::google::protobuf::internal::MergeFromFail(__FILE__, line); +} + +} // namespace + + // =================================================================== #if !defined(_MSC_VER) || _MSC_VER >= 1900 @@ -174,6 +197,7 @@ const int CodeGeneratorRequest::kProtoFileFieldNumber; CodeGeneratorRequest::CodeGeneratorRequest() : ::google::protobuf::Message(), _internal_metadata_(NULL) { + if (this != internal_default_instance()) protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest) } @@ -185,15 +209,13 @@ CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); - MergeFrom(from); + UnsafeMergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorRequest) } void CodeGeneratorRequest::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; parameter_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); } CodeGeneratorRequest::~CodeGeneratorRequest() { @@ -203,8 +225,6 @@ CodeGeneratorRequest::~CodeGeneratorRequest() { void CodeGeneratorRequest::SharedDtor() { parameter_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } } void CodeGeneratorRequest::SetCachedSize(int size) const { @@ -218,11 +238,11 @@ const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() { } const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); - return *default_instance_; + protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + return *internal_default_instance(); } -CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL; +::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorRequest> CodeGeneratorRequest_default_instance_; CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena) const { CodeGeneratorRequest* n = new CodeGeneratorRequest; @@ -239,7 +259,7 @@ void CodeGeneratorRequest::Clear() { } file_to_generate_.Clear(); proto_file_.Clear(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + _has_bits_.Clear(); if (_internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->Clear(); } @@ -406,9 +426,9 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( return target; } -int CodeGeneratorRequest::ByteSize() const { +size_t CodeGeneratorRequest::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest) - int total_size = 0; + size_t total_size = 0; // optional string parameter = 2; if (has_parameter()) { @@ -418,18 +438,22 @@ int CodeGeneratorRequest::ByteSize() const { } // repeated string file_to_generate = 1; - total_size += 1 * this->file_to_generate_size(); + total_size += 1 * + ::google::protobuf::internal::FromIntSize(this->file_to_generate_size()); for (int i = 0; i < this->file_to_generate_size(); i++) { total_size += ::google::protobuf::internal::WireFormatLite::StringSize( this->file_to_generate(i)); } // repeated .google.protobuf.FileDescriptorProto proto_file = 15; - total_size += 1 * this->proto_file_size(); - for (int i = 0; i < this->proto_file_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->proto_file(i)); + { + unsigned int count = this->proto_file_size(); + total_size += 1UL * count; + for (unsigned int i = 0; i < count; i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->proto_file(i)); + } } if (_internal_metadata_.have_unknown_fields()) { @@ -437,18 +461,17 @@ int CodeGeneratorRequest::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; + _cached_size_ = cached_size; GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const CodeGeneratorRequest* source = + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const CodeGeneratorRequest* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>( &from); if (source == NULL) { @@ -456,16 +479,22 @@ void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorRequest) - MergeFrom(*source); + UnsafeMergeFrom(*source); } } void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); + if (GOOGLE_PREDICT_TRUE(&from != this)) { + UnsafeMergeFrom(from); + } else { + MergeFromFail(__LINE__); } - file_to_generate_.MergeFrom(from.file_to_generate_); +} + +void CodeGeneratorRequest::UnsafeMergeFrom(const CodeGeneratorRequest& from) { + GOOGLE_DCHECK(&from != this); + file_to_generate_.UnsafeMergeFrom(from.file_to_generate_); proto_file_.MergeFrom(from.proto_file_); if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { if (from.has_parameter()) { @@ -474,7 +503,8 @@ void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { } } if (from._internal_metadata_.have_unknown_fields()) { - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata( + from.unknown_fields(), &_internal_metadata_); } } @@ -489,7 +519,7 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { // @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (&from == this) return; Clear(); - MergeFrom(from); + UnsafeMergeFrom(from); } bool CodeGeneratorRequest::IsInitialized() const { @@ -529,49 +559,49 @@ int CodeGeneratorRequest::file_to_generate_size() const { void CodeGeneratorRequest::clear_file_to_generate() { file_to_generate_.Clear(); } - const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { +const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_.Get(index); } - ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { +::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_.Mutable(index); } - void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { +void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) file_to_generate_.Mutable(index)->assign(value); } - void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { +void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { file_to_generate_.Mutable(index)->assign(value); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } - void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { +void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { file_to_generate_.Mutable(index)->assign( reinterpret_cast<const char*>(value), size); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } - ::std::string* CodeGeneratorRequest::add_file_to_generate() { +::std::string* CodeGeneratorRequest::add_file_to_generate() { // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_.Add(); } - void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { +void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { file_to_generate_.Add()->assign(value); // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } - void CodeGeneratorRequest::add_file_to_generate(const char* value) { +void CodeGeneratorRequest::add_file_to_generate(const char* value) { file_to_generate_.Add()->assign(value); // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } - void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { +void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size); // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } - const ::google::protobuf::RepeatedPtrField< ::std::string>& +const ::google::protobuf::RepeatedPtrField< ::std::string>& CodeGeneratorRequest::file_to_generate() const { // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_; } - ::google::protobuf::RepeatedPtrField< ::std::string>* +::google::protobuf::RepeatedPtrField< ::std::string>* CodeGeneratorRequest::mutable_file_to_generate() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return &file_to_generate_; @@ -591,37 +621,37 @@ void CodeGeneratorRequest::clear_parameter() { parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_parameter(); } - const ::std::string& CodeGeneratorRequest::parameter() const { +const ::std::string& CodeGeneratorRequest::parameter() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter) return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorRequest::set_parameter(const ::std::string& value) { +void CodeGeneratorRequest::set_parameter(const ::std::string& value) { set_has_parameter(); parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter) } - void CodeGeneratorRequest::set_parameter(const char* value) { +void CodeGeneratorRequest::set_parameter(const char* value) { set_has_parameter(); parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter) } - void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { +void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { set_has_parameter(); parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(reinterpret_cast<const char*>(value), size)); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter) } - ::std::string* CodeGeneratorRequest::mutable_parameter() { +::std::string* CodeGeneratorRequest::mutable_parameter() { set_has_parameter(); // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter) return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - ::std::string* CodeGeneratorRequest::release_parameter() { +::std::string* CodeGeneratorRequest::release_parameter() { // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter) clear_has_parameter(); return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { +void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { if (parameter != NULL) { set_has_parameter(); } else { @@ -661,6 +691,9 @@ CodeGeneratorRequest::proto_file() const { return proto_file_; } +inline const CodeGeneratorRequest* CodeGeneratorRequest::internal_default_instance() { + return &CodeGeneratorRequest_default_instance_.get(); +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== @@ -673,6 +706,7 @@ const int CodeGeneratorResponse_File::kContentFieldNumber; CodeGeneratorResponse_File::CodeGeneratorResponse_File() : ::google::protobuf::Message(), _internal_metadata_(NULL) { + if (this != internal_default_instance()) protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File) } @@ -684,17 +718,15 @@ CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorRespon : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); - MergeFrom(from); + UnsafeMergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File) } void CodeGeneratorResponse_File::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); insertion_point_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); content_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); } CodeGeneratorResponse_File::~CodeGeneratorResponse_File() { @@ -706,8 +738,6 @@ void CodeGeneratorResponse_File::SharedDtor() { name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); insertion_point_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); content_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } } void CodeGeneratorResponse_File::SetCachedSize(int size) const { @@ -721,11 +751,11 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() { } const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); - return *default_instance_; + protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + return *internal_default_instance(); } -CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL; +::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse_File> CodeGeneratorResponse_File_default_instance_; CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf::Arena* arena) const { CodeGeneratorResponse_File* n = new CodeGeneratorResponse_File; @@ -748,7 +778,7 @@ void CodeGeneratorResponse_File::Clear() { content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } } - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + _has_bits_.Clear(); if (_internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->Clear(); } @@ -921,9 +951,9 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( return target; } -int CodeGeneratorResponse_File::ByteSize() const { +size_t CodeGeneratorResponse_File::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File) - int total_size = 0; + size_t total_size = 0; if (_has_bits_[0 / 32] & 7u) { // optional string name = 1; @@ -953,18 +983,17 @@ int CodeGeneratorResponse_File::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; + _cached_size_ = cached_size; GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const CodeGeneratorResponse_File* source = + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const CodeGeneratorResponse_File* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>( &from); if (source == NULL) { @@ -972,15 +1001,21 @@ void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& fr ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse.File) - MergeFrom(*source); + UnsafeMergeFrom(*source); } } void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) { // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); + if (GOOGLE_PREDICT_TRUE(&from != this)) { + UnsafeMergeFrom(from); + } else { + MergeFromFail(__LINE__); } +} + +void CodeGeneratorResponse_File::UnsafeMergeFrom(const CodeGeneratorResponse_File& from) { + GOOGLE_DCHECK(&from != this); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { set_has_name(); @@ -996,7 +1031,8 @@ void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& fro } } if (from._internal_metadata_.have_unknown_fields()) { - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata( + from.unknown_fields(), &_internal_metadata_); } } @@ -1011,7 +1047,7 @@ void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from // @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (&from == this) return; Clear(); - MergeFrom(from); + UnsafeMergeFrom(from); } bool CodeGeneratorResponse_File::IsInitialized() const { @@ -1050,6 +1086,7 @@ const int CodeGeneratorResponse::kFileFieldNumber; CodeGeneratorResponse::CodeGeneratorResponse() : ::google::protobuf::Message(), _internal_metadata_(NULL) { + if (this != internal_default_instance()) protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse) } @@ -1061,15 +1098,13 @@ CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); - MergeFrom(from); + UnsafeMergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse) } void CodeGeneratorResponse::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; error_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); } CodeGeneratorResponse::~CodeGeneratorResponse() { @@ -1079,8 +1114,6 @@ CodeGeneratorResponse::~CodeGeneratorResponse() { void CodeGeneratorResponse::SharedDtor() { error_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } } void CodeGeneratorResponse::SetCachedSize(int size) const { @@ -1094,11 +1127,11 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() { } const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); - return *default_instance_; + protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + return *internal_default_instance(); } -CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL; +::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse> CodeGeneratorResponse_default_instance_; CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* arena) const { CodeGeneratorResponse* n = new CodeGeneratorResponse; @@ -1114,7 +1147,7 @@ void CodeGeneratorResponse::Clear() { error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } file_.Clear(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + _has_bits_.Clear(); if (_internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->Clear(); } @@ -1241,9 +1274,9 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( return target; } -int CodeGeneratorResponse::ByteSize() const { +size_t CodeGeneratorResponse::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse) - int total_size = 0; + size_t total_size = 0; // optional string error = 1; if (has_error()) { @@ -1253,11 +1286,14 @@ int CodeGeneratorResponse::ByteSize() const { } // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; - total_size += 1 * this->file_size(); - for (int i = 0; i < this->file_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->file(i)); + { + unsigned int count = this->file_size(); + total_size += 1UL * count; + for (unsigned int i = 0; i < count; i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->file(i)); + } } if (_internal_metadata_.have_unknown_fields()) { @@ -1265,18 +1301,17 @@ int CodeGeneratorResponse::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; + _cached_size_ = cached_size; GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const CodeGeneratorResponse* source = + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const CodeGeneratorResponse* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>( &from); if (source == NULL) { @@ -1284,15 +1319,21 @@ void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse) - MergeFrom(*source); + UnsafeMergeFrom(*source); } } void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); + if (GOOGLE_PREDICT_TRUE(&from != this)) { + UnsafeMergeFrom(from); + } else { + MergeFromFail(__LINE__); } +} + +void CodeGeneratorResponse::UnsafeMergeFrom(const CodeGeneratorResponse& from) { + GOOGLE_DCHECK(&from != this); file_.MergeFrom(from.file_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_error()) { @@ -1301,7 +1342,8 @@ void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { } } if (from._internal_metadata_.have_unknown_fields()) { - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata( + from.unknown_fields(), &_internal_metadata_); } } @@ -1316,7 +1358,7 @@ void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) { // @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (&from == this) return; Clear(); - MergeFrom(from); + UnsafeMergeFrom(from); } bool CodeGeneratorResponse::IsInitialized() const { @@ -1361,37 +1403,37 @@ void CodeGeneratorResponse_File::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } - const ::std::string& CodeGeneratorResponse_File::name() const { +const ::std::string& CodeGeneratorResponse_File::name() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name) return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_name(const ::std::string& value) { +void CodeGeneratorResponse_File::set_name(const ::std::string& value) { set_has_name(); name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name) } - void CodeGeneratorResponse_File::set_name(const char* value) { +void CodeGeneratorResponse_File::set_name(const char* value) { set_has_name(); name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name) } - void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { +void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { set_has_name(); name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(reinterpret_cast<const char*>(value), size)); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name) } - ::std::string* CodeGeneratorResponse_File::mutable_name() { +::std::string* CodeGeneratorResponse_File::mutable_name() { set_has_name(); // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name) return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - ::std::string* CodeGeneratorResponse_File::release_name() { +::std::string* CodeGeneratorResponse_File::release_name() { // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { +void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { if (name != NULL) { set_has_name(); } else { @@ -1415,37 +1457,37 @@ void CodeGeneratorResponse_File::clear_insertion_point() { insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_insertion_point(); } - const ::std::string& CodeGeneratorResponse_File::insertion_point() const { +const ::std::string& CodeGeneratorResponse_File::insertion_point() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { +void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { set_has_insertion_point(); insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } - void CodeGeneratorResponse_File::set_insertion_point(const char* value) { +void CodeGeneratorResponse_File::set_insertion_point(const char* value) { set_has_insertion_point(); insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } - void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { +void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { set_has_insertion_point(); insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(reinterpret_cast<const char*>(value), size)); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } - ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { +::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { set_has_insertion_point(); // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - ::std::string* CodeGeneratorResponse_File::release_insertion_point() { +::std::string* CodeGeneratorResponse_File::release_insertion_point() { // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) clear_has_insertion_point(); return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { +void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { if (insertion_point != NULL) { set_has_insertion_point(); } else { @@ -1469,37 +1511,37 @@ void CodeGeneratorResponse_File::clear_content() { content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_content(); } - const ::std::string& CodeGeneratorResponse_File::content() const { +const ::std::string& CodeGeneratorResponse_File::content() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content) return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_content(const ::std::string& value) { +void CodeGeneratorResponse_File::set_content(const ::std::string& value) { set_has_content(); content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content) } - void CodeGeneratorResponse_File::set_content(const char* value) { +void CodeGeneratorResponse_File::set_content(const char* value) { set_has_content(); content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content) } - void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { +void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { set_has_content(); content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(reinterpret_cast<const char*>(value), size)); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content) } - ::std::string* CodeGeneratorResponse_File::mutable_content() { +::std::string* CodeGeneratorResponse_File::mutable_content() { set_has_content(); // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content) return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - ::std::string* CodeGeneratorResponse_File::release_content() { +::std::string* CodeGeneratorResponse_File::release_content() { // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content) clear_has_content(); return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { +void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { if (content != NULL) { set_has_content(); } else { @@ -1509,6 +1551,9 @@ void CodeGeneratorResponse_File::clear_content() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) } +inline const CodeGeneratorResponse_File* CodeGeneratorResponse_File::internal_default_instance() { + return &CodeGeneratorResponse_File_default_instance_.get(); +} // ------------------------------------------------------------------- // CodeGeneratorResponse @@ -1527,37 +1572,37 @@ void CodeGeneratorResponse::clear_error() { error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_error(); } - const ::std::string& CodeGeneratorResponse::error() const { +const ::std::string& CodeGeneratorResponse::error() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error) return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse::set_error(const ::std::string& value) { +void CodeGeneratorResponse::set_error(const ::std::string& value) { set_has_error(); error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error) } - void CodeGeneratorResponse::set_error(const char* value) { +void CodeGeneratorResponse::set_error(const char* value) { set_has_error(); error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error) } - void CodeGeneratorResponse::set_error(const char* value, size_t size) { +void CodeGeneratorResponse::set_error(const char* value, size_t size) { set_has_error(); error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(reinterpret_cast<const char*>(value), size)); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error) } - ::std::string* CodeGeneratorResponse::mutable_error() { +::std::string* CodeGeneratorResponse::mutable_error() { set_has_error(); // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error) return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - ::std::string* CodeGeneratorResponse::release_error() { +::std::string* CodeGeneratorResponse::release_error() { // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error) clear_has_error(); return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } - void CodeGeneratorResponse::set_allocated_error(::std::string* error) { +void CodeGeneratorResponse::set_allocated_error(::std::string* error) { if (error != NULL) { set_has_error(); } else { @@ -1597,6 +1642,9 @@ CodeGeneratorResponse::file() const { return file_; } +inline const CodeGeneratorResponse* CodeGeneratorResponse::internal_default_instance() { + return &CodeGeneratorResponse_default_instance_.get(); +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 282c977d..f9a99e75 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -8,12 +8,12 @@ #include <google/protobuf/stubs/common.h> -#if GOOGLE_PROTOBUF_VERSION < 3000000 +#if GOOGLE_PROTOBUF_VERSION < 3001000 #error This file was generated by a newer version of protoc which is #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3000002 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. @@ -36,6 +36,7 @@ namespace compiler { // Internal implementation detail -- do not call these. void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); +void LIBPROTOC_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); @@ -68,6 +69,8 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorRequest& default_instance(); + static const CodeGeneratorRequest* internal_default_instance(); + void Swap(CodeGeneratorRequest* other); // implements Message ---------------------------------------------- @@ -82,7 +85,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message void Clear(); bool IsInitialized() const; - int ByteSize() const; + size_t ByteSizeLong() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); void SerializeWithCachedSizes( @@ -98,6 +101,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(CodeGeneratorRequest* other); + void UnsafeMergeFrom(const CodeGeneratorRequest& from); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -159,18 +163,20 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message inline void clear_has_parameter(); ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - ::google::protobuf::uint32 _has_bits_[1]; + ::google::protobuf::internal::HasBits<1> _has_bits_; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; - ::google::protobuf::internal::ArenaStringPtr parameter_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; - friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + ::google::protobuf::internal::ArenaStringPtr parameter_; + friend void LIBPROTOC_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); void InitAsDefaultInstance(); - static CodeGeneratorRequest* default_instance_; }; +extern ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorRequest> CodeGeneratorRequest_default_instance_; + // ------------------------------------------------------------------- class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse.File) */ { @@ -196,6 +202,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse_File& default_instance(); + static const CodeGeneratorResponse_File* internal_default_instance(); + void Swap(CodeGeneratorResponse_File* other); // implements Message ---------------------------------------------- @@ -210,7 +218,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M void Clear(); bool IsInitialized() const; - int ByteSize() const; + size_t ByteSizeLong() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); void SerializeWithCachedSizes( @@ -226,6 +234,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(CodeGeneratorResponse_File* other); + void UnsafeMergeFrom(const CodeGeneratorResponse_File& from); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -287,18 +296,20 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M inline void clear_has_content(); ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - ::google::protobuf::uint32 _has_bits_[1]; + ::google::protobuf::internal::HasBits<1> _has_bits_; mutable int _cached_size_; ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::internal::ArenaStringPtr insertion_point_; ::google::protobuf::internal::ArenaStringPtr content_; - friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void LIBPROTOC_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); void InitAsDefaultInstance(); - static CodeGeneratorResponse_File* default_instance_; }; +extern ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse_File> CodeGeneratorResponse_File_default_instance_; + // ------------------------------------------------------------------- class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse) */ { @@ -324,6 +335,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse& default_instance(); + static const CodeGeneratorResponse* internal_default_instance(); + void Swap(CodeGeneratorResponse* other); // implements Message ---------------------------------------------- @@ -338,7 +351,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag void Clear(); bool IsInitialized() const; - int ByteSize() const; + size_t ByteSizeLong() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); void SerializeWithCachedSizes( @@ -354,6 +367,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(CodeGeneratorResponse* other); + void UnsafeMergeFrom(const CodeGeneratorResponse& from); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -401,17 +415,19 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag inline void clear_has_error(); ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - ::google::protobuf::uint32 _has_bits_[1]; + ::google::protobuf::internal::HasBits<1> _has_bits_; mutable int _cached_size_; - ::google::protobuf::internal::ArenaStringPtr error_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; - friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + ::google::protobuf::internal::ArenaStringPtr error_; + friend void LIBPROTOC_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto_impl(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); void InitAsDefaultInstance(); - static CodeGeneratorResponse* default_instance_; }; +extern ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse> CodeGeneratorResponse_default_instance_; + // =================================================================== @@ -559,6 +575,9 @@ CodeGeneratorRequest::proto_file() const { return proto_file_; } +inline const CodeGeneratorRequest* CodeGeneratorRequest::internal_default_instance() { + return &CodeGeneratorRequest_default_instance_.get(); +} // ------------------------------------------------------------------- // CodeGeneratorResponse_File @@ -725,6 +744,9 @@ inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* con // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) } +inline const CodeGeneratorResponse_File* CodeGeneratorResponse_File::internal_default_instance() { + return &CodeGeneratorResponse_File_default_instance_.get(); +} // ------------------------------------------------------------------- // CodeGeneratorResponse @@ -813,6 +835,9 @@ CodeGeneratorResponse::file() const { return file_; } +inline const CodeGeneratorResponse* CodeGeneratorResponse::internal_default_instance() { + return &CodeGeneratorResponse_default_instance_.get(); +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index d5468a0c..3b1b0d1d 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -88,8 +88,8 @@ string StripProto(const string& filename) { // Returns the Python module name expected for a given .proto filename. string ModuleName(const string& filename) { string basename = StripProto(filename); - StripString(&basename, "-", '_'); - StripString(&basename, "/", '.'); + ReplaceCharacters(&basename, "-", '_'); + ReplaceCharacters(&basename, "/", '.'); return basename + "_pb2"; } @@ -320,7 +320,7 @@ bool Generator::Generate(const FileDescriptor* file, file_ = file; string module_name = ModuleName(file->name()); string filename = module_name; - StripString(&filename, ".", '/'); + ReplaceCharacters(&filename, ".", '/'); filename += ".py"; FileDescriptorProto fdp; @@ -430,6 +430,15 @@ void Generator::PrintFileDescriptor() const { } printer_->Print("]"); } + if (file_->public_dependency_count() > 0) { + printer_->Print(",\npublic_dependencies=["); + for (int i = 0; i < file_->public_dependency_count(); ++i) { + string module_alias = ModuleAlias(file_->public_dependency(i)->name()); + printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", + module_alias); + } + printer_->Print("]"); + } // TODO(falk): Also print options and fix the message_type, enum_type, // service and extension later in the generation. @@ -1094,6 +1103,8 @@ void Generator::PrintFieldDescriptor( m["default_value"] = StringifyDefaultValue(field); m["is_extension"] = is_extension ? "True" : "False"; m["options"] = OptionsValue("FieldOptions", options_string); + m["json_name"] = field.has_json_name() ? + ", json_name='" + field.json_name() + "'": ""; // We always set message_type and enum_type to None at this point, and then // these fields in correctly after all referenced descriptors have been // defined and/or imported (see FixForeignFieldsInDescriptors()). @@ -1104,7 +1115,7 @@ void Generator::PrintFieldDescriptor( " has_default_value=$has_default_value$, default_value=$default_value$,\n" " message_type=None, enum_type=None, containing_type=None,\n" " is_extension=$is_extension$, extension_scope=None,\n" - " options=$options$)"; + " options=$options$$json_name$)"; printer_->Print(m, field_descriptor_decl); } |