diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
28 files changed, 505 insertions, 138 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index bcfa5020..b7c1766b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -48,8 +48,8 @@ #include <google/protobuf/compiler/importer.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/stubs/stl_util-inl.h> #include <google/protobuf/stubs/map-util.h> +#include <google/protobuf/stubs/stl_util.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 76d2b798..67c12d7a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -46,10 +46,10 @@ namespace compiler { namespace cpp { EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, - const string& dllexport_decl) + const Options& options) : descriptor_(descriptor), classname_(ClassName(descriptor, false)), - dllexport_decl_(dllexport_decl) { + options_(options) { } EnumGenerator::~EnumGenerator() {} @@ -88,10 +88,10 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["min_name"] = min_value->name(); vars["max_name"] = max_value->name(); - if (dllexport_decl_.empty()) { + if (options_.dllexport_decl.empty()) { vars["dllexport"] = ""; } else { - vars["dllexport"] = dllexport_decl_ + " "; + vars["dllexport"] = options_.dllexport_decl + " "; } printer->Print(vars, diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 58f7721e..2e85a0bd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -36,8 +36,10 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #include <string> +#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> + namespace google { namespace protobuf { namespace io { @@ -53,7 +55,7 @@ class EnumGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit EnumGenerator(const EnumDescriptor* descriptor, - const string& dllexport_decl); + const Options& options); ~EnumGenerator(); // Header stuff. @@ -86,7 +88,7 @@ class EnumGenerator { private: const EnumDescriptor* descriptor_; string classname_; - string dllexport_decl_; + Options options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index a369f417..6e1620d4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -46,8 +46,9 @@ namespace cpp { namespace { void SetEnumVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { - SetCommonFieldVariables(descriptor, variables); + map<string, string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); const EnumValueDescriptor* default_value = descriptor->default_value_enum(); (*variables)["type"] = ClassName(descriptor->enum_type(), true); (*variables)["default"] = SimpleItoa(default_value->number()); @@ -58,9 +59,10 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // =================================================================== EnumFieldGenerator:: -EnumFieldGenerator(const FieldDescriptor* descriptor) +EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetEnumVariables(descriptor, &variables_); + SetEnumVariables(descriptor, &variables_, options); } EnumFieldGenerator::~EnumFieldGenerator() {} @@ -84,7 +86,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return static_cast< $type$ >($name$_);\n" "}\n" "inline void $classname$::set_$name$($type$ value) {\n" - " GOOGLE_DCHECK($type$_IsValid(value));\n" + " assert($type$_IsValid(value));\n" " set_has_$name$();\n" " $name$_ = value;\n" "}\n"); @@ -152,9 +154,10 @@ GenerateByteSize(io::Printer* printer) const { // =================================================================== RepeatedEnumFieldGenerator:: -RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor) +RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetEnumVariables(descriptor, &variables_); + SetEnumVariables(descriptor, &variables_, options); } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} @@ -187,11 +190,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" "inline void $classname$::set_$name$(int index, $type$ value) {\n" - " GOOGLE_DCHECK($type$_IsValid(value));\n" + " assert($type$_IsValid(value));\n" " $name$_.Set(index, value);\n" "}\n" "inline void $classname$::add_$name$($type$ value) {\n" - " GOOGLE_DCHECK($type$_IsValid(value));\n" + " assert($type$_IsValid(value));\n" " $name$_.Add(value);\n" "}\n"); printer->Print(variables_, @@ -345,7 +348,9 @@ GenerateByteSize(io::Printer* printer) const { " total_size += $tag_size$ +\n" " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" "}\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" "_$name$_cached_byte_size_ = data_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "total_size += data_size;\n"); } else { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 0793430c..65770083 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -46,7 +46,8 @@ namespace cpp { class EnumFieldGenerator : public FieldGenerator { public: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor); + explicit EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~EnumFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -71,7 +72,8 @@ class EnumFieldGenerator : public FieldGenerator { class RepeatedEnumFieldGenerator : public FieldGenerator { public: - explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); + explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedEnumFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 658a7077..ef56b5e5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -57,9 +57,9 @@ string ExtendeeClassName(const FieldDescriptor* descriptor) { } // anonymous namespace ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, - const string& dllexport_decl) + const Options& options) : descriptor_(descriptor), - dllexport_decl_(dllexport_decl) { + options_(options) { // Construct type_traits_. if (descriptor_->is_repeated()) { type_traits_ = "Repeated"; @@ -106,8 +106,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { // export/import specifier. if (descriptor_->extension_scope() == NULL) { vars["qualifier"] = "extern"; - if (!dllexport_decl_.empty()) { - vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"]; + if (!options_.dllexport_decl.empty()) { + vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"]; } } else { vars["qualifier"] = "static"; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index 3068b091..50ad035b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -37,6 +37,7 @@ #include <string> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -56,8 +57,8 @@ namespace cpp { class ExtensionGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit ExtensionGenerator(const FieldDescriptor* descriptor, - const string& dllexport_decl); + explicit ExtensionGenerator(const FieldDescriptor* desycriptor, + const Options& options); ~ExtensionGenerator(); // Header stuff. @@ -72,7 +73,7 @@ class ExtensionGenerator { private: const FieldDescriptor* descriptor_; string type_traits_; - string dllexport_decl_; + Options options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 103cac4a..0786176b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -52,7 +52,8 @@ namespace cpp { using internal::WireFormat; void SetCommonFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { + map<string, string>* variables, + const Options& options) { (*variables)["name"] = FieldName(descriptor); (*variables)["index"] = SimpleItoa(descriptor->index()); (*variables)["number"] = SimpleItoa(descriptor->number()); @@ -64,6 +65,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["deprecation"] = descriptor->options().deprecated() ? " PROTOBUF_DEPRECATED" : ""; + (*variables)["cppget"] = "Get"; } FieldGenerator::~FieldGenerator() {} @@ -80,46 +82,47 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { } -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, + const Options& options) : descriptor_(descriptor), - field_generators_( - new scoped_ptr<FieldGenerator>[descriptor->field_count()]) { + field_generators_(new scoped_ptr<FieldGenerator>[descriptor->field_count()]) { // Construct all the FieldGenerators. for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(MakeGenerator(descriptor->field(i))); + field_generators_[i].reset(MakeGenerator(descriptor->field(i), options)); } } -FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { +FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, + const Options& options) { if (field->is_repeated()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new RepeatedMessageFieldGenerator(field); + return new RepeatedMessageFieldGenerator(field, options); case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // RepeatedStringFieldGenerator handles unknown ctypes. case FieldOptions::STRING: - return new RepeatedStringFieldGenerator(field); + return new RepeatedStringFieldGenerator(field, options); } case FieldDescriptor::CPPTYPE_ENUM: - return new RepeatedEnumFieldGenerator(field); + return new RepeatedEnumFieldGenerator(field, options); default: - return new RepeatedPrimitiveFieldGenerator(field); + return new RepeatedPrimitiveFieldGenerator(field, options); } } else { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field); + return new MessageFieldGenerator(field, options); case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // StringFieldGenerator handles unknown ctypes. case FieldOptions::STRING: - return new StringFieldGenerator(field); + return new StringFieldGenerator(field, options); } case FieldDescriptor::CPPTYPE_ENUM: - return new EnumFieldGenerator(field); + return new EnumFieldGenerator(field, options); default: - return new PrimitiveFieldGenerator(field); + return new PrimitiveFieldGenerator(field, options); } } } diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index c303a337..f7d99b15 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -40,6 +40,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -57,7 +58,8 @@ namespace cpp { // ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', // 'deprecation']. void SetCommonFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables); + map<string, string>* variables, + const Options& options); class FieldGenerator { public: @@ -114,6 +116,13 @@ class FieldGenerator { // Most field types don't need this, so the default implementation is empty. virtual void GenerateDestructorCode(io::Printer* printer) const {} + // Generate code that allocates the fields's default instance. + virtual void GenerateDefaultInstanceAllocator(io::Printer* printer) const {} + + // Generate code that should be run when ShutdownProtobufLibrary() is called, + // to delete all dynamically-allocated objects. + virtual void GenerateShutdownCode(io::Printer* printer) const {} + // Generate lines to decode this field, which will be placed inside the // message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; @@ -144,7 +153,7 @@ class FieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor); + explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; @@ -153,7 +162,8 @@ class FieldGeneratorMap { const Descriptor* descriptor_; scoped_array<scoped_ptr<FieldGenerator> > field_generators_; - static FieldGenerator* MakeGenerator(const FieldDescriptor* field); + static FieldGenerator* MakeGenerator(const FieldDescriptor* field, + const Options& options); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index b8e7708f..1bbc89c4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -51,7 +51,7 @@ namespace cpp { // =================================================================== FileGenerator::FileGenerator(const FileDescriptor* file, - const string& dllexport_decl) + const Options& options) : file_(file), message_generators_( new scoped_ptr<MessageGenerator>[file->message_type_count()]), @@ -61,26 +61,26 @@ FileGenerator::FileGenerator(const FileDescriptor* file, new scoped_ptr<ServiceGenerator>[file->service_count()]), extension_generators_( new scoped_ptr<ExtensionGenerator>[file->extension_count()]), - dllexport_decl_(dllexport_decl) { + options_(options) { for (int i = 0; i < file->message_type_count(); i++) { message_generators_[i].reset( - new MessageGenerator(file->message_type(i), dllexport_decl)); + new MessageGenerator(file->message_type(i), options)); } for (int i = 0; i < file->enum_type_count(); i++) { enum_generators_[i].reset( - new EnumGenerator(file->enum_type(i), dllexport_decl)); + new EnumGenerator(file->enum_type(i), options)); } for (int i = 0; i < file->service_count(); i++) { service_generators_[i].reset( - new ServiceGenerator(file->service(i), dllexport_decl)); + new ServiceGenerator(file->service(i), options)); } for (int i = 0; i < file->extension_count(); i++) { extension_generators_[i].reset( - new ExtensionGenerator(file->extension(i), dllexport_decl)); + new ExtensionGenerator(file->extension(i), options)); } SplitStringUsing(file_->package(), ".", &package_parts_); @@ -104,6 +104,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "filename", file_->name(), "filename_identifier", filename_identifier); + printer->Print( "#include <google/protobuf/stubs/common.h>\n" "\n"); @@ -128,13 +129,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // OK, it's now safe to #include other files. printer->Print( - "#include <google/protobuf/generated_message_util.h>\n" + "#include <google/protobuf/generated_message_util.h>\n"); + if (file_->message_type_count() > 0) { + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include <google/protobuf/message.h>\n"); + } else { + printer->Print( + "#include <google/protobuf/message_lite.h>\n"); + } + } + printer->Print( "#include <google/protobuf/repeated_field.h>\n" "#include <google/protobuf/extension_set.h>\n"); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) { printer->Print( - "#include <google/protobuf/generated_message_reflection.h>\n"); + "#include <google/protobuf/generated_enum_reflection.h>\n"); } if (HasGenericServices(file_)) { @@ -142,6 +153,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "#include <google/protobuf/service.h>\n"); } + if (HasUnknownFields(file_) && file_->message_type_count() > 0) { + printer->Print( + "#include <google/protobuf/unknown_field_set.h>\n"); + } + for (int i = 0; i < file_->dependency_count(); i++) { printer->Print( @@ -149,9 +165,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "dependency", StripProto(file_->dependency(i)->name())); } + printer->Print( "// @@protoc_insertion_point(includes)\n"); + // Open namespace. GenerateNamespaceOpeners(printer); @@ -162,7 +180,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// Internal implementation detail -- do not call these.\n" "void $dllexport_decl$ $adddescriptorsname$();\n", "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "dllexport_decl", dllexport_decl_); + "dllexport_decl", options_.dllexport_decl); printer->Print( // Note that we don't put dllexport_decl on these because they are only @@ -282,6 +300,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" "\n" // The generated code calls accessors that might be deprecated. We don't @@ -294,11 +313,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/stubs/once.h>\n" "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", + "filename", file_->name(), "basename", StripProto(file_->name())); if (HasDescriptorMethods(file_)) { printer->Print( "#include <google/protobuf/descriptor.h>\n" + "#include <google/protobuf/generated_message_reflection.h>\n" "#include <google/protobuf/reflection_ops.h>\n" "#include <google/protobuf/wire_format.h>\n"); } @@ -504,10 +525,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { " static bool already_here = false;\n" " if (already_here) return;\n" " already_here = true;\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n", + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", // Without. "void $adddescriptorsname$_impl() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n", + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", // Vars. "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); @@ -521,9 +544,9 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { vector<string> dependency_package_parts; SplitStringUsing(dependency->package(), ".", &dependency_package_parts); printer->Print("::"); - for (int i = 0; i < dependency_package_parts.size(); i++) { + for (int j = 0; j < dependency_package_parts.size(); j++) { printer->Print("$name$::", - "name", dependency_package_parts[i]); + "name", dependency_package_parts[j]); } // Call its AddDescriptors function. printer->Print( @@ -547,10 +570,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { printer->Print("\n \"$data$\"", - "data", EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); + "data", + EscapeTrigraphs( + CEscape(file_data.substr(i, kBytesPerLine)))); } printer->Print( - ", $size$);\n", + ", $size$);\n", "size", SimpleItoa(file_data.size())); // Call MessageFactory::InternalRegisterGeneratedFile(). @@ -594,7 +619,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // Without. "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" "void $adddescriptorsname$() {\n" - " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" + " ::google::protobuf::::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" " &$adddescriptorsname$_impl);\n" "}\n", // Vars. diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index b4e01285..2deefaa8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -39,6 +39,7 @@ #include <vector> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -61,7 +62,7 @@ class FileGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit FileGenerator(const FileDescriptor* file, - const string& dllexport_decl); + const Options& options); ~FileGenerator(); void GenerateHeader(io::Printer* printer); @@ -85,7 +86,7 @@ class FileGenerator { // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. vector<string> package_parts_; - string dllexport_decl_; + const Options options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index bb84e2ab..1813510b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -78,11 +78,13 @@ bool CppGenerator::Generate(const FileDescriptor* file, // } // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or // __declspec(dllimport) depending on what is being compiled. - string dllexport_decl; + Options file_options; for (int i = 0; i < options.size(); i++) { if (options[i].first == "dllexport_decl") { - dllexport_decl = options[i].second; + file_options.dllexport_decl = options[i].second; + } else if (options[i].first == "safe_boundary_check") { + file_options.safe_boundary_check = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -95,7 +97,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, string basename = StripProto(file->name()); basename.append(".pb"); - FileGenerator file_generator(file, dllexport_decl); + FileGenerator file_generator(file, file_options); // Generate header. { diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index c4b868c2..28911ab0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -148,7 +148,7 @@ string ClassName(const Descriptor* descriptor, bool qualified) { string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { if (enum_descriptor->containing_type() == NULL) { if (qualified) { - return DotsToColons(enum_descriptor->full_name()); + return "::" + DotsToColons(enum_descriptor->full_name()); } else { return enum_descriptor->name(); } @@ -259,10 +259,23 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { string DefaultValue(const FieldDescriptor* field) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: + // gcc rejects the decimal form of kint32min and kint64min. + if (field->default_value_int32() == kint32min) { + // Make sure we are in a 2's complement system. + GOOGLE_COMPILE_ASSERT(kint32min == -0x80000000, kint32min_value_error); + return "-0x80000000"; + } return SimpleItoa(field->default_value_int32()); case FieldDescriptor::CPPTYPE_UINT32: return SimpleItoa(field->default_value_uint32()) + "u"; case FieldDescriptor::CPPTYPE_INT64: + // See the comments for CPPTYPE_INT32. + if (field->default_value_int64() == kint64min) { + // Make sure we are in a 2's complement system. + GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000), + kint64min_value_error); + return "GOOGLE_LONGLONG(-0x8000000000000000)"; + } return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; case FieldDescriptor::CPPTYPE_UINT64: return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; @@ -308,8 +321,9 @@ string DefaultValue(const FieldDescriptor* field) { ClassName(field->enum_type(), true), field->default_value_enum()->number()); case FieldDescriptor::CPPTYPE_STRING: - return "\"" + EscapeTrigraphs(CEscape(field->default_value_string())) + - "\""; + return "\"" + EscapeTrigraphs( + CEscape(field->default_value_string())) + + "\""; case FieldDescriptor::CPPTYPE_MESSAGE: return FieldMessageTypeName(field) + "::default_instance()"; } @@ -401,6 +415,23 @@ void PrintHandlingOptionalStaticInitializers( } } + +static bool HasEnumDefinitions(const Descriptor* message_type) { + if (message_type->enum_type_count() > 0) return true; + for (int i = 0; i < message_type->nested_type_count(); ++i) { + if (HasEnumDefinitions(message_type->nested_type(i))) return true; + } + return false; +} + +bool HasEnumDefinitions(const FileDescriptor* file) { + if (file->enum_type_count() > 0) return true; + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasEnumDefinitions(file->message_type(i))) return true; + } + return false; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 662a7c31..526e19cc 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -122,23 +122,27 @@ string GlobalShutdownFileName(const string& filename); string EscapeTrigraphs(const string& to_escape); // Do message classes in this file keep track of unknown fields? -inline bool HasUnknownFields(const FileDescriptor *file) { +inline bool HasUnknownFields(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } + +// Does this file have any enum type definitions? +bool HasEnumDefinitions(const FileDescriptor* file); + // Does this file have generated parsing, serialization, and other // standard methods for which reflection-based fallback implementations exist? -inline bool HasGeneratedMethods(const FileDescriptor *file) { +inline bool HasGeneratedMethods(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::CODE_SIZE; } -// Do message classes in this file have descriptor and refelction methods? -inline bool HasDescriptorMethods(const FileDescriptor *file) { +// Do message classes in this file have descriptor and reflection methods? +inline bool HasDescriptorMethods(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } // Should we generate generic services for this file? -inline bool HasGenericServices(const FileDescriptor *file) { +inline bool HasGenericServices(const FileDescriptor* file) { return file->service_count() > 0 && file->options().optimize_for() != FileOptions::LITE_RUNTIME && file->options().cc_generic_services(); @@ -173,6 +177,7 @@ void PrintHandlingOptionalStaticInitializers( io::Printer* printer, const char* with_static_init, const char* without_static_init); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 1c158be0..1ea4f13d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -48,6 +48,7 @@ #include <google/protobuf/wire_format.h> #include <google/protobuf/descriptor.pb.h> + namespace google { namespace protobuf { namespace compiler { @@ -103,6 +104,13 @@ struct ExtensionRangeSorter { } }; +// Returns true if the "required" restriction check should be ignored for the +// given field. +inline static bool ShouldIgnoreRequiredFieldCheck( + const FieldDescriptor* field) { + return false; +} + // Returns true if the message type has any required fields. If it doesn't, // we can optimize out calls to its IsInitialized() method. // @@ -129,7 +137,8 @@ static bool HasRequiredFields( if (field->is_required()) { return true; } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !ShouldIgnoreRequiredFieldCheck(field)) { if (HasRequiredFields(field->message_type(), already_seen)) { return true; } @@ -280,11 +289,11 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) { // =================================================================== MessageGenerator::MessageGenerator(const Descriptor* descriptor, - const string& dllexport_decl) + const Options& options) : descriptor_(descriptor), classname_(ClassName(descriptor, false)), - dllexport_decl_(dllexport_decl), - field_generators_(descriptor), + options_(options), + field_generators_(descriptor, options), nested_generators_(new scoped_ptr<MessageGenerator>[ descriptor->nested_type_count()]), enum_generators_(new scoped_ptr<EnumGenerator>[ @@ -294,17 +303,17 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, for (int i = 0; i < descriptor->nested_type_count(); i++) { nested_generators_[i].reset( - new MessageGenerator(descriptor->nested_type(i), dllexport_decl)); + new MessageGenerator(descriptor->nested_type(i), options)); } for (int i = 0; i < descriptor->enum_type_count(); i++) { enum_generators_[i].reset( - new EnumGenerator(descriptor->enum_type(i), dllexport_decl)); + new EnumGenerator(descriptor->enum_type(i), options)); } for (int i = 0; i < descriptor->extension_count(); i++) { extension_generators_[i].reset( - new ExtensionGenerator(descriptor->extension(i), dllexport_decl)); + new ExtensionGenerator(descriptor->extension(i), options)); } } @@ -349,7 +358,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { PrintFieldComment(printer, field); map<string, string> vars; - SetCommonFieldVariables(field, &vars); + SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); if (field->is_repeated()) { @@ -386,7 +395,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { PrintFieldComment(printer, field); map<string, string> vars; - SetCommonFieldVariables(field, &vars); + SetCommonFieldVariables(field, &vars, options_); // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -446,10 +455,10 @@ GenerateClassDefinition(io::Printer* printer) { map<string, string> vars; vars["classname"] = classname_; vars["field_count"] = SimpleItoa(descriptor_->field_count()); - if (dllexport_decl_.empty()) { + if (options_.dllexport_decl.empty()) { vars["dllexport"] = ""; } else { - vars["dllexport"] = dllexport_decl_ + " "; + vars["dllexport"] = options_.dllexport_decl + " "; } vars["superclass"] = SuperClassName(descriptor_); @@ -507,6 +516,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } + printer->Print(vars, "void Swap($classname$* other);\n" "\n" @@ -605,6 +615,7 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(" private:\n"); printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->is_repeated()) { printer->Print( @@ -680,7 +691,7 @@ GenerateClassDefinition(io::Printer* printer) { // Without. "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n", // Vars. - "dllexport_decl", dllexport_decl_, + "dllexport_decl", options_.dllexport_decl, "adddescriptorsname", GlobalAddDescriptorsName(descriptor_->file()->name())); @@ -772,9 +783,11 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { printer->Print(vars, " -1,\n"); } + printer->Print( + " ::google::protobuf::DescriptorPool::generated_pool(),\n"); + printer->Print(vars, + " ::google::protobuf::MessageFactory::generated_factory(),\n"); printer->Print(vars, - " ::google::protobuf::DescriptorPool::generated_pool(),\n" - " ::google::protobuf::MessageFactory::generated_factory(),\n" " sizeof($classname$));\n"); // Handle nested types. @@ -803,6 +816,13 @@ GenerateTypeRegistrations(io::Printer* printer) { void MessageGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) { + // 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++) { + field_generators_.get(descriptor_->field(i)) + .GenerateDefaultInstanceAllocator(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. @@ -846,6 +866,12 @@ GenerateShutdownCode(io::Printer* printer) { "classname", classname_); } + // Handle default instances of fields. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateShutdownCode(printer); + } + // Handle nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateShutdownCode(printer); @@ -1957,6 +1983,7 @@ GenerateIsInitialized(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !ShouldIgnoreRequiredFieldCheck(field) && HasRequiredFields(field->message_type())) { if (field->is_repeated()) { printer->Print( diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 04778f6d..a7e43d9c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -38,6 +38,7 @@ #include <string> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -57,7 +58,7 @@ class MessageGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit MessageGenerator(const Descriptor* descriptor, - const string& dllexport_decl); + const Options& options); ~MessageGenerator(); // Header stuff. @@ -153,7 +154,7 @@ class MessageGenerator { const Descriptor* descriptor_; string classname_; - string dllexport_decl_; + Options options_; FieldGeneratorMap field_generators_; scoped_array<scoped_ptr<MessageGenerator> > nested_generators_; scoped_array<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 7c785e7e..447f975f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -45,8 +45,9 @@ namespace cpp { namespace { void SetMessageVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { - SetCommonFieldVariables(descriptor, variables); + map<string, string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); (*variables)["stream_writer"] = (*variables)["declared_type"] + (HasFastArraySerialization(descriptor->message_type()->file()) ? @@ -59,9 +60,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // =================================================================== MessageFieldGenerator:: -MessageFieldGenerator(const FieldDescriptor* descriptor) +MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetMessageVariables(descriptor, &variables_); + SetMessageVariables(descriptor, &variables_, options); } MessageFieldGenerator::~MessageFieldGenerator() {} @@ -76,7 +78,8 @@ GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, "inline const $type$& $name$() const$deprecation$;\n" "inline $type$* mutable_$name$()$deprecation$;\n" - "inline $type$* release_$name$()$deprecation$;\n"); + "inline $type$* release_$name$()$deprecation$;\n" + "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n"); } void MessageFieldGenerator:: @@ -103,6 +106,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" + "}\n" + "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + " delete $name$_;\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " } else {\n" + " clear_has_$name$();\n" + " }\n" "}\n"); } @@ -167,9 +179,10 @@ GenerateByteSize(io::Printer* printer) const { // =================================================================== RepeatedMessageFieldGenerator:: -RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor) +RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetMessageVariables(descriptor, &variables_); + SetMessageVariables(descriptor, &variables_, options); } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} @@ -197,7 +210,7 @@ void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, "inline const $type$& $classname$::$name$(int index) const {\n" - " return $name$_.Get(index);\n" + " return $name$_.$cppget$(index);\n" "}\n" "inline $type$* $classname$::mutable_$name$(int index) {\n" " return $name$_.Mutable(index);\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index f5147278..a5ed68a5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -46,7 +46,8 @@ namespace cpp { class MessageFieldGenerator : public FieldGenerator { public: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor); + explicit MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -71,7 +72,8 @@ class MessageFieldGenerator : public FieldGenerator { class RepeatedMessageFieldGenerator : public FieldGenerator { public: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); + explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedMessageFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h new file mode 100644 index 00000000..78770662 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: rennie@google.com (Jeffrey Rennie) + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ + +#include <string> + +#include <google/protobuf/stubs/common.h> +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Generator options: +struct Options { + Options() : safe_boundary_check(false) { + } + string dllexport_decl; + bool safe_boundary_check; +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 5e8df0f4..1c35fefa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -80,8 +80,9 @@ int FixedSize(FieldDescriptor::Type type) { } void SetPrimitiveVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { - SetCommonFieldVariables(descriptor, variables); + map<string, string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); (*variables)["default"] = DefaultValue(descriptor); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); @@ -99,9 +100,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // =================================================================== PrimitiveFieldGenerator:: -PrimitiveFieldGenerator(const FieldDescriptor* descriptor) +PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetPrimitiveVariables(descriptor, &variables_); + SetPrimitiveVariables(descriptor, &variables_, options); } PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} @@ -190,9 +192,10 @@ GenerateByteSize(io::Printer* printer) const { // =================================================================== RepeatedPrimitiveFieldGenerator:: -RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor) +RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetPrimitiveVariables(descriptor, &variables_); + SetPrimitiveVariables(descriptor, &variables_, options); if (descriptor->options().packed()) { variables_["packed_reader"] = "ReadPackedPrimitive"; @@ -366,7 +369,9 @@ GenerateByteSize(io::Printer* printer) const { " total_size += $tag_size$ +\n" " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" "}\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" "_$name$_cached_byte_size_ = data_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "total_size += data_size;\n"); } else { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 8fcd74ae..48249c40 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -46,7 +46,8 @@ namespace cpp { class PrimitiveFieldGenerator : public FieldGenerator { public: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor); + explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~PrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -71,7 +72,8 @@ class PrimitiveFieldGenerator : public FieldGenerator { class RepeatedPrimitiveFieldGenerator : public FieldGenerator { public: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); + explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedPrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index c2825683..d20018ea 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -43,14 +43,14 @@ namespace compiler { namespace cpp { ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor, - const string& dllexport_decl) + const Options& options) : descriptor_(descriptor) { vars_["classname"] = descriptor_->name(); vars_["full_name"] = descriptor_->full_name(); - if (dllexport_decl.empty()) { + if (options.dllexport_decl.empty()) { vars_["dllexport"] = ""; } else { - vars_["dllexport"] = dllexport_decl + " "; + vars_["dllexport"] = options.dllexport_decl + " "; } } diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h index 10e9dd3c..820f9f5f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.h +++ b/src/google/protobuf/compiler/cpp/cpp_service.h @@ -38,6 +38,7 @@ #include <map> #include <string> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> namespace google { @@ -55,7 +56,7 @@ class ServiceGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit ServiceGenerator(const ServiceDescriptor* descriptor, - const string& dllexport_decl); + const Options& options); ~ServiceGenerator(); // Header stuff. diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 3cec2b6b..9c0911ac 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -46,11 +46,14 @@ namespace cpp { namespace { void SetStringVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { - SetCommonFieldVariables(descriptor, variables); + map<string, string>* variables, + const Options& options) { + SetCommonFieldVariables(descriptor, variables, options); (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default_length"] = + SimpleItoa(descriptor->default_value_string().length()); (*variables)["default_variable"] = descriptor->default_value_string().empty() - ? "::google::protobuf::internal::kEmptyString" + ? "&::google::protobuf::internal::kEmptyString" : "_default_" + FieldName(descriptor) + "_"; (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; @@ -61,9 +64,10 @@ void SetStringVariables(const FieldDescriptor* descriptor, // =================================================================== StringFieldGenerator:: -StringFieldGenerator(const FieldDescriptor* descriptor) +StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetStringVariables(descriptor, &variables_); + SetStringVariables(descriptor, &variables_, options); } StringFieldGenerator::~StringFieldGenerator() {} @@ -72,7 +76,7 @@ void StringFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::std::string* $name$_;\n"); if (!descriptor_->default_value_string().empty()) { - printer->Print(variables_, "static const ::std::string $default_variable$;\n"); + printer->Print(variables_, "static ::std::string* $default_variable$;\n"); } } @@ -109,7 +113,9 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline void set_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n" "inline ::std::string* mutable_$name$()$deprecation$;\n" - "inline ::std::string* release_$name$()$deprecation$;\n"); + "inline ::std::string* release_$name$()$deprecation$;\n" + "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); @@ -126,14 +132,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "inline void $classname$::set_$name$(const ::std::string& value) {\n" " set_has_$name$();\n" - " if ($name$_ == &$default_variable$) {\n" + " if ($name$_ == $default_variable$) {\n" " $name$_ = new ::std::string;\n" " }\n" " $name$_->assign(value);\n" "}\n" "inline void $classname$::set_$name$(const char* value) {\n" " set_has_$name$();\n" - " if ($name$_ == &$default_variable$) {\n" + " if ($name$_ == $default_variable$) {\n" " $name$_ = new ::std::string;\n" " }\n" " $name$_->assign(value);\n" @@ -141,20 +147,20 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline " "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" " set_has_$name$();\n" - " if ($name$_ == &$default_variable$) {\n" + " if ($name$_ == $default_variable$) {\n" " $name$_ = new ::std::string;\n" " }\n" " $name$_->assign(reinterpret_cast<const char*>(value), size);\n" "}\n" "inline ::std::string* $classname$::mutable_$name$() {\n" " set_has_$name$();\n" - " if ($name$_ == &$default_variable$) {\n"); + " if ($name$_ == $default_variable$) {\n"); if (descriptor_->default_value_string().empty()) { printer->Print(variables_, " $name$_ = new ::std::string;\n"); } else { printer->Print(variables_, - " $name$_ = new ::std::string($default_variable$);\n"); + " $name$_ = new ::std::string(*$default_variable$);\n"); } printer->Print(variables_, " }\n" @@ -162,21 +168,34 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "inline ::std::string* $classname$::release_$name$() {\n" " clear_has_$name$();\n" - " if ($name$_ == &$default_variable$) {\n" + " if ($name$_ == $default_variable$) {\n" " return NULL;\n" " } else {\n" " ::std::string* temp = $name$_;\n" - " $name$_ = const_cast< ::std::string*>(&$default_variable$);\n" + " $name$_ = const_cast< ::std::string*>($default_variable$);\n" " return temp;\n" " }\n" + "}\n" + "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if ($name$_ != $default_variable$) {\n" + " delete $name$_;\n" + " }\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $name$_ = $name$;\n" + " } else {\n" + " clear_has_$name$();\n" + " $name$_ = const_cast< ::std::string*>($default_variable$);\n" + " }\n" "}\n"); } void StringFieldGenerator:: GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { + // Initialized in GenerateDefaultInstanceAllocator. printer->Print(variables_, - "const ::std::string $classname$::$default_variable$($default$);\n"); + "::std::string* $classname$::$default_variable$ = NULL;\n"); } } @@ -184,13 +203,13 @@ void StringFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { if (descriptor_->default_value_string().empty()) { printer->Print(variables_, - "if ($name$_ != &$default_variable$) {\n" + "if ($name$_ != $default_variable$) {\n" " $name$_->clear();\n" "}\n"); } else { printer->Print(variables_, - "if ($name$_ != &$default_variable$) {\n" - " $name$_->assign($default_variable$);\n" + "if ($name$_ != $default_variable$) {\n" + " $name$_->assign(*$default_variable$);\n" "}\n"); } } @@ -208,18 +227,35 @@ GenerateSwappingCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = const_cast< ::std::string*>(&$default_variable$);\n"); + "$name$_ = const_cast< ::std::string*>($default_variable$);\n"); } void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { printer->Print(variables_, - "if ($name$_ != &$default_variable$) {\n" + "if ($name$_ != $default_variable$) {\n" " delete $name$_;\n" "}\n"); } void StringFieldGenerator:: +GenerateDefaultInstanceAllocator(io::Printer* printer) const { + if (!descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "$classname$::$default_variable$ =\n" + " new ::std::string($default$, $default_length$);\n"); + } +} + +void StringFieldGenerator:: +GenerateShutdownCode(io::Printer* printer) const { + if (!descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "delete $classname$::$default_variable$;\n"); + } +} + +void StringFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" @@ -273,9 +309,10 @@ GenerateByteSize(io::Printer* printer) const { // =================================================================== RepeatedStringFieldGenerator:: -RepeatedStringFieldGenerator(const FieldDescriptor* descriptor) +RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { - SetStringVariables(descriptor, &variables_); + SetStringVariables(descriptor, &variables_, options); } RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} @@ -328,7 +365,7 @@ void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, "inline const ::std::string& $classname$::$name$(int index) const {\n" - " return $name$_.Get(index);\n" + " return $name$_.$cppget$(index);\n" "}\n" "inline ::std::string* $classname$::mutable_$name$(int index) {\n" " return $name$_.Mutable(index);\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 7f45107d..3264134a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -46,7 +46,8 @@ namespace cpp { class StringFieldGenerator : public FieldGenerator { public: - explicit StringFieldGenerator(const FieldDescriptor* descriptor); + explicit StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~StringFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -59,6 +60,8 @@ class StringFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; + void GenerateDefaultInstanceAllocator(io::Printer* printer) const; + void GenerateShutdownCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -73,7 +76,8 @@ class StringFieldGenerator : public FieldGenerator { class RepeatedStringFieldGenerator : public FieldGenerator { public: - explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor); + explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedStringFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index 54d830fc..e14a818c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -103,9 +103,19 @@ message TestConflictingSymbolNames { message DO {} optional DO do = 32; + // Some template parameter names for extensions. + optional int32 field_type = 33; + optional bool is_packed = 34; + extensions 1000 to max; } +message TestConflictingSymbolNamesExtension { + extend TestConflictingSymbolNames { + repeated int32 repeated_int32_ext = 20423638 [packed=true]; + } +} + message DummyMessage {} service TestConflictingMethodNames { diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 301a7ce6..b5f9ab58 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -44,6 +44,8 @@ // correctly and produces the interfaces we expect, which is why this test // is written this way. +#include <google/protobuf/compiler/cpp/cpp_unittest.h> + #include <vector> #include <google/protobuf/unittest.pb.h> @@ -64,7 +66,7 @@ #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -#include <google/protobuf/stubs/stl_util-inl.h> +#include <google/protobuf/stubs/stl_util.h> namespace google { namespace protobuf { @@ -74,6 +76,8 @@ namespace cpp { // Can't use an anonymous namespace here due to brokenness of Tru64 compiler. namespace cpp_unittest { +namespace protobuf_unittest = ::protobuf_unittest; + class MockErrorCollector : public MultiFileErrorCollector { public: @@ -174,6 +178,15 @@ TEST(GeneratedMessageTest, Trigraph) { EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph()); } +TEST(GeneratedMessageTest, ExtremeSmallIntegerDefault) { + const unittest::TestExtremeDefaultValues& extreme_default = + unittest::TestExtremeDefaultValues::default_instance(); + EXPECT_EQ(-0x80000000, kint32min); + EXPECT_EQ(GOOGLE_LONGLONG(-0x8000000000000000), kint64min); + EXPECT_EQ(kint32min, extreme_default.really_small_int32()); + EXPECT_EQ(kint64min, extreme_default.really_small_int64()); +} + TEST(GeneratedMessageTest, Accessors) { // Set every field to a unique value then go back and check all those // values. @@ -202,6 +215,13 @@ TEST(GeneratedMessageTest, MutableStringDefault) { EXPECT_EQ("hello", *message.mutable_default_string()); } +TEST(GeneratedMessageTest, StringDefaults) { + unittest::TestExtremeDefaultValues message; + // Check if '\000' can be used in default string value. + EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero()); + EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero()); +} + TEST(GeneratedMessageTest, ReleaseString) { // Check that release_foo() starts out NULL, and gives us a value // that we can delete after it's been set. @@ -244,6 +264,49 @@ TEST(GeneratedMessageTest, ReleaseMessage) { EXPECT_FALSE(message.has_optional_nested_message()); } +TEST(GeneratedMessageTest, SetAllocatedString) { + // Check that set_allocated_foo() works for strings. + unittest::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_string()); + const string kHello("hello"); + message.set_optional_string(kHello); + EXPECT_TRUE(message.has_optional_string()); + + message.set_allocated_optional_string(NULL); + EXPECT_FALSE(message.has_optional_string()); + EXPECT_EQ("", message.optional_string()); + + message.set_allocated_optional_string(new string(kHello)); + EXPECT_TRUE(message.has_optional_string()); + EXPECT_EQ(kHello, message.optional_string()); +} + +TEST(GeneratedMessageTest, SetAllocatedMessage) { + // Check that set_allocated_foo() can be called in all cases. + unittest::TestAllTypes message; + + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + EXPECT_TRUE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + unittest::TestAllTypes::NestedMessage* nest = + message.release_optional_nested_message(); + ASSERT_TRUE(nest != NULL); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.set_allocated_optional_nested_message(nest); + EXPECT_TRUE(message.has_optional_nested_message()); + EXPECT_EQ(1, message.optional_nested_message().bb()); +} + TEST(GeneratedMessageTest, Clear) { // Set every field to a unique value, clear the message, then check that // it is cleared. @@ -695,6 +758,13 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) { message.set_friend_(5); EXPECT_EQ(5, message.friend_()); + + // Instantiate extension template functions to test conflicting template + // parameter names. + typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage; + message.AddExtension(ExtensionMessage::repeated_int32_ext, 123); + EXPECT_EQ(123, + message.GetExtension(ExtensionMessage::repeated_int32_ext, 0)); } #ifndef PROTOBUF_TEST_NO_DESCRIPTORS @@ -869,11 +939,10 @@ TEST(GeneratedEnumTest, MinAndMax) { EXPECT_NE(null_pointer, &unittest::ForeignEnum_MAX); EXPECT_NE(null_pointer, &unittest::ForeignEnum_ARRAYSIZE); - // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases. + // Make sure we can use _MIN and _MAX as switch cases. switch (unittest::SPARSE_A) { case unittest::TestSparseEnum_MIN: case unittest::TestSparseEnum_MAX: - case unittest::TestSparseEnum_ARRAYSIZE: break; default: break; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.h b/src/google/protobuf/compiler/cpp/cpp_unittest.h new file mode 100644 index 00000000..a3a1d1ba --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.h @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This header declares the namespace google::protobuf::protobuf_unittest in order to expose +// any problems with the generated class names. We use this header to ensure +// unittest.cc will declare the namespace prior to other includes, while obeying +// normal include ordering. +// +// When generating a class name of "foo.Bar" we must ensure we prefix the class +// name with "::", in case the namespace google::protobuf::foo exists. We intentionally +// trigger that case here by declaring google::protobuf::protobuf_unittest. +// +// See ClassName in helpers.h for more details. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ + +namespace google { +namespace protobuf { +namespace protobuf_unittest {} +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ |