diff options
author | Jos Hickson <jos.hickson@gmail.com> | 2016-05-11 09:23:46 +0100 |
---|---|---|
committer | Jos Hickson <jos.hickson@gmail.com> | 2016-05-11 09:23:46 +0100 |
commit | 2b22b611a8af9e9d06491de2ebcc5d9b962e544c (patch) | |
tree | 1d8b5a7399380da5fb3260e2f8eaa2b8cf31bec2 /src | |
parent | 48ebb29a8ec118bf6b9ee39f6be42b57321c099a (diff) | |
parent | a1938b2aa9ca86ce7ce50c27ff9737c1008d2a03 (diff) | |
download | protobuf-2b22b611a8af9e9d06491de2ebcc5d9b962e544c.tar.gz protobuf-2b22b611a8af9e9d06491de2ebcc5d9b962e544c.tar.bz2 protobuf-2b22b611a8af9e9d06491de2ebcc5d9b962e544c.zip |
Merge remote-tracking branch 'refs/remotes/google/master'
Diffstat (limited to 'src')
255 files changed, 9105 insertions, 2954 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 073673a5..80065506 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -455,6 +455,7 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/csharp/csharp_message.h \ google/protobuf/compiler/csharp/csharp_message_field.cc \ google/protobuf/compiler/csharp/csharp_message_field.h \ + google/protobuf/compiler/csharp/csharp_options.h \ google/protobuf/compiler/csharp/csharp_primitive_field.cc \ google/protobuf/compiler/csharp/csharp_primitive_field.h \ google/protobuf/compiler/csharp/csharp_reflection_class.cc \ @@ -506,6 +507,8 @@ protoc_inputs = \ google/protobuf/unittest_preserve_unknown_enum.proto \ google/protobuf/unittest.proto \ google/protobuf/unittest_proto3_arena.proto \ + google/protobuf/unittest_proto3_arena_lite.proto \ + google/protobuf/unittest_proto3_lite.proto \ google/protobuf/unittest_well_known_types.proto \ google/protobuf/util/internal/testdata/anys.proto \ google/protobuf/util/internal/testdata/books.proto \ @@ -608,6 +611,10 @@ protoc_outputs = \ google/protobuf/unittest_preserve_unknown_enum.pb.h \ google/protobuf/unittest_proto3_arena.pb.cc \ google/protobuf/unittest_proto3_arena.pb.h \ + google/protobuf/unittest_proto3_arena_lite.pb.cc \ + google/protobuf/unittest_proto3_arena_lite.pb.h \ + google/protobuf/unittest_proto3_lite.pb.cc \ + google/protobuf/unittest_proto3_lite.pb.h \ google/protobuf/unittest_well_known_types.pb.cc \ google/protobuf/unittest_well_known_types.pb.h \ google/protobuf/util/internal/testdata/anys.pb.cc \ @@ -709,6 +716,8 @@ protobuf_test_SOURCES = \ google/protobuf/no_field_presence_test.cc \ google/protobuf/preserve_unknown_enum_test.cc \ google/protobuf/proto3_arena_unittest.cc \ + google/protobuf/proto3_arena_lite_unittest.cc \ + google/protobuf/proto3_lite_unittest.cc \ google/protobuf/reflection_ops_unittest.cc \ google/protobuf/repeated_field_reflection_unittest.cc \ google/protobuf/repeated_field_unittest.cc \ diff --git a/src/README.md b/src/README.md index 4e312c0c..63d6e24c 100644 --- a/src/README.md +++ b/src/README.md @@ -16,10 +16,13 @@ To build protobuf from source, the following tools are needed: * automake * libtool * curl (used to download gmock) + * make + * g++ + * unzip On Ubuntu, you can install them with: - $ sudo apt-get install autoconf automake libtool curl + $ sudo apt-get install autoconf automake libtool curl make g++ unzip On other platforms, please use the corresponding package managing tool to install them before proceeding. @@ -181,7 +184,7 @@ In the downloads section, download the zip file protoc-$VERSION-win32.zip. It contains the protoc binary as well as public proto files of protobuf library. -To build from source using Microsoft Visual C++, see cmake/README.md. +To build from source using Microsoft Visual C++, see [cmake/README.md](../cmake/README.md). To build from source using Cygwin or MinGW, follow the Unix installation instructions, above. diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index f3ca06bf..f7b1d310 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -35,10 +35,15 @@ namespace protobuf { namespace internal { namespace { -string GetTypeUrl(const Descriptor* message) { - return string(kTypeGoogleApisComPrefix) + message->full_name(); +string GetTypeUrl(const Descriptor* message, + const string& type_url_prefix) { + if (!type_url_prefix.empty() && + type_url_prefix[type_url_prefix.size() - 1] == '/') { + return type_url_prefix + message->full_name(); + } else { + return type_url_prefix + "/" + message->full_name(); + } } - } // namespace const char kAnyFullTypeName[] = "google.protobuf.Any"; @@ -50,8 +55,13 @@ AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) } void AnyMetadata::PackFrom(const Message& message) { + PackFrom(message, kTypeGoogleApisComPrefix); +} + +void AnyMetadata::PackFrom(const Message& message, + const string& type_url_prefix) { type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(), - GetTypeUrl(message.GetDescriptor())); + GetTypeUrl(message.GetDescriptor(), type_url_prefix)); message.SerializeToString(value_->MutableNoArena( &::google::protobuf::internal::GetEmptyStringAlreadyInited())); } @@ -67,30 +77,20 @@ bool AnyMetadata::UnpackTo(Message* message) const { bool AnyMetadata::InternalIs(const Descriptor* descriptor) const { const string type_url = type_url_->GetNoArena( &::google::protobuf::internal::GetEmptyString()); - const string full_name = descriptor->full_name(); - if (type_url.length() < full_name.length()) { - return false; + string full_name; + if (!ParseAnyTypeUrl(type_url, &full_name)) { + return false; } - return (0 == type_url.compare( - type_url.length() - full_name.length(), - full_name.length(), - full_name)); + return full_name == descriptor->full_name(); } bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { - static const char* prefix[] = { - kTypeGoogleApisComPrefix, - kTypeGoogleProdComPrefix - }; - for (int i = 0; i < 2; i++) { - const int prefix_len = strlen(prefix[i]); - if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) { - full_type_name->assign(type_url.data() + prefix_len, - type_url.size() - prefix_len); - return true; - } + size_t pos = type_url.find_last_of("/"); + if (pos == string::npos || pos + 1 == type_url.size()) { + return false; } - return false; + *full_type_name = type_url.substr(pos + 1); + return true; } diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index c8dbef13..04e54166 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -50,10 +50,26 @@ class LIBPROTOBUF_EXPORT AnyMetadata { // AnyMetadata does not take ownership of "type_url" and "value". AnyMetadata(UrlType* type_url, ValueType* value); + // Packs a message using the default type URL prefix: "type.googleapis.com". + // The resulted type URL will be "type.googleapis.com/<message_full_name>". void PackFrom(const Message& message); - + // Packs a message using the given type URL prefix. The type URL will be + // constructed by concatenating the message type's full name to the prefix + // with an optional "/" separator if the prefix doesn't already end up "/". + // For example, both PackFrom(message, "type.googleapis.com") and + // PackFrom(message, "type.googleapis.com/") yield the same result type + // URL: "type.googleapis.com/<message_full_name>". + void PackFrom(const Message& message, const string& type_url_prefix); + + // Unpacks the payload into the given message. Returns false if the message's + // type doesn't match the type specified in the type URL (i.e., the full + // name after the last "/" of the type URL doesn't match the message's actaul + // full name) or parsing the payload has failed. bool UnpackTo(Message* message) const; + // Checks whether the type specified in the type URL matches the given type. + // A type is consdiered matching if its full name matches the full name after + // the last "/" in the type URL. template<typename T> bool Is() const { return InternalIs(T::default_instance().GetDescriptor()); diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index 0bf523b3..fbde4a6d 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\031google/protobuf/any.proto\022\017google.prot" "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002" - " \001(\014BK\n\023com.google.protobufB\010AnyProtoP\001\240" - "\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownType" - "sb\006proto3", 169); + " \001(\014Br\n\023com.google.protobufB\010AnyProtoP\001Z" + "%github.com/golang/protobuf/ptypes/any\240\001" + "\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes" + "b\006proto3", 208); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/any.proto", &protobuf_RegisterTypes); Any::default_instance_ = new Any(); @@ -116,6 +117,11 @@ void Any::PackFrom(const ::google::protobuf::Message& message) { _any_metadata_.PackFrom(message); } +void Any::PackFrom(const ::google::protobuf::Message& message, + const ::std::string& type_url_prefix) { + _any_metadata_.PackFrom(message, type_url_prefix); +} + bool Any::UnpackTo(::google::protobuf::Message* message) const { return _any_metadata_.UnpackTo(message); } @@ -190,13 +196,14 @@ Any* Any::New(::google::protobuf::Arena* arena) const { } void Any::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Any) type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool Any::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Any) for (;;) { @@ -302,6 +309,7 @@ void Any::SerializeWithCachedSizes( } int Any::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any) int total_size = 0; // optional string type_url = 1; @@ -325,18 +333,22 @@ int Any::ByteSize() const { } void Any::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Any* source = ::google::protobuf::internal::DynamicCastToGenerated<const Any>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Any) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any) MergeFrom(*source); } } void Any::MergeFrom(const Any& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.type_url().size() > 0) { @@ -349,12 +361,14 @@ void Any::MergeFrom(const Any& from) { } void Any::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Any) if (&from == this) return; Clear(); MergeFrom(from); } void Any::CopyFrom(const Any& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any) if (&from == this) return; Clear(); MergeFrom(from); @@ -417,6 +431,7 @@ void Any::clear_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Any::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -460,6 +475,7 @@ void Any::clear_value() { return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Any::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.value) return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index 97982ecf..100a67f6 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -60,6 +60,8 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message { // implements Any ----------------------------------------------- void PackFrom(const ::google::protobuf::Message& message); + void PackFrom(const ::google::protobuf::Message& message, + const ::std::string& type_url_prefix); bool UnpackTo(::google::protobuf::Message* message) const; template<typename T> bool Is() const { return _any_metadata_.Is<T>(); @@ -182,6 +184,7 @@ inline ::std::string* Any::mutable_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Any::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -225,6 +228,7 @@ inline ::std::string* Any::mutable_value() { return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Any::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.value) return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index e8a18bc3..45db6ede 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -33,14 +33,43 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; option java_package = "com.google.protobuf"; option java_outer_classname = "AnyProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; -// `Any` contains an arbitrary serialized message along with a URL -// that describes the type of the serialized message. +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". // // // JSON @@ -73,7 +102,7 @@ option objc_class_prefix = "GPB"; // message Any { // A URL/resource name whose content describes the type of the - // serialized message. + // serialized protocol buffer message. // // For URLs which use the schema `http`, `https`, or no schema, the // following restrictions and interpretations apply: @@ -81,6 +110,8 @@ message Any { // * If no schema is provided, `https` is assumed. // * The last segment of the URL's path must represent the fully // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). // * An HTTP GET on the URL must yield a [google.protobuf.Type][] // value in binary format, or produce an error. // * Applications are allowed to cache lookup results based on the @@ -94,6 +125,6 @@ message Any { // string type_url = 1; - // Must be valid serialized data of the above specified type. + // Must be a valid serialized protocol buffer of the above specified type. bytes value = 2; } diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index e589a89d..cbeba302 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -265,6 +265,7 @@ Api* Api::New(::google::protobuf::Arena* arena) const { } void Api::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Api) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; @@ -277,7 +278,7 @@ void Api::Clear() { bool Api::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Api) for (;;) { @@ -538,6 +539,7 @@ void Api::SerializeWithCachedSizes( } int Api::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api) int total_size = 0; // optional string name = 1; @@ -598,18 +600,22 @@ int Api::ByteSize() const { } void Api::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Api) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Api* source = ::google::protobuf::internal::DynamicCastToGenerated<const Api>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Api) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Api) MergeFrom(*source); } } void Api::MergeFrom(const Api& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); methods_.MergeFrom(from.methods_); options_.MergeFrom(from.options_); @@ -631,12 +637,14 @@ void Api::MergeFrom(const Api& from) { } void Api::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Api) if (&from == this) return; Clear(); MergeFrom(from); } void Api::CopyFrom(const Api& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Api) if (&from == this) return; Clear(); MergeFrom(from); @@ -704,6 +712,7 @@ void Api::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Api::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -807,6 +816,7 @@ void Api::clear_version() { return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Api::release_version() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.version) return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -841,6 +851,7 @@ const ::google::protobuf::SourceContext& Api::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Api::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -984,8 +995,17 @@ Method* Method::New(::google::protobuf::Arena* arena) const { } void Method::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Method) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(Method, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<Method*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -1005,7 +1025,7 @@ void Method::Clear() { bool Method::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Method) for (;;) { @@ -1269,6 +1289,7 @@ void Method::SerializeWithCachedSizes( } int Method::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method) int total_size = 0; // optional string name = 1; @@ -1323,18 +1344,22 @@ int Method::ByteSize() const { } void Method::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Method) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Method* source = ::google::protobuf::internal::DynamicCastToGenerated<const Method>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Method) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Method) MergeFrom(*source); } } void Method::MergeFrom(const Method& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.name().size() > 0) { @@ -1361,12 +1386,14 @@ void Method::MergeFrom(const Method& from) { } void Method::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Method) if (&from == this) return; Clear(); MergeFrom(from); } void Method::CopyFrom(const Method& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Method) if (&from == this) return; Clear(); MergeFrom(from); @@ -1434,6 +1461,7 @@ void Method::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1477,6 +1505,7 @@ void Method::clear_request_type_url() { return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_request_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url) return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1534,6 +1563,7 @@ void Method::clear_response_type_url() { return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_response_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url) return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1678,13 +1708,14 @@ Mixin* Mixin::New(::google::protobuf::Arena* arena) const { } void Mixin::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool Mixin::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Mixin) for (;;) { @@ -1802,6 +1833,7 @@ void Mixin::SerializeWithCachedSizes( } int Mixin::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin) int total_size = 0; // optional string name = 1; @@ -1825,18 +1857,22 @@ int Mixin::ByteSize() const { } void Mixin::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Mixin) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Mixin* source = ::google::protobuf::internal::DynamicCastToGenerated<const Mixin>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Mixin) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Mixin) MergeFrom(*source); } } void Mixin::MergeFrom(const Mixin& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.name().size() > 0) { @@ -1849,12 +1885,14 @@ void Mixin::MergeFrom(const Mixin& from) { } void Mixin::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Mixin) if (&from == this) return; Clear(); MergeFrom(from); } void Mixin::CopyFrom(const Mixin& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Mixin) if (&from == this) return; Clear(); MergeFrom(from); @@ -1917,6 +1955,7 @@ void Mixin::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Mixin::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1960,6 +1999,7 @@ void Mixin::clear_root() { return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Mixin::release_root() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root) return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index e1dca4e4..bb35e471 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -468,6 +468,7 @@ inline ::std::string* Api::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Api::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -571,6 +572,7 @@ inline ::std::string* Api::mutable_version() { return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Api::release_version() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.version) return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -605,6 +607,7 @@ inline ::google::protobuf::SourceContext* Api::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Api::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -699,6 +702,7 @@ inline ::std::string* Method::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -742,6 +746,7 @@ inline ::std::string* Method::mutable_request_type_url() { return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_request_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url) return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -799,6 +804,7 @@ inline ::std::string* Method::mutable_response_type_url() { return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_response_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url) return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -904,6 +910,7 @@ inline ::std::string* Mixin::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Mixin::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -947,6 +954,7 @@ inline ::std::string* Mixin::mutable_root() { return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Mixin::release_root() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root) return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index cd0b21a7..613e5897 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -30,6 +30,7 @@ #include <google/protobuf/arena.h> + #ifdef ADDRESS_SANITIZER #include <sanitizer/asan_interface.h> #endif @@ -37,6 +38,7 @@ namespace google { namespace protobuf { + google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_; #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) Arena::ThreadCache& Arena::thread_cache() { @@ -247,6 +249,19 @@ uint64 Arena::SpaceUsed() const { return space_used; } +pair<uint64, uint64> Arena::SpaceAllocatedAndUsed() const { + uint64 allocated = 0; + uint64 used = 0; + + Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_)); + while (b != NULL) { + allocated += b->size; + used += (b->pos - kHeaderSize); + b = b->next; + } + return std::make_pair(allocated, used); +} + uint64 Arena::FreeBlocks() { uint64 space_allocated = 0; Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_)); diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index 5ad94fa9..b3d66d91 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -56,6 +56,7 @@ using type_info = ::type_info; #include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/type_traits.h> + namespace google { namespace protobuf { @@ -210,7 +211,12 @@ struct ArenaOptions { // // This protocol is implemented by all arena-enabled proto2 message classes as // well as RepeatedPtrField. + +#if __cplusplus >= 201103L +class Arena final { +#else class LIBPROTOBUF_EXPORT Arena { +#endif public: // Arena constructor taking custom options. See ArenaOptions below for // descriptions of the options available. @@ -446,6 +452,10 @@ class LIBPROTOBUF_EXPORT Arena { // As above, but does not include any free space in underlying blocks. GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() const; + // Combines SpaceAllocated and SpaceUsed. Returns a pair of + // <space_allocated, space_used>. + GOOGLE_ATTRIBUTE_NOINLINE pair<uint64, uint64> SpaceAllocatedAndUsed() const; + // Frees all storage allocated by this arena after calling destructors // registered with OwnDestructor() and freeing objects registered with Own(). // Any objects allocated on this arena are unusable after this call. It also @@ -507,11 +517,11 @@ class LIBPROTOBUF_EXPORT Arena { // // This is inside Arena because only Arena has the friend relationships // necessary to see the underlying generated code traits. - template<typename T> - struct is_arena_constructable : - public google::protobuf::internal::integral_constant<bool, - sizeof(InternalIsArenaConstructableHelper::ArenaConstructable< - const T>(static_cast<const T*>(0))) == sizeof(char)> { + template <typename T> + struct is_arena_constructable + : public google::protobuf::internal::integral_constant< + bool, sizeof(InternalIsArenaConstructableHelper::ArenaConstructable< + const T>(static_cast<const T*>(0))) == sizeof(char)> { }; private: diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py index 87a69b2a..56a7dd05 100644 --- a/src/google/protobuf/arena_nc_test.py +++ b/src/google/protobuf/arena_nc_test.py @@ -35,7 +35,7 @@ import unittest from google3.testing.pybase import fake_target_util -import unittest +from google3.testing.pybase import unittest class ArenaNcTest(unittest.TestCase): diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 6b67f446..ab25ffe1 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -342,6 +342,64 @@ TEST(ArenaTest, Swap) { EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint()); } +TEST(ArenaTest, ReflectionSwapFields) { + Arena arena1; + Arena arena2; + TestAllTypes* arena1_message; + TestAllTypes* arena2_message; + + // Case 1: messages on different arenas, only one message is set. + arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2); + TestUtil::SetAllFields(arena1_message); + const Reflection* reflection = arena1_message->GetReflection(); + std::vector<const FieldDescriptor*> fields; + reflection->ListFields(*arena1_message, &fields); + reflection->SwapFields(arena1_message, arena2_message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + string output; + arena1_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(*arena2_message); + reflection->SwapFields(arena1_message, arena2_message, fields); + arena2_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(*arena1_message); + + // Case 2: messages on different arenas, both messages are set. + arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2); + TestUtil::SetAllFields(arena1_message); + TestUtil::SetAllFields(arena2_message); + reflection->SwapFields(arena1_message, arena2_message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + TestUtil::ExpectAllFieldsSet(*arena1_message); + TestUtil::ExpectAllFieldsSet(*arena2_message); + + // Case 3: messages on different arenas with different lifetimes. + arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + { + Arena arena3; + TestAllTypes* arena3_message = Arena::CreateMessage<TestAllTypes>(&arena3); + TestUtil::SetAllFields(arena3_message); + reflection->SwapFields(arena1_message, arena3_message, fields); + } + TestUtil::ExpectAllFieldsSet(*arena1_message); + + // Case 4: one message on arena, the other on heap. + arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + TestAllTypes message; + TestUtil::SetAllFields(arena1_message); + reflection->SwapFields(arena1_message, &message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(NULL, message.GetArena()); + arena1_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(message); +} + TEST(ArenaTest, SetAllocatedMessage) { Arena arena; TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena); diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h index e2e2f254..590ffce9 100755 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -134,7 +134,8 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // UnsafeArenaRelease() on another field of a message in the same arena. Used // to implement unsafe_arena_set_allocated_<field> in generated classes. inline void UnsafeArenaSetAllocated(const ::std::string* default_value, - ::std::string* value, ::google::protobuf::Arena* /* arena */) { + ::std::string* value, + ::google::protobuf::Arena* /* arena */) { if (value != NULL) { ptr_ = value; } else { diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc index 3fb582be..ea405d7d 100644 --- a/src/google/protobuf/arenastring_unittest.cc +++ b/src/google/protobuf/arenastring_unittest.cc @@ -28,9 +28,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// arenastring_unittest.cc is not open-sourced. Do not include in open-source -// distribution. - // Based on mvels@'s frankenstring. #include <google/protobuf/arenastring.h> diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 3a816b05..fcad6b61 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -46,10 +46,11 @@ #include <unistd.h> #endif #include <errno.h> +#include <fstream> #include <iostream> #include <ctype.h> -#ifdef GOOGLE_PROTOBUF_ARCH_SPARC +#ifdef GOOGLE_PROTOBUF_ARCH_SPARC #include <limits.h> //For PATH_MAX #endif @@ -948,17 +949,23 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative( return true; } + CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { executable_name_ = argv[0]; + vector<string> arguments; + for (int i = 1; i < argc; ++i) { + arguments.push_back(argv[i]); + } + // Iterate through all arguments and parse them. - for (int i = 1; i < argc; i++) { + for (int i = 0; i < arguments.size(); ++i) { string name, value; - if (ParseArgument(argv[i], &name, &value)) { + if (ParseArgument(arguments[i].c_str(), &name, &value)) { // Returned true => Use the next argument as the flag value. - if (i + 1 == argc || argv[i+1][0] == '-') { + if (i + 1 == arguments.size() || arguments[i + 1][0] == '-') { std::cerr << "Missing value for flag: " << name << std::endl; if (name == "--decode") { std::cerr << "To decode an unknown message, use --decode_raw." @@ -967,7 +974,7 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { return PARSE_ARGUMENT_FAIL; } else { ++i; - value = argv[i]; + value = arguments[i]; } } diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index f196ffc5..d1377666 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -212,6 +212,7 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Parse all command-line arguments. ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); + // Parses a command-line argument into a name/value pair. Returns // true if the next argument in the argv should be used as the value, // false otherwise. diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index dda007d4..ae2900b1 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -60,16 +60,17 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -namespace google { -namespace protobuf { -namespace compiler { // Disable the whole test when we use tcmalloc for "draconian" heap checks, in // which case tcmalloc will print warnings that fail the plugin tests. #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN +namespace google { +namespace protobuf { +namespace compiler { #if defined(_WIN32) #ifndef STDIN_FILENO @@ -376,7 +377,9 @@ void CommandLineInterfaceTest::CreateTempFile( // Write file. string full_name = temp_directory_ + "/" + name; - GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true)); + GOOGLE_CHECK_OK(File::SetContents( + full_name, StringReplace(contents, "$tmpdir", temp_directory_, true), + true)); } void CommandLineInterfaceTest::CreateTempDir(const string& name) { @@ -1090,6 +1093,7 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { } #endif // !_WIN32 + // ------------------------------------------------------------------- TEST_F(CommandLineInterfaceTest, ParseErrors) { diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 47729e1c..77451ab1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -54,6 +54,7 @@ #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 5ee6f000..c81c5982 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -69,11 +69,12 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} -void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) { +void EnumGenerator::FillForwardDeclaration( + map<string, const EnumDescriptor*>* enum_names) { if (!options_.proto_h) { return; } - enum_names->insert(classname_); + (*enum_names)[classname_] = descriptor_; } void EnumGenerator::GenerateDefinition(io::Printer* printer) { @@ -83,6 +84,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); printer->Print(vars, "enum $enumbase$ {\n"); + printer->Annotate("enumbase", descriptor_); printer->Indent(); const EnumValueDescriptor* min_value = descriptor_->value(0); @@ -96,9 +98,11 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["number"] = Int32ToString(descriptor_->value(i)->number()); vars["prefix"] = (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; + vars["deprecation"] = descriptor_->value(i)->options().deprecated() ? + " PROTOBUF_DEPRECATED" : ""; if (i > 0) printer->Print(",\n"); - printer->Print(vars, "$prefix$$name$ = $number$"); + printer->Print(vars, "$prefix$$name$$deprecation$ = $number$"); if (descriptor_->value(i)->number() < min_value->number()) { min_value = descriptor_->value(i); @@ -140,15 +144,16 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "$prefix$$short_name$_MAX + 1;\n\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"); // The _Name and _Parse methods - printer->Print(vars, - "inline const ::std::string& $classname$_Name($classname$ value) {\n" - " return ::google::protobuf::internal::NameOfEnum(\n" - " $classname$_descriptor(), value);\n" - "}\n"); + printer->Print( + vars, + "inline const ::std::string& $classname$_Name($classname$ value) {\n" + " return ::google::protobuf::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); printer->Print(vars, "inline bool $classname$_Parse(\n" " const ::std::string& name, $classname$* value) {\n" @@ -164,7 +169,7 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type " "{};\n", "classname", ClassName(descriptor_, true)); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "template <>\n" "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" @@ -183,8 +188,11 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { for (int j = 0; j < descriptor_->value_count(); j++) { vars["tag"] = EnumValueName(descriptor_->value(j)); + vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ? + "PROTOBUF_DEPRECATED_ATTR " : ""; printer->Print(vars, - "static $constexpr$const $nested_name$ $tag$ = $classname$_$tag$;\n"); + "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n" + " $classname$_$tag$;\n"); } printer->Print(vars, @@ -201,16 +209,18 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { " $classname$_$nested_name$_ARRAYSIZE;\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "static inline const ::google::protobuf::EnumDescriptor*\n" "$nested_name$_descriptor() {\n" " return $classname$_descriptor();\n" "}\n"); printer->Print(vars, - "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" - " return $classname$_Name(value);\n" - "}\n"); + "static inline const ::std::string& " + "$nested_name$_Name($nested_name$ value) {" + "\n" + " return $classname$_Name(value);\n" + "}\n"); printer->Print(vars, "static inline bool $nested_name$_Parse(const ::std::string& name,\n" " $nested_name$* value) {\n" @@ -240,7 +250,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { vars["classname"] = classname_; vars["constexpr"] = options_.proto_h ? "constexpr " : ""; - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" " protobuf_AssignDescriptorsOnce();\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index f3aa72e4..90edf001 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -35,12 +35,12 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#include <map> #include <set> #include <string> #include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> - namespace google { namespace protobuf { namespace io { @@ -55,8 +55,7 @@ namespace cpp { class EnumGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit EnumGenerator(const EnumDescriptor* descriptor, - const Options& options); + EnumGenerator(const EnumDescriptor* descriptor, const Options& options); ~EnumGenerator(); // Header stuff. @@ -64,8 +63,10 @@ class EnumGenerator { // Fills the name to use when declaring the enum. This is for use when // generating other .proto.h files. This code should be placed within the // enum's package namespace, but NOT within any class, even for nested - // enums. - void FillForwardDeclaration(set<string>* enum_names); + // enums. A given key in enum_names will map from an enum class name to the + // EnumDescriptor that was responsible for its inclusion in the map. This can + // be used to associate the descriptor with the code generated for it. + void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for @@ -94,10 +95,10 @@ class EnumGenerator { private: const EnumDescriptor* descriptor_; - string classname_; - Options options_; + const string classname_; + const Options& options_; // whether to generate the *_ARRAYSIZE constant. - bool generate_array_size_; + const bool generate_array_size_; 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 824e2205..10252b39 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -36,6 +36,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/wire_format.h> namespace google { namespace protobuf { @@ -58,10 +59,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // =================================================================== -EnumFieldGenerator:: -EnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetEnumVariables(descriptor, &variables_, options); } @@ -75,8 +75,8 @@ GeneratePrivateMembers(io::Printer* printer) const { void EnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$() const$deprecation$;\n" - "void set_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$() const;\n" + "$deprecated_attr$void set_$name$($type$ value);\n"); } void EnumFieldGenerator:: @@ -135,15 +135,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "if ($type$_IsValid(value)) {\n" " set_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "} else {\n" " mutable_unknown_fields()->AddVarint($number$, value);\n"); } else { printer->Print( "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(value);\n"); + " unknown_fields_stream.WriteVarint32($tag$);\n" + " unknown_fields_stream.WriteVarint32(value);\n", + "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_))); } printer->Print(variables_, "}\n"); @@ -228,10 +229,9 @@ GenerateConstructorCode(io::Printer* printer) const { // =================================================================== -RepeatedEnumFieldGenerator:: -RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetEnumVariables(descriptor, &variables_, options); } @@ -241,8 +241,8 @@ void RepeatedEnumFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField<int> $name$_;\n"); - if (descriptor_->is_packed() - && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -251,12 +251,12 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$(int index) const$deprecation$;\n" - "void set_$name$(int index, $type$ value)$deprecation$;\n" - "void add_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$(int index) const;\n" + "$deprecated_attr$void set_$name$(int index, $type$ value);\n" + "$deprecated_attr$void add_$name$($type$ value);\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" - "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n" + "$deprecated_attr$::google::protobuf::RepeatedField<int>* mutable_$name$();\n"); } void RepeatedEnumFieldGenerator:: @@ -335,7 +335,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "} else {\n" " mutable_unknown_fields()->AddVarint($number$, value);\n"); @@ -362,7 +362,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { " NULL,\n" " NULL,\n" " this->mutable_$name$())));\n"); - } else if (UseUnknownFieldSet(descriptor_->file())) { + } else if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n" " input,\n" @@ -399,7 +399,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { " if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" " } else {\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, " mutable_unknown_fields()->AddVarint($number$, value);\n"); } else { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 5b1d01ea..fe21c575 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -46,8 +46,7 @@ namespace cpp { class EnumFieldGenerator : public FieldGenerator { public: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); ~EnumFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -74,8 +73,8 @@ class EnumFieldGenerator : public FieldGenerator { class EnumOneofFieldGenerator : public EnumFieldGenerator { public: - explicit EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~EnumOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -91,8 +90,8 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator { class RepeatedEnumFieldGenerator : public FieldGenerator { public: - explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedEnumFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 8d47d4e0..b3ba3a2e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -77,6 +77,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, WireFormat::TagSize(descriptor->number(), descriptor->type())); (*variables)["deprecation"] = descriptor->options().deprecated() ? " PROTOBUF_DEPRECATED" : ""; + (*variables)["deprecated_attr"] = descriptor->options().deprecated() + ? "PROTOBUF_DEPRECATED_ATTR " : ""; (*variables)["cppget"] = "Get"; @@ -121,6 +123,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Options& options) : descriptor_(descriptor), + options_(options), field_generators_( new google::protobuf::scoped_ptr<FieldGenerator>[descriptor->field_count()]) { // Construct all the FieldGenerators. diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 1d7f8233..3b012527 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -69,7 +69,7 @@ void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, class FieldGenerator { public: - FieldGenerator() {} + explicit FieldGenerator(const Options& options) : options_(options) {} virtual ~FieldGenerator(); // Generate lines of code declaring members fields of the message class @@ -194,6 +194,9 @@ class FieldGenerator { // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; + protected: + const Options& options_; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); }; @@ -201,13 +204,14 @@ class FieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options); + FieldGeneratorMap(const Descriptor* descriptor, const Options& options); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; private: const Descriptor* descriptor_; + const Options& options_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGenerator> > field_generators_; static FieldGenerator* MakeGenerator(const FieldDescriptor* field, diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 37e4bae4..385b973e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -59,6 +59,7 @@ namespace cpp { FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), + options_(options), message_generators_( new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]), enum_generators_( @@ -66,8 +67,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) service_generators_( new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]), extension_generators_( - new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]), - options_(options) { + new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) { for (int i = 0; i < file->message_type_count(); i++) { message_generators_[i].reset( @@ -94,7 +94,8 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateProtoHeader(io::Printer* printer) { +void FileGenerator::GenerateProtoHeader(io::Printer* printer, + const string& info_path) { if (!options_.proto_h) { return; } @@ -114,6 +115,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) { "dependency", dependency); } + GenerateMetadataPragma(printer, info_path); + printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -167,7 +170,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) { GenerateBottomHeaderGuard(printer, filename_identifier); } -void FileGenerator::GeneratePBHeader(io::Printer* printer) { +void FileGenerator::GeneratePBHeader(io::Printer* printer, + const string& info_path) { string filename_identifier = FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); GenerateTopHeaderGuard(printer, filename_identifier); @@ -179,6 +183,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { GenerateLibraryIncludes(printer); } GenerateDependencyIncludes(printer); + GenerateMetadataPragma(printer, info_path); printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -237,7 +242,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { } void FileGenerator::GenerateSource(io::Printer* printer) { - bool well_known = IsWellKnownMessage(file_); + const bool use_system_include = IsWellKnownMessage(file_); string header = StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( @@ -258,16 +263,16 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), "header", header, - "left", well_known ? "<" : "\"", - "right", well_known ? ">" : "\""); + "left", use_system_include ? "<" : "\"", + "right", use_system_include ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream - if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + if (!UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { printer->Print( "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n"); } - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include <google/protobuf/descriptor.h>\n" "#include <google/protobuf/generated_message_reflection.h>\n" @@ -292,7 +297,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { GenerateNamespaceOpeners(printer); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" @@ -306,7 +311,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "name", ClassName(file_->enum_type(i), false)); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { for (int i = 0; i < file_->service_count(); i++) { printer->Print( "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", @@ -331,7 +336,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // Generate classes. for (int i = 0; i < file_->message_type_count(); i++) { - if (i == 0 && HasGeneratedMethods(file_)) { + if (i == 0 && HasGeneratedMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" @@ -356,7 +361,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n"); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < file_->service_count(); i++) { if (i == 0) printer->Print("\n"); @@ -401,20 +406,24 @@ class FileGenerator::ForwardDeclarations { return ns; } - set<string>& classes() { return classes_; } - set<string>& enums() { return enums_; } + map<string, const Descriptor*>& classes() { return classes_; } + map<string, const EnumDescriptor*>& enums() { return enums_; } void Print(io::Printer* printer) const { - for (set<string>::const_iterator it = enums_.begin(), end = enums_.end(); + for (map<string, const EnumDescriptor *>::const_iterator + it = enums_.begin(), + end = enums_.end(); it != end; ++it) { - printer->Print("enum $enumname$ : int;\n" - "bool $enumname$_IsValid(int value);\n", - "enumname", it->c_str()); + printer->Print("enum $enumname$ : int;\n", "enumname", it->first); + printer->Annotate("enumname", it->second); + printer->Print("bool $enumname$_IsValid(int value);\n", "enumname", + it->first); } - for (set<string>::const_iterator it = classes_.begin(), - end = classes_.end(); + for (map<string, const Descriptor *>::const_iterator it = classes_.begin(), + end = classes_.end(); it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->c_str()); + printer->Print("class $classname$;\n", "classname", it->first); + printer->Annotate("classname", it->second); } for (map<string, ForwardDeclarations *>::const_iterator it = namespaces_.begin(), @@ -431,8 +440,8 @@ class FileGenerator::ForwardDeclarations { private: map<string, ForwardDeclarations*> namespaces_; - set<string> classes_; - set<string> enums_; + map<string, const Descriptor*> classes_; + map<string, const EnumDescriptor*> enums_; }; void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { @@ -453,7 +462,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_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "void $assigndescriptorsname$() {\n", @@ -486,7 +495,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { for (int i = 0; i < file_->service_count(); i++) { service_generators_[i]->GenerateDescriptorInitializer(printer, i); } @@ -552,22 +561,23 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // Now generate the AddDescriptors() function. PrintHandlingOptionalStaticInitializers( - file_, 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$() {\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" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n", - // Vars. - "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + 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$() {\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" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", + // Vars. + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); printer->Indent(); @@ -584,7 +594,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "name", add_desc_name); } - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { // 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. @@ -678,23 +688,23 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "\n"); PrintHandlingOptionalStaticInitializers( - file_, printer, - // With static initializers. - "// Force AddDescriptors() to be called at static initialization time.\n" - "struct StaticDescriptorInitializer_$filename$ {\n" - " StaticDescriptorInitializer_$filename$() {\n" - " $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())); + file_, options_, printer, + // With static initializers. + "// Force AddDescriptors() to be called at static initialization time.\n" + "struct StaticDescriptorInitializer_$filename$ {\n" + " StaticDescriptorInitializer_$filename$() {\n" + " $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())); } void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { @@ -751,16 +761,15 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, const string& filename_identifier) { // Generate top of header. printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" - "#define PROTOBUF_$filename_identifier$__INCLUDED\n" - "\n" - "#include <string>\n" - "\n", - "filename", file_->name(), - "filename_identifier", filename_identifier); + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" + "#define PROTOBUF_$filename_identifier$__INCLUDED\n" + "\n" + "#include <string>\n", + "filename", file_->name(), "filename_identifier", filename_identifier); + printer->Print("\n"); } void FileGenerator::GenerateBottomHeaderGuard( @@ -799,12 +808,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include <google/protobuf/arena.h>\n" "#include <google/protobuf/arenastring.h>\n" "#include <google/protobuf/generated_message_util.h>\n"); - if (UseUnknownFieldSet(file_)) { + if (UseUnknownFieldSet(file_, options_)) { printer->Print( "#include <google/protobuf/metadata.h>\n"); } if (file_->message_type_count() > 0) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include <google/protobuf/message.h>\n"); } else { @@ -818,7 +827,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (HasMapFields(file_)) { printer->Print( "#include <google/protobuf/map.h>\n"); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include <google/protobuf/map_field_inl.h>\n"); } else { @@ -828,7 +837,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } if (HasEnumDefinitions(file_)) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include <google/protobuf/generated_enum_reflection.h>\n"); } else { @@ -837,12 +846,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { printer->Print( "#include <google/protobuf/service.h>\n"); } - if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + if (UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { printer->Print( "#include <google/protobuf/unknown_field_set.h>\n"); } @@ -854,6 +863,19 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } } +void FileGenerator::GenerateMetadataPragma(io::Printer* printer, + const string& info_path) { + if (!info_path.empty() && !options_.annotation_pragma_name.empty() && + !options_.annotation_guard_name.empty()) { + printer->Print( + "#ifdef $guard$\n" + "#pragma $pragma$ \"$info_path$\"\n" + "#endif // $guard$\n", + "guard", options_.annotation_guard_name, "pragma", + options_.annotation_pragma_name, "info_path", info_path); + } +} + void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { set<string> public_import_names; for (int i = 0; i < file_->public_dependency_count(); i++) { @@ -861,16 +883,17 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { } for (int i = 0; i < file_->dependency_count(); i++) { - bool well_known = IsWellKnownMessage(file_->dependency(i)); + const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); + printer->Print( "#include $left$$dependency$.pb.h$right$$iwyu$\n", "dependency", StripProto(name), "iwyu", (public_import) ? " // IWYU pragma: export" : "", - "left", well_known ? "<" : "\"", - "right", well_known ? ">" : "\""); + "left", use_system_include ? "<" : "\"", + "right", use_system_include ? ">" : "\""); } } @@ -897,13 +920,15 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( } void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - set<string> classes; + map<string, const Descriptor*> classes; for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->FillMessageForwardDeclarations(&classes); } - for (set<string>::const_iterator it = classes.begin(), end = classes.end(); + for (map<string, const Descriptor *>::const_iterator it = classes.begin(), + end = classes.end(); it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->c_str()); + printer->Print("class $classname$;\n", "classname", it->first); + printer->Annotate("classname", it->second); } } @@ -930,7 +955,7 @@ void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { } void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { // Generate service definitions. for (int i = 0; i < file_->service_count(); i++) { if (i > 0) { diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 29cdaea5..5dcf692b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -65,12 +65,17 @@ class ExtensionGenerator; // extension.h class FileGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit FileGenerator(const FileDescriptor* file, - const Options& options); + FileGenerator(const FileDescriptor* file, const Options& options); ~FileGenerator(); - void GenerateProtoHeader(io::Printer* printer); - void GeneratePBHeader(io::Printer* printer); + // info_path, if non-empty, should be the path (relative to printer's output) + // to the metadata file describing this proto header. + void GenerateProtoHeader(io::Printer* printer, + const string& info_path); + // info_path, if non-empty, should be the path (relative to printer's output) + // to the metadata file describing this PB header. + void GeneratePBHeader(io::Printer* printer, + const string& info_path); void GenerateSource(io::Printer* printer); private: @@ -102,6 +107,10 @@ class FileGenerator { void GenerateLibraryIncludes(io::Printer* printer); void GenerateDependencyIncludes(io::Printer* printer); + // Generate a pragma to pull in metadata using the given info_path (if + // non-empty). info_path should be relative to printer's output. + void GenerateMetadataPragma(io::Printer* printer, const string& info_path); + // Generates a couple of different pieces before definitions: void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); @@ -134,6 +143,7 @@ class FileGenerator { void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); const FileDescriptor* file_; + const Options options_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; @@ -142,7 +152,6 @@ class FileGenerator { // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. vector<string> package_parts_; - 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 781526b5..31d189c2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -90,6 +90,14 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.dllexport_decl = options[i].second; } else if (options[i].first == "safe_boundary_check") { file_options.safe_boundary_check = true; + } else if (options[i].first == "annotate_headers") { + file_options.annotate_headers = true; + } else if (options[i].first == "annotation_pragma_name") { + file_options.annotation_pragma_name = options[i].second; + } else if (options[i].first == "annotation_guard_name") { + file_options.annotation_guard_name = options[i].second; + } else if (options[i].first == "lite") { + file_options.enforce_lite = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -107,16 +115,40 @@ bool CppGenerator::Generate(const FileDescriptor* file, if (file_options.proto_h) { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".proto.h")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateProtoHeader(&printer); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + string info_path = basename + ".proto.h.meta"; + io::Printer printer(output.get(), '$', file_options.annotate_headers + ? &annotation_collector + : NULL); + file_generator.GenerateProtoHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } } basename.append(".pb"); { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".h")); - io::Printer printer(output.get(), '$'); - file_generator.GeneratePBHeader(&printer); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( + &annotations); + string info_path = basename + ".h.meta"; + io::Printer printer(output.get(), '$', file_options.annotate_headers + ? &annotation_collector + : NULL); + file_generator.GeneratePBHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } } // Generate cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index fb46e387..2ad4d36a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -68,14 +68,15 @@ const char* const kKeywordList[] = { "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "class", "compl", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", - "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", - "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", - "or_eq", "private", "protected", "public", "register", "reinterpret_cast", - "return", "short", "signed", "sizeof", "static", "static_assert", - "static_cast", "struct", "switch", "template", "this", "thread_local", - "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", - "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" + "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", + "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", + "mutable", "namespace", "new", "noexcept", "not", "not_eq", "NULL", + "operator", "or", "or_eq", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", + "static_assert", "static_cast", "struct", "switch", "template", "this", + "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", + "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", + "while", "xor", "xor_eq" }; hash_set<string> MakeKeywordsMap() { @@ -171,9 +172,10 @@ string DependentBaseClassTemplateName(const Descriptor* descriptor) { return ClassName(descriptor, false) + "_InternalBase"; } -string SuperClassName(const Descriptor* descriptor) { - return HasDescriptorMethods(descriptor->file()) ? - "::google::protobuf::Message" : "::google::protobuf::MessageLite"; +string SuperClassName(const Descriptor* descriptor, const Options& options) { + return HasDescriptorMethods(descriptor->file(), options) + ? "::google::protobuf::Message" + : "::google::protobuf::MessageLite"; } string DependentBaseDownCast() { @@ -485,8 +487,9 @@ string SafeFunctionName(const Descriptor* descriptor, return function_name; } -bool StaticInitializersForced(const FileDescriptor* file) { - if (HasDescriptorMethods(file) || file->extension_count() > 0) { +bool StaticInitializersForced(const FileDescriptor* file, + const Options& options) { + if (HasDescriptorMethods(file, options) || file->extension_count() > 0) { return true; } for (int i = 0; i < file->message_type_count(); ++i) { @@ -498,10 +501,10 @@ bool StaticInitializersForced(const FileDescriptor* file) { } void PrintHandlingOptionalStaticInitializers( - const FileDescriptor* file, io::Printer* printer, + 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) { + const char* var1, const string& val1, const char* var2, + const string& val2) { map<string, string> vars; if (var1) { vars[var1] = val1; @@ -510,14 +513,16 @@ void PrintHandlingOptionalStaticInitializers( vars[var2] = val2; } PrintHandlingOptionalStaticInitializers( - vars, file, printer, with_static_init, without_static_init); + vars, file, options, printer, with_static_init, without_static_init); } -void PrintHandlingOptionalStaticInitializers( - const map<string, string>& vars, const FileDescriptor* file, - io::Printer* printer, const char* with_static_init, - const char* without_static_init) { - if (StaticInitializersForced(file)) { +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( @@ -612,10 +617,11 @@ enum Utf8CheckMode { }; // Which level of UTF-8 enforcemant is placed on this file. -static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { +static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, + const Options& options) { if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { return STRICT; - } else if (field->file()->options().optimize_for() != + } else if (GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME) { return VERIFY; } else { @@ -624,13 +630,13 @@ static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { } static void GenerateUtf8CheckCode(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map<string, string>& variables, const char* parameters, const char* strict_function, const char* verify_function, io::Printer* printer) { - switch (GetUtf8CheckMode(field)) { + switch (GetUtf8CheckMode(field, options)) { case STRICT: { if (for_parse) { printer->Print("DO_("); @@ -674,23 +680,22 @@ static void GenerateUtf8CheckCode(const FieldDescriptor* field, } void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map<string, string>& variables, const char* parameters, io::Printer* printer) { - GenerateUtf8CheckCode(field, for_parse, variables, parameters, + GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, "VerifyUtf8String", "VerifyUTF8StringNamedField", printer); } void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map<string, string>& variables, const char* parameters, io::Printer* printer) { - GenerateUtf8CheckCode(field, for_parse, variables, parameters, - "VerifyUtf8Cord", "VerifyUTF8CordNamedField", - printer); + GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, + "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index a22d414d..018acfca 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -37,8 +37,9 @@ #include <map> #include <string> -#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> namespace google { namespace protobuf { @@ -72,7 +73,7 @@ string DependentBaseClassTemplateName(const Descriptor* descriptor); // Name of the base class: either the dependent base class (for use with // proto_h) or google::protobuf::Message. -string SuperClassName(const Descriptor* descriptor); +string SuperClassName(const Descriptor* descriptor, const Options& options); // Returns a string that down-casts from the dependent base class to the // derived class. @@ -118,7 +119,7 @@ string DependentTypeName(const FieldDescriptor* field); string FieldMessageTypeName(const FieldDescriptor* field); // Strips ".proto" or ".protodevel" from the end of a filename. -string StripProto(const string& filename); +LIBPROTOC_EXPORT string StripProto(const string& filename); // Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). // Note: non-built-in type names will be qualified, meaning they will start @@ -168,12 +169,17 @@ inline bool PreserveUnknownFields(const Descriptor* message) { return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } +// Returns the optimize mode for <file>, respecting <options.enforce_lite>. +::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( + const FileDescriptor* file, const Options& options); + // If PreserveUnknownFields() is true, determines whether unknown // fields will be stored in an UnknownFieldSet or a string. // If PreserveUnknownFields() is false, this method will not be // used. -inline bool UseUnknownFieldSet(const FileDescriptor* file) { - return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +inline bool UseUnknownFieldSet(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; } @@ -186,45 +192,52 @@ 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) { - return file->options().optimize_for() != FileOptions::CODE_SIZE; +inline bool HasGeneratedMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE; } // 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; +inline bool HasDescriptorMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; } // Should we generate generic services for this file? -inline bool HasGenericServices(const FileDescriptor* file) { +inline bool HasGenericServices(const FileDescriptor* file, + const Options& options) { return file->service_count() > 0 && - file->options().optimize_for() != FileOptions::LITE_RUNTIME && + GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME && file->options().cc_generic_services(); } // Should we generate a separate, super-optimized code path for serializing to // flat arrays? We don't do this in Lite mode because we'd rather reduce code // size. -inline bool HasFastArraySerialization(const FileDescriptor* file) { - return file->options().optimize_for() == FileOptions::SPEED; +inline bool HasFastArraySerialization(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) == FileOptions::SPEED; } // Returns whether we have to generate code with static initializers. -bool StaticInitializersForced(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, io::Printer* printer, + 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 = ""); + const char* var1 = NULL, const string& val1 = "", const char* var2 = NULL, + const string& val2 = ""); -void PrintHandlingOptionalStaticInitializers( - const map<string, string>& vars, const FileDescriptor* file, - io::Printer* printer, const char* with_static_init, - const char* 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); inline bool IsMapEntryMessage(const Descriptor* descriptor) { @@ -267,19 +280,23 @@ bool IsAnyMessage(const Descriptor* descriptor); bool IsWellKnownMessage(const FileDescriptor* descriptor); -void GenerateUtf8CheckCodeForString( - const FieldDescriptor* field, - bool for_parse, - const map<string, string>& variables, - const char* parameters, - io::Printer* printer); - -void GenerateUtf8CheckCodeForCord( - const FieldDescriptor* field, - bool for_parse, - const map<string, string>& variables, - const char* parameters, - io::Printer* printer); +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const map<string, string>& variables, + const char* parameters, + io::Printer* printer); + +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const map<string, string>& variables, + const char* parameters, io::Printer* printer); + +inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( + const FileDescriptor* file, const Options& options) { + return options.enforce_lite + ? FileOptions::LITE_RUNTIME + : file->options().optimize_for(); +} } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index e5e2f07d..f585c31b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -49,10 +49,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); - (*variables)["stream_writer"] = (*variables)["declared_type"] + - (HasFastArraySerialization(descriptor->message_type()->file()) ? - "MaybeToArray" : - ""); + (*variables)["stream_writer"] = + (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file(), options) + ? "MaybeToArray" + : ""); (*variables)["full_name"] = descriptor->full_name(); const FieldDescriptor* key = @@ -83,7 +84,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - if (HasDescriptorMethods(descriptor->file())) { + if (HasDescriptorMethods(descriptor->file(), options)) { (*variables)["lite"] = ""; } else { (*variables)["lite"] = "Lite"; @@ -98,10 +99,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } } -MapFieldGenerator:: -MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -127,10 +128,10 @@ GeneratePrivateMembers(io::Printer* printer) const { void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" - " $name$() const$deprecation$;\n" - "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" + " $name$() const;\n" + "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" + " mutable_$name$();\n"); } void MapFieldGenerator:: @@ -170,7 +171,7 @@ GenerateSwappingCode(io::Printer* printer) const { void MapFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(variables_, "$name$_.SetAssignDescriptorCallback(\n" " protobuf_AssignDescriptorsOnce);\n" @@ -217,7 +218,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " (*mutable_$name$())[entry->key()] =\n" " static_cast< $val_cpp$ >(*entry->mutable_value());\n" " } else {\n"); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(variables_, " mutable_unknown_fields()" "->AddLengthDelimited($number$, data);\n"); @@ -238,14 +239,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { descriptor_->message_type()->FindFieldByName("key"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - key_field, true, variables_, + key_field, options_, true, variables_, "entry->key().data(), entry->key().length(),\n", printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, true, variables_, - "entry->mutable_value()->data(),\n" - "entry->mutable_value()->length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, true, variables_, + "entry->mutable_value()->data(),\n" + "entry->mutable_value()->length(),\n", + printer); } // If entry is allocated by arena, its desctructor should be avoided. @@ -285,14 +286,14 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { const FieldDescriptor* value_field = descriptor_->message_type()->FindFieldByName("value"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - key_field, false, variables_, - "it->first.data(), it->first.length(),\n", printer); + GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, + "it->first.data(), it->first.length(),\n", + printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, false, variables_, - "it->second.data(), it->second.length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, + "it->second.data(), it->second.length(),\n", + printer); } printer->Outdent(); @@ -343,14 +344,14 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { const FieldDescriptor* value_field = descriptor_->message_type()->FindFieldByName("value"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - key_field, false, variables_, - "it->first.data(), it->first.length(),\n", printer); + GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, + "it->first.data(), it->first.length(),\n", + printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, false, variables_, - "it->second.data(), it->second.length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, + "it->second.data(), it->second.length(),\n", + printer); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 5e205623..087dcde0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -43,8 +43,7 @@ namespace cpp { class MapFieldGenerator : public FieldGenerator { public: - explicit MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); ~MapFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 8304ebbd..da2a4c92 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -106,8 +106,8 @@ struct ExtensionRangeSorter { // Returns true if the "required" restriction check should be ignored for the // given field. -inline static bool ShouldIgnoreRequiredFieldCheck( - const FieldDescriptor* field) { +inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, + const Options& options) { return false; } @@ -116,9 +116,8 @@ inline static bool ShouldIgnoreRequiredFieldCheck( // // already_seen is used to avoid checking the same type multiple times // (and also to protect against recursion). -static bool HasRequiredFields( - const Descriptor* type, - hash_set<const Descriptor*>* already_seen) { +static bool HasRequiredFields(const Descriptor* type, const Options& options, + hash_set<const Descriptor*>* already_seen) { if (already_seen->count(type) > 0) { // Since the first occurrence of a required field causes the whole // function to return true, we can assume that if the type is already @@ -138,8 +137,8 @@ static bool HasRequiredFields( return true; } if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !ShouldIgnoreRequiredFieldCheck(field)) { - if (HasRequiredFields(field->message_type(), already_seen)) { + !ShouldIgnoreRequiredFieldCheck(field, options)) { + if (HasRequiredFields(field->message_type(), options, already_seen)) { return true; } } @@ -148,9 +147,9 @@ static bool HasRequiredFields( return false; } -static bool HasRequiredFields(const Descriptor* type) { +static bool HasRequiredFields(const Descriptor* type, const Options& options) { hash_set<const Descriptor*> already_seen; - return HasRequiredFields(type, &already_seen); + return HasRequiredFields(type, options, &already_seen); } // This returns an estimate of the compiler's alignment for the field. This @@ -423,8 +422,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -FillMessageForwardDeclarations(set<string>* class_names) { - class_names->insert(classname_); +FillMessageForwardDeclarations(map<string, const Descriptor*>* class_names) { + (*class_names)[classname_] = descriptor_; for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need forward declaration. Since map entry @@ -436,7 +435,7 @@ FillMessageForwardDeclarations(set<string>* class_names) { } void MessageGenerator:: -FillEnumForwardDeclarations(set<string>* enum_names) { +FillEnumForwardDeclarations(map<string, const EnumDescriptor*>* enum_names) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->FillEnumForwardDeclarations(enum_names); } @@ -480,7 +479,7 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { // If the message is dependent, the inline clear_*() method will need // to delete the message type, so it must be in the dependent base // class. (See also GenerateFieldAccessorDeclarations.) - printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$void clear_$name$();\n"); } // Generate type-specific accessor declarations. field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); @@ -515,22 +514,24 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (field->is_repeated()) { - printer->Print(vars, "int $name$_size() const$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n"); } else if (HasHasMethod(field)) { - printer->Print(vars, "bool has_$name$() const$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n"); } else if (HasPrivateHasMethod(field)) { printer->Print(vars, "private:\n" - "bool has_$name$() const$deprecation$;\n" + "bool has_$name$() const;\n" "public:\n"); } if (!dependent_field) { // If this field is dependent, then its clear_() method is in the // depenent base class. (See also GenerateDependentAccessorDeclarations.) - printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$void clear_$name$();\n"); } - printer->Print(vars, "static const int $constant_name$ = $number$;\n"); + printer->Print(vars, + "$deprecated_attr$static const int $constant_name$ = " + "$number$;\n"); // Generate type-specific accessor declarations. field_generators_.get(field).GenerateAccessorDeclarations(printer); @@ -837,7 +838,7 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) { map<string, string> vars; vars["classname"] = DependentBaseClassTemplateName(descriptor_); - vars["superclass"] = SuperClassName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_, options_); printer->Print(vars, "template <class T>\n" @@ -888,10 +889,11 @@ GenerateClassDefinition(io::Printer* printer) { vars["superclass"] = DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - vars["superclass"] = SuperClassName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_, options_); } printer->Print(vars, "class $dllexport$$classname$ : public $superclass$ {\n"); + printer->Annotate("classname", descriptor_); if (use_dependent_base_) { printer->Print(vars, " friend class $superclass$;\n"); } @@ -911,7 +913,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" " return _internal_metadata_.unknown_fields();\n" @@ -965,7 +967,7 @@ GenerateClassDefinition(io::Printer* printer) { } // Only generate this member if it's not disabled. - if (HasDescriptorMethods(descriptor_->file()) && + if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print(vars, "static const ::google::protobuf::Descriptor* descriptor();\n"); @@ -1002,7 +1004,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (!StaticInitializersForced(descriptor_->file())) { + 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" @@ -1027,6 +1029,8 @@ GenerateClassDefinition(io::Printer* printer) { "// implements Any -----------------------------------------------\n" "\n" "void PackFrom(const ::google::protobuf::Message& message);\n" + "void PackFrom(const ::google::protobuf::Message& message,\n" + " const ::std::string& type_url_prefix);\n" "bool UnpackTo(::google::protobuf::Message* message) const;\n" "template<typename T> bool Is() const {\n" " return _any_metadata_.Is<T>();\n" @@ -1043,8 +1047,8 @@ GenerateClassDefinition(io::Printer* printer) { "\n" "$classname$* New(::google::protobuf::Arena* arena) const;\n"); - if (HasGeneratedMethods(descriptor_->file())) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "void CopyFrom(const ::google::protobuf::Message& from);\n" "void MergeFrom(const ::google::protobuf::Message& from);\n"); @@ -1066,11 +1070,11 @@ GenerateClassDefinition(io::Printer* printer) { " ::google::protobuf::io::CodedOutputStream* output) const;\n"); // DiscardUnknownFields() is implemented in message.cc using reflections. We // need to implement this function in generated code for messages. - if (!UseUnknownFieldSet(descriptor_->file())) { + if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "void DiscardUnknownFields();\n"); } - if (HasFastArraySerialization(descriptor_->file())) { + if (HasFastArraySerialization(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n"); } @@ -1093,7 +1097,7 @@ GenerateClassDefinition(io::Printer* printer) { } uses_string_ = false; if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { uses_string_ = true; } for (int i = 0; i < descriptors.size(); i++) { @@ -1123,7 +1127,7 @@ GenerateClassDefinition(io::Printer* printer) { "classname", classname_); } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "private:\n" "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" @@ -1147,7 +1151,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata GetMetadata() const;\n" "\n"); @@ -1236,7 +1240,7 @@ GenerateClassDefinition(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - if (HasGeneratedMethods(descriptor_->file()) && + if (HasGeneratedMethods(descriptor_->file(), options_) && !descriptor_->options().message_set_wire_format() && num_required_fields_ > 1) { printer->Print( @@ -1278,7 +1282,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { @@ -1405,15 +1409,14 @@ GenerateClassDefinition(io::Printer* printer) { // friends so that they can access private static variables like // default_instance_ and reflection_. PrintHandlingOptionalStaticInitializers( - descriptor_->file(), 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())); + 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 $assigndescriptorsname$();\n" @@ -1576,7 +1579,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { // Unknown field offset: either points to the unknown field set if embedded // directly, or indicates that the unknown field set is stored as part of the // internal metadata if not. - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, " -1,\n"); } else { @@ -1616,7 +1619,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { // arena pointer and unknown field set (in a space-efficient way) if we use // that implementation strategy, or an offset directly to the arena pointer if // not (because e.g. we don't have an unknown field set). - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" "$classname$, _internal_metadata_),\n"); @@ -1706,7 +1709,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { "classname", classname_); if ((descriptor_->oneof_decl_count() > 0) && - HasDescriptorMethods(descriptor_->file())) { + HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n", "classname", classname_); @@ -1746,7 +1749,7 @@ GenerateShutdownCode(io::Printer* printer) { "delete $classname$::default_instance_;\n", "classname", classname_); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { if (descriptor_->oneof_decl_count() > 0) { printer->Print( "delete $classname$_default_oneof_instance_;\n", @@ -1774,7 +1777,8 @@ void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { // mutable_unknown_fields wrapper function for LazyStringOutputStream // callback. - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "static ::std::string* MutableUnknownFieldsFor$classname$(\n" " $classname$* ptr) {\n" @@ -1789,6 +1793,11 @@ GenerateClassMethods(io::Printer* printer) { " _any_metadata_.PackFrom(message);\n" "}\n" "\n" + "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n" + " const ::std::string& type_url_prefix) {\n" + " _any_metadata_.PackFrom(message, type_url_prefix);\n" + "}\n" + "\n" "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" " return _any_metadata_.UnpackTo(message);\n" "}\n" @@ -1843,7 +1852,7 @@ GenerateClassMethods(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { GenerateClear(printer); printer->Print("\n"); @@ -1853,7 +1862,7 @@ GenerateClassMethods(io::Printer* printer) { GenerateSerializeWithCachedSizes(printer); printer->Print("\n"); - if (HasFastArraySerialization(descriptor_->file())) { + if (HasFastArraySerialization(descriptor_->file(), options_)) { GenerateSerializeWithCachedSizesToArray(printer); printer->Print("\n"); } @@ -1874,7 +1883,7 @@ GenerateClassMethods(io::Printer* printer) { GenerateSwap(printer); printer->Print("\n"); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" " protobuf_AssignDescriptorsOnce();\n" @@ -1899,11 +1908,10 @@ GenerateClassMethods(io::Printer* printer) { void MessageGenerator:: GenerateOffsets(io::Printer* printer) { - printer->Print( - "static const int $classname$_offsets_[$field_count$] = {\n", - "classname", classname_, - "field_count", SimpleItoa(max( - 1, descriptor_->field_count() + descriptor_->oneof_decl_count()))); + printer->Print("static const int $classname$_offsets_[$field_count$] = {\n", + "classname", classname_, "field_count", + SimpleItoa(std::max(1, descriptor_->field_count() + + descriptor_->oneof_decl_count()))); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1952,7 +1960,7 @@ GenerateSharedConstructorCode(io::Printer* printer) { "_cached_size_ = 0;\n").c_str()); if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "_unknown_fields_.UnsafeSetDefault(\n" " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); @@ -1997,7 +2005,7 @@ GenerateSharedDestructorCode(io::Printer* printer) { // Write the desctructor for _unknown_fields_ in lite runtime. if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { if (SupportsArenas(descriptor_)) { printer->Print( "_unknown_fields_.Destroy(\n" @@ -2028,11 +2036,11 @@ GenerateSharedDestructorCode(io::Printer* printer) { } PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - "if (this != default_instance_) {\n", - // Without. - "if (this != &default_instance()) {\n"); + 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 @@ -2112,7 +2120,7 @@ GenerateStructors(io::Printer* printer) { superclass = DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - superclass = SuperClassName(descriptor_); + superclass = SuperClassName(descriptor_, options_); } string initializer_with_arena = superclass + "()"; @@ -2120,7 +2128,7 @@ GenerateStructors(io::Printer* printer) { initializer_with_arena += ",\n _extensions_(arena)"; } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { initializer_with_arena += ",\n _internal_metadata_(arena)"; } else { initializer_with_arena += ",\n _arena_ptr_(arena)"; @@ -2140,7 +2148,7 @@ GenerateStructors(io::Printer* printer) { } string initializer_null; - initializer_null = (UseUnknownFieldSet(descriptor_->file()) ? + initializer_null = (UseUnknownFieldSet(descriptor_->file(), options_) ? ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)"); if (IsAnyMessage(descriptor_)) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; @@ -2194,24 +2202,23 @@ GenerateStructors(io::Printer* printer) { if (!field->is_repeated() && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && (field->containing_oneof() == NULL || - HasDescriptorMethods(descriptor_->file()))) { + HasDescriptorMethods(descriptor_->file(), options_))) { string name; if (field->containing_oneof()) { name = classname_ + "_default_oneof_instance_->"; } name += FieldName(field); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", - // Without. - " $name$_ = const_cast< $type$*>(\n" - " $type$::internal_default_instance());\n", - // Vars. - "name", name, - "type", FieldMessageTypeName(field)); + descriptor_->file(), options_, printer, + // With static initializers. + " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", + // Without. + " $name$_ = const_cast< $type$*>(\n" + " $type$::internal_default_instance());\n", + // Vars. + "name", name, "type", FieldMessageTypeName(field)); } else if (field->containing_oneof() && - HasDescriptorMethods(descriptor_->file())) { + HasDescriptorMethods(descriptor_->file(), options_)) { field_generators_.get(descriptor_->field(i)) .GenerateConstructorCode(printer); } @@ -2227,10 +2234,10 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "superclass", superclass, "full_name", descriptor_->full_name()); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( ",\n _internal_metadata_(NULL)"); - } else if (!UseUnknownFieldSet(descriptor_->file())) { + } else if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(",\n _arena_ptr_(NULL)"); } if (IsAnyMessage(descriptor_)) { @@ -2278,7 +2285,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); // Only generate this member if it's not disabled. - if (HasDescriptorMethods(descriptor_->file()) && + if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" @@ -2296,14 +2303,14 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " if (default_instance_ == NULL) $adddescriptorsname$();\n", - // Without. - " $adddescriptorsname$();\n", - // Vars. - "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + descriptor_->file(), options_, printer, + // With static initializers. + " if (default_instance_ == NULL) $adddescriptorsname$();\n", + // Without. + " $adddescriptorsname$();\n", + // Vars. + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); printer->Print( " return *default_instance_;\n" @@ -2345,8 +2352,10 @@ static int popcnt(uint32 n) { void MessageGenerator:: GenerateClear(io::Printer* printer) { - printer->Print("void $classname$::Clear() {\n", - "classname", classname_); + printer->Print( + "void $classname$::Clear() {\n" + "// @@protoc_insertion_point(message_clear_start:$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Step 1: Extensions @@ -2383,8 +2392,16 @@ GenerateClear(io::Printer* printer) { // positions of two fields in the Message. // ZR_ zeroes a non-empty range of fields via memset. const char* macros = + "#if defined(__clang__)\n" + "#define ZR_HELPER_(f) \\\n" + " _Pragma(\"clang diagnostic push\") \\\n" + " _Pragma(\"clang diagnostic ignored \\\"-Winvalid-offsetof\\\"\") \\\n" + " __builtin_offsetof($classname$, f) \\\n" + " _Pragma(\"clang diagnostic pop\")\n" + "#else\n" "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n" - " &reinterpret_cast<$classname$*>(16)->f)\n\n" + " &reinterpret_cast<$classname$*>(16)->f)\n" + "#endif\n\n" "#define ZR_(first, last) do {\\\n" " ::memset(&first, 0,\\\n" " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n" @@ -2512,7 +2529,7 @@ GenerateClear(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " mutable_unknown_fields()->Clear();\n" @@ -2542,10 +2559,13 @@ GenerateOneofClear(io::Printer* printer) { map<string, string> oneof_vars; oneof_vars["classname"] = classname_; oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); + oneof_vars["full_name"] = descriptor_->full_name(); string message_class; printer->Print(oneof_vars, - "void $classname$::clear_$oneofname$() {\n"); + "void $classname$::clear_$oneofname$() {\n" + "// @@protoc_insertion_point(one_of_clear_start:" + "$full_name$)\n"); printer->Indent(); printer->Print(oneof_vars, "switch($oneofname$_case()) {\n"); @@ -2628,7 +2648,7 @@ GenerateSwap(io::Printer* printer) { "classname", classname_); printer->Indent(); - if (HasGeneratedMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); field_generators_.get(field).GenerateSwappingCode(printer); @@ -2649,19 +2669,15 @@ GenerateSwap(io::Printer* printer) { } } - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( + // Ignore PreserveUnknownFields here - always swap internal_metadata as it + // may contain more than just unknown fields. + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + printer->Print( "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - } else { - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); - } } else { - // Still swap internal_metadata as it may contain more than just - // unknown fields. - printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } + printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Swap(&other->_extensions_);\n"); @@ -2676,13 +2692,15 @@ GenerateSwap(io::Printer* printer) { void MessageGenerator:: GenerateMergeFrom(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized MergeFrom (aka that which takes in the Message // base class as a parameter). printer->Print( - "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", - "classname", classname_); + "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)) MergeFromFail(__LINE__);\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Cast the message to the proper type. If we find that the message is @@ -2694,11 +2712,15 @@ GenerateMergeFrom(io::Printer* printer) { " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n" " &from);\n" "if (source == NULL) {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_fail:" + "$full_name$)\n" " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" "} else {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_success:" + "$full_name$)\n" " MergeFrom(*source);\n" "}\n", - "classname", classname_); + "classname", classname_, "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); @@ -2715,9 +2737,11 @@ GenerateMergeFrom(io::Printer* printer) { // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. printer->Print( - "void $classname$::MergeFrom(const $classname$& from) {\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", - "classname", classname_); + "void $classname$::MergeFrom(const $classname$& from) {\n" + "// @@protoc_insertion_point(class_specific_merge_from_start:" + "$full_name$)\n" + " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Merge Repeated fields. These fields do not require a @@ -2818,7 +2842,7 @@ GenerateMergeFrom(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (from._internal_metadata_.have_unknown_fields()) {\n" " mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n" @@ -2837,12 +2861,14 @@ GenerateMergeFrom(io::Printer* printer) { void MessageGenerator:: GenerateCopyFrom(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized CopyFrom (aka that which takes in the Message // base class as a parameter). printer->Print( - "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n", - "classname", classname_); + "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n" + "// @@protoc_insertion_point(generalized_copy_from_start:" + "$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( @@ -2856,8 +2882,10 @@ GenerateCopyFrom(io::Printer* printer) { // Generate the class-specific CopyFrom. printer->Print( - "void $classname$::CopyFrom(const $classname$& from) {\n", - "classname", classname_); + "void $classname$::CopyFrom(const $classname$& from) {\n" + "// @@protoc_insertion_point(class_specific_copy_from_start:" + "$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( @@ -2879,15 +2907,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "classname", classname_); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " return _extensions_.ParseMessageSet(input, default_instance_,\n" - " mutable_unknown_fields());\n", - // Without. - " return _extensions_.ParseMessageSet(input, &default_instance(),\n" - " mutable_unknown_fields());\n", - // Vars. - "classname", classname_); + 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" + " mutable_unknown_fields());\n", + // Vars. + "classname", classname_); printer->Print( "}\n"); @@ -2897,11 +2925,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print( "bool $classname$::MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input) {\n" - "#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n" + "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n" " ::google::protobuf::uint32 tag;\n", "classname", classname_); - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file(), options_)) { // Use LazyStringOutputString to avoid initializing unknown fields string // unless it is actually needed. For the same reason, disable eager refresh // on the CodedOutputStream. @@ -3129,32 +3158,32 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Print(") {\n"); if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), 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" - " mutable_unknown_fields()));\n"); + 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" + " mutable_unknown_fields()));\n"); } else { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), 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" - " &unknown_fields_stream));\n"); + 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" + " &unknown_fields_stream));\n"); } } else { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); + descriptor_->file(), options_, printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); } printer->Print( " continue;\n" @@ -3163,7 +3192,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // We really don't recognize this tag. Skip it. if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" " input, tag, mutable_unknown_fields()));\n"); @@ -3256,7 +3285,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { " ::google::protobuf::io::CodedOutputStream* output) const {\n" " _extensions_.SerializeMessageSetWithCachedSizes(output);\n", "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" " unknown_fields(), output);\n"); @@ -3296,7 +3325,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { " target =\n" " _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n", "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( " target = ::google::protobuf::internal::WireFormat::\n" " SerializeUnknownMessageSetItemsToArray(\n" @@ -3362,7 +3391,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n"); printer->Indent(); if (to_array) { @@ -3429,10 +3458,11 @@ GenerateByteSize(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. printer->Print( - "int $classname$::ByteSize() const {\n" - " int total_size = _extensions_.MessageSetByteSize();\n", - "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + "int $classname$::ByteSize() const {\n" + "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" + " int total_size = _extensions_.MessageSetByteSize();\n", + "classname", classname_, "full_name", descriptor_->full_name()); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " total_size += ::google::protobuf::internal::WireFormat::\n" @@ -3451,8 +3481,10 @@ 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", - "classname", classname_); + "int $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"); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -3475,8 +3507,9 @@ GenerateByteSize(io::Printer* printer) { } printer->Print( - "int $classname$::ByteSize() const {\n", - "classname", classname_); + "int $classname$::ByteSize() 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" @@ -3652,7 +3685,7 @@ GenerateByteSize(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " total_size +=\n" @@ -3718,8 +3751,8 @@ 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())) { + !ShouldIgnoreRequiredFieldCheck(field, options_) && + HasRequiredFields(field->message_type(), options_)) { if (field->is_repeated()) { printer->Print( "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 8e19a3f0..31223e13 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -67,9 +67,13 @@ class MessageGenerator { // Header stuff. // Return names for foward declarations of this class and all its nested - // types. - void FillMessageForwardDeclarations(set<string>* class_names); - void FillEnumForwardDeclarations(set<string>* enum_names); + // types. A given key in {class,enum}_names will map from a class name to the + // descriptor that was responsible for its inclusion in the map. This can be + // used to associate the descriptor with the code generated for it. + void FillMessageForwardDeclarations( + map<string, const Descriptor*>* class_names); + void FillEnumForwardDeclarations( + map<string, const EnumDescriptor*>* enum_names); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index b4545892..332c0264 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -53,10 +53,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["non_null_ptr_to_name"] = StrCat("this->", (*variables)["name"], "_"); } - (*variables)["stream_writer"] = (*variables)["declared_type"] + - (HasFastArraySerialization(descriptor->message_type()->file()) ? - "MaybeToArray" : - ""); + (*variables)["stream_writer"] = + (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file(), options) + ? "MaybeToArray" + : ""); // NOTE: Escaped here to unblock proto1->proto2 migration. // TODO(liujisi): Extend this to apply for other conflicting methods. (*variables)["release_name"] = @@ -77,11 +78,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // =================================================================== -MessageFieldGenerator:: -MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -95,7 +96,7 @@ GeneratePrivateMembers(io::Printer* printer) const { void MessageFieldGenerator:: GenerateGetterDeclaration(io::Printer* printer) const { printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); } void MessageFieldGenerator:: @@ -105,9 +106,9 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { } // Arena manipulation code is out-of-line in the derived message class. printer->Print(variables_, - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$();\n" + "$deprecated_attr$$type$* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); } void MessageFieldGenerator:: @@ -115,28 +116,28 @@ GenerateAccessorDeclarations(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables_, "private:\n" - "void _slow_mutable_$name$()$deprecation$;\n"); + "void _slow_mutable_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, "void _slow_set_allocated_$name$(\n" - " ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n"); + " ::google::protobuf::Arena* message_arena, $type$** $name$);\n"); } printer->Print(variables_, - "$type$* _slow_$release_name$()$deprecation$;\n" + "$type$* _slow_$release_name$();\n" "public:\n"); } GenerateGetterDeclaration(printer); if (!dependent_field_) { printer->Print(variables_, - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$();\n" + "$deprecated_attr$$type$* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); } if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "$type$* unsafe_arena_release_$name$()$deprecation$;\n" - "void unsafe_arena_set_allocated_$name$(\n" - " $type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* unsafe_arena_release_$name$();\n" + "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$);\n"); } } @@ -167,6 +168,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " }\n" "}\n" "$type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" @@ -246,6 +248,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "template <class T>\n" "inline $type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" " $clear_hasbit$\n" " if ($this_message$GetArenaNoVirtual() != NULL) {\n" @@ -305,6 +308,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "template <class T>\n" "inline $type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" " $dependent_typename$* temp = $name$_;\n" @@ -349,11 +353,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( - variables, descriptor_->file(), printer, - // With static initializers. - " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", - // Without. - " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); + 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_) { @@ -373,6 +377,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" @@ -426,6 +431,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" @@ -547,7 +553,7 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { return; } printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer); } @@ -560,7 +566,7 @@ GenerateGetterDeclaration(io::Printer* printer) const { return; } printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); } void MessageOneofFieldGenerator:: @@ -651,6 +657,7 @@ InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, "$tmpl$" "$inline$" "$type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if ($this_message$has_$name$()) {\n" " $this_message$clear_has_$oneof_name$();\n" " if ($this_message$GetArenaNoVirtual() != NULL) {\n" @@ -706,6 +713,8 @@ InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release" + ":$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $oneof_prefix$$name$_;\n" @@ -744,6 +753,7 @@ InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, "$tmpl$" "$inline$" "$type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if ($this_message$has_$name$()) {\n" " $this_message$clear_has_$oneof_name$();\n" " $dependent_typename$* temp = $field_member$;\n" @@ -805,12 +815,12 @@ GenerateConstructorCode(io::Printer* printer) const { // =================================================================== -RepeatedMessageFieldGenerator:: -RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)), - dependent_getter_(dependent_field_ && options.safe_boundary_check) { +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + dependent_getter_(dependent_field_ && options.safe_boundary_check) { SetMessageVariables(descriptor, &variables_, options); } @@ -825,23 +835,23 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$* mutable_$name$(int index)$deprecation$;\n" - "$type$* add_$name$()$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$(int index);\n" + "$deprecated_attr$$type$* add_$name$();\n"); if (dependent_getter_) { printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const;\n"); } printer->Print(variables_, - "::google::protobuf::RepeatedPtrField< $type$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" + " mutable_$name$();\n"); } void RepeatedMessageFieldGenerator:: GenerateDependentAccessorDeclarations(io::Printer* printer) const { if (dependent_getter_) { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$(int index) const;\n"); } if (dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); @@ -852,15 +862,15 @@ void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { if (!dependent_getter_) { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$(int index) const;\n"); } if (!dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); } if (!dependent_getter_) { printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const;\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 35efd0fa..d8d9279c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -46,8 +46,8 @@ namespace cpp { class MessageFieldGenerator : public FieldGenerator { public: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -83,8 +83,8 @@ class MessageFieldGenerator : public FieldGenerator { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: - explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -110,8 +110,8 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { class RepeatedMessageFieldGenerator : public FieldGenerator { public: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + 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 index 4463f200..ab1d2ed3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -43,11 +43,19 @@ namespace cpp { // Generator options (see generator.cc for a description of each): struct Options { - Options() : safe_boundary_check(false), proto_h(false) { - } + Options() + : safe_boundary_check(false), + proto_h(false), + annotate_headers(false), + enforce_lite(false) {} + string dllexport_decl; bool safe_boundary_check; bool proto_h; + bool annotate_headers; + bool enforce_lite; + string annotation_pragma_name; + string annotation_guard_name; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc index d1efbfe6..34a41d82 100644 --- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -44,9 +44,10 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -#include <google/protobuf/testing/file.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 9f929d37..650f0381 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -100,10 +100,9 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // =================================================================== -PrimitiveFieldGenerator:: -PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); } @@ -117,8 +116,8 @@ GeneratePrivateMembers(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$() const$deprecation$;\n" - "void set_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$() const;\n" + "$deprecated_attr$void set_$name$($type$ value);\n"); } void PrimitiveFieldGenerator:: @@ -256,10 +255,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { // =================================================================== -RepeatedPrimitiveFieldGenerator:: -RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); if (descriptor->is_packed()) { @@ -277,7 +275,8 @@ void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); - if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -286,14 +285,14 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$(int index) const$deprecation$;\n" - "void set_$name$(int index, $type$ value)$deprecation$;\n" - "void add_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$(int index) const;\n" + "$deprecated_attr$void set_$name$(int index, $type$ value);\n" + "$deprecated_attr$void add_$name$($type$ value);\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedField< $type$ >&\n" - " $name$() const$deprecation$;\n" - "::google::protobuf::RepeatedField< $type$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n" + " $name$() const;\n" + "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" + " mutable_$name$();\n"); } void RepeatedPrimitiveFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index fcd7d684..655ebde4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -46,8 +46,8 @@ namespace cpp { class PrimitiveFieldGenerator : public FieldGenerator { public: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~PrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -74,8 +74,8 @@ class PrimitiveFieldGenerator : public FieldGenerator { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: - explicit PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~PrimitiveOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -92,8 +92,8 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { class RepeatedPrimitiveFieldGenerator : public FieldGenerator { public: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedPrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 6b0821a6..1d743457 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -76,10 +76,9 @@ void SetStringVariables(const FieldDescriptor* descriptor, // =================================================================== -StringFieldGenerator:: -StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } @@ -140,19 +139,19 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "const ::std::string& $name$() const$deprecation$;\n" - "void set_$name$(const ::std::string& value)$deprecation$;\n" - "void set_$name$(const char* value)$deprecation$;\n" - "void set_$name$(const $pointer_type$* value, size_t size)" - "$deprecation$;\n" - "::std::string* mutable_$name$()$deprecation$;\n" - "::std::string* $release_name$()$deprecation$;\n" - "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); + "$deprecated_attr$const ::std::string& $name$() const;\n" + "$deprecated_attr$void set_$name$(const ::std::string& value);\n" + "$deprecated_attr$void set_$name$(const char* value);\n" + "$deprecated_attr$void set_$name$(const $pointer_type$* value, size_t size)" + ";\n" + "$deprecated_attr$::std::string* mutable_$name$();\n" + "$deprecated_attr$::std::string* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$(::std::string* $name$);\n"); if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "::std::string* unsafe_arena_release_$name$()$deprecation$;\n" - "void unsafe_arena_set_allocated_$name$(\n" - " ::std::string* $name$)$deprecation$;\n"); + "$deprecated_attr$::std::string* unsafe_arena_release_$name$();\n" + "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" + " ::std::string* $name$);\n"); } @@ -199,10 +198,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\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" + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " $clear_hasbit$\n" " return $name$_.UnsafeArenaRelease($default_variable$,\n" @@ -228,7 +229,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " }\n" " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" " $name$, GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" "}\n"); } else { // No-arena case. @@ -261,6 +263,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_.MutableNoArena($default_variable$);\n" "}\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" @@ -369,7 +372,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } } @@ -378,7 +381,7 @@ void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, @@ -390,7 +393,7 @@ void StringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, @@ -477,6 +480,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.Release($default_variable$,\n" @@ -486,6 +490,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " }\n" "}\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" " clear_has_$oneof_name$();\n" @@ -519,7 +524,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " "$name$, GetArenaNoVirtual());\n" " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" "}\n"); } else { // No-arena case. @@ -572,6 +578,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" @@ -658,7 +665,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } } @@ -666,10 +673,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { // =================================================================== -RepeatedStringFieldGenerator:: -RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } @@ -696,24 +702,24 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "const ::std::string& $name$(int index) const$deprecation$;\n" - "::std::string* mutable_$name$(int index)$deprecation$;\n" - "void set_$name$(int index, const ::std::string& value)$deprecation$;\n" - "void set_$name$(int index, const char* value)$deprecation$;\n" + "$deprecated_attr$const ::std::string& $name$(int index) const;\n" + "$deprecated_attr$::std::string* mutable_$name$(int index);\n" + "$deprecated_attr$void set_$name$(int index, const ::std::string& value);\n" + "$deprecated_attr$void set_$name$(int index, const char* value);\n" "" - "void set_$name$(int index, const $pointer_type$* value, size_t size)" - "$deprecation$;\n" - "::std::string* add_$name$()$deprecation$;\n" - "void add_$name$(const ::std::string& value)$deprecation$;\n" - "void add_$name$(const char* value)$deprecation$;\n" - "void add_$name$(const $pointer_type$* value, size_t size)" - "$deprecation$;\n"); + "$deprecated_attr$void set_$name$(" + "int index, const $pointer_type$* value, size_t size);\n" + "$deprecated_attr$::std::string* add_$name$();\n" + "$deprecated_attr$void add_$name$(const ::std::string& value);\n" + "$deprecated_attr$void add_$name$(const char* value);\n" + "$deprecated_attr$void add_$name$(const $pointer_type$* value, size_t size)" + ";\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" - "$deprecation$;\n" - "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" - "$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() " + "const;\n" + "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + ";\n"); if (unknown_ctype) { printer->Outdent(); @@ -752,6 +758,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\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" @@ -807,7 +814,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " input, this->add_$name$()));\n"); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$(this->$name$_size() - 1).data(),\n" "this->$name$(this->$name$_size() - 1).length(),\n", printer); @@ -821,7 +828,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } printer->Outdent(); @@ -838,7 +845,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { printer->Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 616e2067..cb4e8772 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -46,8 +46,8 @@ namespace cpp { class StringFieldGenerator : public FieldGenerator { public: - explicit StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~StringFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -79,8 +79,8 @@ class StringFieldGenerator : public FieldGenerator { class StringOneofFieldGenerator : public StringFieldGenerator { public: - explicit StringOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + StringOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~StringOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -99,8 +99,8 @@ class StringOneofFieldGenerator : public StringFieldGenerator { class RepeatedStringFieldGenerator : public FieldGenerator { public: - explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedStringFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 9942a343..5d82946d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -82,7 +82,6 @@ namespace google { namespace protobuf { -using internal::NewPermanentCallback; namespace compiler { namespace cpp { @@ -1253,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test { foo_(descriptor_->FindMethodByName("Foo")), bar_(descriptor_->FindMethodByName("Bar")), stub_(&mock_channel_), - done_(NewPermanentCallback(&DoNothing)) {} + done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {} virtual void SetUp() { ASSERT_TRUE(foo_ != NULL); diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index 422eb73b..edd30780 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -41,9 +41,10 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -#include <google/protobuf/testing/file.h> namespace google { namespace protobuf { @@ -51,6 +52,189 @@ namespace compiler { namespace cpp { namespace { +// A CodeGenerator that captures the FileDescriptor it's passed as a +// FileDescriptorProto. +class DescriptorCapturingGenerator : public CodeGenerator { + public: + // Does not own file; file must outlive the Generator. + explicit DescriptorCapturingGenerator(FileDescriptorProto* file) + : file_(file) {} + + virtual bool Generate(const FileDescriptor* file, const string& parameter, + GeneratorContext* context, string* error) const { + file->CopyTo(file_); + return true; + } + + private: + FileDescriptorProto* file_; +}; + +class CppMetadataTest : public ::testing::Test { + public: + // Adds a file with name `filename` and content `data`. + void AddFile(const string& filename, const string& data) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data, + true)); + } + + // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output + // code from the previously added file with name `filename`. Returns true on + // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to + // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info. + bool CaptureMetadata(const string& filename, FileDescriptorProto* file, + string* pb_h, GeneratedCodeInfo* pb_h_info, + string* proto_h, GeneratedCodeInfo* proto_h_info, + string* pb_cc) { + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + CppGenerator cpp_generator; + DescriptorCapturingGenerator capturing_generator(file); + cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); + cli.RegisterGenerator("--capture_out", &capturing_generator, ""); + + string proto_path = "-I" + TestTempDir(); + string cpp_out = + "--cpp_out=annotate_headers=true," + "annotation_pragma_name=pragma_name," + "annotation_guard_name=guard_name:" + + TestTempDir(); + string capture_out = "--capture_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(), + capture_out.c_str(), filename.c_str()}; + + if (cli.Run(5, argv) != 0) { + return false; + } + + string output_base = TestTempDir() + "/" + StripProto(filename); + + if (pb_cc != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.cc", pb_cc, true)); + } + + if (pb_h != NULL && pb_h_info != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.h", pb_h, true)); + if (!DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) { + return false; + } + } + + if (proto_h != NULL && proto_h_info != NULL) { + GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h, + true)); + if (!DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) { + return false; + } + } + + return true; + } + + private: + // Decodes GeneratedCodeInfo stored in path and copies it to info. + // Returns true on success. + bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) { + string data; + GOOGLE_CHECK_OK(File::GetContents(path, &data, true)); + io::ArrayInputStream input(data.data(), data.size()); + return info->ParseFromZeroCopyStream(&input); + } +}; + +const char kSmallTestFile[] = + "syntax = \"proto2\";\n" + "package foo;\n" + "enum Enum { VALUE = 0; }\n" + "message Message { }\n"; + +// Finds the Annotation for a given source file and path (or returns null if it +// couldn't). +const GeneratedCodeInfo::Annotation* FindAnnotationOnPath( + const GeneratedCodeInfo& info, const string& source_file, + const vector<int>& path) { + for (int i = 0; i < info.annotation_size(); ++i) { + const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i); + if (annotation->source_file() != source_file || + annotation->path_size() != path.size()) { + continue; + } + int node = 0; + for (; node < path.size(); ++node) { + if (annotation->path(node) != path[node]) { + break; + } + } + if (node == path.size()) { + return annotation; + } + } + return NULL; +} + +// Returns true if the provided annotation covers a given substring in +// file_content. +bool AnnotationMatchesSubstring(const string& file_content, + const GeneratedCodeInfo::Annotation* annotation, + const string& expected_text) { + uint32 begin = annotation->begin(); + uint32 end = annotation->end(); + if (end < begin || end > file_content.size()) { + return false; + } + return file_content.substr(begin, end - begin) == expected_text; +} + +TEST_F(CppMetadataTest, CapturesEnumNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Enum", file.enum_type(0).name()); + vector<int> enum_path; + enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber); + enum_path.push_back(0); + const GeneratedCodeInfo::Annotation* enum_annotation = + FindAnnotationOnPath(info, "test.proto", enum_path); + EXPECT_TRUE(NULL != enum_annotation); + EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum")); +} + +TEST_F(CppMetadataTest, AddsPragma) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos); + EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") != + string::npos); +} + +TEST_F(CppMetadataTest, CapturesMessageNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Message", file.message_type(0).name()); + vector<int> message_path; + message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber); + message_path.push_back(0); + const GeneratedCodeInfo::Annotation* message_annotation = + FindAnnotationOnPath(info, "test.proto", message_path); + EXPECT_TRUE(NULL != message_annotation); + EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, message_annotation, "Message")); +} + } // namespace } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc index 56681989..bdfcc2be 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -41,6 +41,7 @@ #include <google/protobuf/compiler/csharp/csharp_doc_comment.h> #include <google/protobuf/compiler/csharp/csharp_enum.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> using google::protobuf::internal::scoped_ptr; @@ -49,8 +50,8 @@ namespace protobuf { namespace compiler { namespace csharp { -EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) : - SourceGeneratorBase(descriptor->file()), +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) : + SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor) { } @@ -64,11 +65,24 @@ void EnumGenerator::Generate(io::Printer* printer) { "access_level", class_access_level(), "name", descriptor_->name()); printer->Indent(); + std::set<string> used_names; for (int i = 0; i < descriptor_->value_count(); i++) { WriteEnumValueDocComment(printer, descriptor_->value(i)); - printer->Print("$name$ = $number$,\n", - "name", descriptor_->value(i)->name(), - "number", SimpleItoa(descriptor_->value(i)->number())); + string original_name = descriptor_->value(i)->name(); + string name = options()->legacy_enum_values + ? descriptor_->value(i)->name() + : GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name()); + // Make sure we don't get any duplicate names due to prefix removal. + while (!used_names.insert(name).second) { + // It's possible we'll end up giving this warning multiple times, but that's better than not at all. + GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name + << ") in " << descriptor_->name() << "; adding underscore to distinguish"; + name += "_"; + } + printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n", + "original_name", original_name, + "name", name, + "number", SimpleItoa(descriptor_->value(i)->number())); } printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h index 2cf2fad4..8925cdf2 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum.h @@ -43,7 +43,7 @@ namespace csharp { class EnumGenerator : public SourceGeneratorBase { public: - EnumGenerator(const EnumDescriptor* descriptor); + EnumGenerator(const EnumDescriptor* descriptor, const Options* options); ~EnumGenerator(); void Generate(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc index d38fb1ed..67c0b596 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -38,6 +38,7 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_enum_field.h> namespace google { @@ -46,8 +47,8 @@ namespace compiler { namespace csharp { EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) { } EnumFieldGenerator::~EnumFieldGenerator() { @@ -80,9 +81,9 @@ void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) { "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)"); } -EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal) { +EnumOneofFieldGenerator::EnumOneofFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) { } EnumOneofFieldGenerator::~EnumOneofFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h index 08364157..9b7669ba 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -43,7 +43,9 @@ namespace csharp { class EnumFieldGenerator : public PrimitiveFieldGenerator { public: - EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + EnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~EnumFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -57,7 +59,9 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator { class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { public: - EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~EnumOneofFieldGenerator(); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 5df43d3f..e3c34040 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -94,14 +94,15 @@ void FieldGeneratorBase::SetCommonFieldVariables( void FieldGeneratorBase::SetCommonOneofFieldVariables( map<string, string>* variables) { (*variables)["oneof_name"] = oneof_name(); - (*variables)["has_property_check"] = oneof_name() + "Case_ == " + oneof_property_name() + + (*variables)["has_property_check"] = + oneof_name() + "Case_ == " + oneof_property_name() + "OneofCase." + property_name(); (*variables)["oneof_property_name"] = oneof_property_name(); } FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, - int fieldOrdinal) - : SourceGeneratorBase(descriptor->file()), + int fieldOrdinal, const Options* options) + : SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor), fieldOrdinal_(fieldOrdinal) { SetCommonFieldVariables(&variables_); @@ -158,10 +159,11 @@ std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) { case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: if (IsWrapperType(descriptor)) { - const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); + const FieldDescriptor* wrapped_field = + descriptor->message_type()->field(0); string wrapped_field_type_name = type_name(wrapped_field); - // String and ByteString go to the same type; other wrapped types go to the - // nullable equivalent. + // String and ByteString go to the same type; other wrapped types + // go to the nullable equivalent. if (wrapped_field->type() == FieldDescriptor::TYPE_STRING || wrapped_field->type() == FieldDescriptor::TYPE_BYTES) { return wrapped_field_type_name; @@ -304,7 +306,9 @@ std::string FieldGeneratorBase::default_value() { std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) { switch (descriptor->type()) { case FieldDescriptor::TYPE_ENUM: - return type_name() + "." + descriptor->default_value_enum()->name(); + // All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to + // any C# enum. This means we don't need to work out what we actually mapped the enum value name to. + return "0"; case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: if (IsWrapperType(descriptor)) { diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index d83543bd..4109f3ca 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -44,7 +44,9 @@ namespace csharp { class FieldGeneratorBase : public SourceGeneratorBase { public: - FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal); + FieldGeneratorBase(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); ~FieldGeneratorBase(); virtual void GenerateCloningCode(io::Printer* printer) = 0; diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index 825de542..d74e8c88 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -41,6 +41,7 @@ #include <google/protobuf/compiler/csharp/csharp_generator.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> #include <google/protobuf/compiler/csharp/csharp_names.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_reflection_class.h> using google::protobuf::internal::scoped_ptr; @@ -51,8 +52,9 @@ namespace compiler { namespace csharp { void GenerateFile(const google::protobuf::FileDescriptor* file, - io::Printer* printer) { - ReflectionClassGenerator reflectionClassGenerator(file); + io::Printer* printer, + const Options* options) { + ReflectionClassGenerator reflectionClassGenerator(file, options); reflectionClassGenerator.Generate(printer); } @@ -71,15 +73,19 @@ bool Generator::Generate( return false; } - std::string file_extension = ".cs"; - std::string base_namespace = ""; - bool generate_directories = false; + struct Options cli_options; + for (int i = 0; i < options.size(); i++) { if (options[i].first == "file_extension") { - file_extension = options[i].second; + cli_options.file_extension = options[i].second; } else if (options[i].first == "base_namespace") { - base_namespace = options[i].second; - generate_directories = true; + cli_options.base_namespace = options[i].second; + cli_options.base_namespace_specified = true; + } else if (options[i].first == "internal_access") { + cli_options.internal_access = true; + } else if (options[i].first == "legacy_enum_values") { + // TODO: Remove this before final release + cli_options.legacy_enum_values = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -87,7 +93,12 @@ bool Generator::Generate( } string filename_error = ""; - std::string filename = GetOutputFile(file, file_extension, generate_directories, base_namespace, &filename_error); + std::string filename = GetOutputFile(file, + cli_options.file_extension, + cli_options.base_namespace_specified, + cli_options.base_namespace, + &filename_error); + if (filename.empty()) { *error = filename_error; return false; @@ -96,7 +107,7 @@ bool Generator::Generate( generator_context->Open(filename)); io::Printer printer(output.get(), '$'); - GenerateFile(file, &printer); + GenerateFile(file, &printer, &cli_options); return true; } diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc index 7ef7df42..5755fee0 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc @@ -30,8 +30,8 @@ #include <memory> -#include <google/protobuf/compiler/ruby/ruby_generator.h> #include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/printer.h> @@ -45,7 +45,23 @@ namespace compiler { namespace csharp { namespace { -// TODO(jtattermusch): add some tests. +TEST(CSharpEnumValue, PascalCasedPrefixStripping) { + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz")); + EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___")); + // Identifiers can't start with digits + EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR")); + EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2")); +} } // namespace } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index c51fe44b..6c154c5a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -48,6 +48,7 @@ #include <google/protobuf/compiler/csharp/csharp_enum_field.h> #include <google/protobuf/compiler/csharp/csharp_map_field.h> #include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_primitive_field.h> #include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> #include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> @@ -127,7 +128,8 @@ std::string GetFileNameBase(const FileDescriptor* descriptor) { } std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) { - // TODO: Detect collisions with existing messages, and append an underscore if necessary. + // TODO: Detect collisions with existing messages, + // and append an underscore if necessary. return GetFileNameBase(descriptor) + "Reflection"; } @@ -176,6 +178,104 @@ std::string UnderscoresToPascalCase(const std::string& input) { return UnderscoresToCamelCase(input, true); } +// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty) +// into a PascalCase string. Precise rules implemented: + +// Previous input character Current character Case +// Any Non-alphanumeric Skipped +// None - first char of input Alphanumeric Upper +// Non-letter (e.g. _ or 1) Alphanumeric Upper +// Numeric Alphanumeric Upper +// Lower letter Alphanumeric Same as current +// Upper letter Alphanumeric Lower +std::string ShoutyToPascalCase(const std::string& input) { + string result; + // Simple way of implementing "always start with upper" + char previous = '_'; + for (int i = 0; i < input.size(); i++) { + char current = input[i]; + if (!ascii_isalnum(current)) { + previous = current; + continue; + } + if (!ascii_isalnum(previous)) { + result += ascii_toupper(current); + } else if (ascii_isdigit(previous)) { + result += ascii_toupper(current); + } else if (ascii_islower(previous)) { + result += current; + } else { + result += ascii_tolower(current); + } + previous = current; + } + return result; +} + +// Attempt to remove a prefix from a value, ignoring casing and skipping underscores. +// (foo, foo_bar) => bar - underscore after prefix is skipped +// (FOO, foo_bar) => bar - casing is ignored +// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored +// (foobar, foo_barbaz) => baz - underscore in value is ignored +// (foo, bar) => bar - prefix isn't matched; return original value +std::string TryRemovePrefix(const std::string& prefix, const std::string& value) { + // First normalize to a lower-case no-underscores prefix to match against + std::string prefix_to_match = ""; + for (size_t i = 0; i < prefix.size(); i++) { + if (prefix[i] != '_') { + prefix_to_match += ascii_tolower(prefix[i]); + } + } + + // This keeps track of how much of value we've consumed + size_t prefix_index, value_index; + for (prefix_index = 0, value_index = 0; + prefix_index < prefix_to_match.size() && value_index < value.size(); + value_index++) { + // Skip over underscores in the value + if (value[value_index] == '_') { + continue; + } + if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) { + // Failed to match the prefix - bail out early. + return value; + } + } + + // If we didn't finish looking through the prefix, we can't strip it. + if (prefix_index < prefix_to_match.size()) { + return value; + } + + // Step over any underscores after the prefix + while (value_index < value.size() && value[value_index] == '_') { + value_index++; + } + + // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip. + if (value_index == value.size()) { + return value; + } + + return value.substr(value_index); +} + +// Format the enum value name in a pleasant way for C#: +// - Strip the enum name as a prefix if possible +// - Convert to PascalCase. +// For example, an enum called Color with a value of COLOR_BLUE should +// result in an enum value in C# called just Blue +std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) { + std::string stripped = TryRemovePrefix(enum_name, enum_value_name); + std::string result = ShoutyToPascalCase(stripped); + // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned + // string is a valid identifier. + if (ascii_isdigit(result[0])) { + result = "_" + result; + } + return result; +} + std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { std::string result = GetFileNamespace(file); if (result != "") { @@ -351,49 +451,50 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { } FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) { + int fieldOrdinal, + const Options* options) { switch (descriptor->type()) { case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_MESSAGE: if (descriptor->is_repeated()) { if (descriptor->is_map()) { - return new MapFieldGenerator(descriptor, fieldOrdinal); + return new MapFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options); } } else { if (IsWrapperType(descriptor)) { if (descriptor->containing_oneof()) { - return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal); + return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new WrapperFieldGenerator(descriptor, fieldOrdinal); + return new WrapperFieldGenerator(descriptor, fieldOrdinal, options); } } else { if (descriptor->containing_oneof()) { - return new MessageOneofFieldGenerator(descriptor, fieldOrdinal); + return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new MessageFieldGenerator(descriptor, fieldOrdinal); + return new MessageFieldGenerator(descriptor, fieldOrdinal, options); } } } case FieldDescriptor::TYPE_ENUM: if (descriptor->is_repeated()) { - return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options); } else { if (descriptor->containing_oneof()) { - return new EnumOneofFieldGenerator(descriptor, fieldOrdinal); + return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new EnumFieldGenerator(descriptor, fieldOrdinal); + return new EnumFieldGenerator(descriptor, fieldOrdinal, options); } } default: if (descriptor->is_repeated()) { - return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options); } else { if (descriptor->containing_oneof()) { - return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal); + return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options); } } } diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index e96e7938..1563ca7e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -36,6 +36,7 @@ #define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ #include <string> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/compiler/code_generator.h> @@ -46,6 +47,7 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; class FieldGeneratorBase; // TODO: start using this enum. @@ -82,7 +84,9 @@ std::string GetPropertyName(const FieldDescriptor* descriptor); int GetFixedSize(FieldDescriptor::Type type); -std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter, bool preserve_period); +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter, + bool preserve_period); inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) { return UnderscoresToCamelCase(input, cap_next_letter, false); @@ -90,22 +94,28 @@ inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_nex std::string UnderscoresToPascalCase(const std::string& input); +// Note that we wouldn't normally want to export this (we're not expecting +// it to be used outside libprotoc itself) but this exposes it for testing. +std::string LIBPROTOBUF_EXPORT GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name); + // TODO(jtattermusch): perhaps we could move this to strutil std::string StringToBase64(const std::string& input); std::string FileDescriptorToBase64(const FileDescriptor* descriptor); -FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); -// Determines whether the given message is a map entry message, i.e. one implicitly created -// by protoc due to a map<key, value> field. +// Determines whether the given message is a map entry message, +// i.e. one implicitly created by protoc due to a map<key, value> field. inline bool IsMapEntryMessage(const Descriptor* descriptor) { return descriptor->options().map_entry(); } -// Determines whether we're generating code for the proto representation of descriptors etc, -// for use in the runtime. This is the only type which is allowed to use proto2 syntax, -// and it generates internal classes. +// Determines whether we're generating code for the proto representation of +// descriptors etc, for use in the runtime. This is the only type which is +// allowed to use proto2 syntax, and it generates internal classes. inline bool IsDescriptorProto(const FileDescriptor* descriptor) { return descriptor->name() == "google/protobuf/descriptor.proto"; } diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc index 15c68b3f..565d1225 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc @@ -48,8 +48,9 @@ namespace compiler { namespace csharp { MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, + const Options* options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } MapFieldGenerator::~MapFieldGenerator() { @@ -62,8 +63,10 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { descriptor_->message_type()->FindFieldByName("value"); variables_["key_type_name"] = type_name(key_descriptor); variables_["value_type_name"] = type_name(value_descriptor); - scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1)); - scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2)); + scoped_ptr<FieldGeneratorBase> key_generator( + CreateFieldGenerator(key_descriptor, 1, this->options())); + scoped_ptr<FieldGeneratorBase> value_generator( + CreateFieldGenerator(value_descriptor, 2, this->options())); printer->Print( variables_, diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.h b/src/google/protobuf/compiler/csharp/csharp_map_field.h index f33fe1c3..84a33a03 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h @@ -43,7 +43,9 @@ namespace csharp { class MapFieldGenerator : public FieldGeneratorBase { public: - MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MapFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); ~MapFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index e0230a24..532da6b9 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -60,8 +60,9 @@ bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { return d1->number() < d2->number(); } -MessageGenerator::MessageGenerator(const Descriptor* descriptor) - : SourceGeneratorBase(descriptor->file()), +MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const Options* options) + : SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor) { // sorted field names @@ -185,7 +186,8 @@ void MessageGenerator::Generate(io::Printer* printer) { } printer->Outdent(); printer->Print("}\n"); - // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go. + // TODO: Should we put the oneof .proto comments here? + // It's unclear exactly where they should go. printer->Print( vars, "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n" @@ -214,13 +216,14 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("public static partial class Types {\n"); printer->Indent(); for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator enumGenerator(descriptor_->enum_type(i)); + EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options()); enumGenerator.Generate(printer); } for (int i = 0; i < descriptor_->nested_type_count(); i++) { // Don't generate nested types for maps... if (!IsMapEntryMessage(descriptor_->nested_type(i))) { - MessageGenerator messageGenerator(descriptor_->nested_type(i)); + MessageGenerator messageGenerator( + descriptor_->nested_type(i), this->options()); messageGenerator.Generate(printer); } } @@ -268,7 +271,8 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) { // Clone just the right field for each oneof for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); - vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + vars["property_name"] = UnderscoresToCamelCase( + descriptor_->oneof_decl(i)->name(), true); printer->Print(vars, "switch (other.$property_name$Case) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { @@ -449,7 +453,8 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); // Handle both packed and unpacked repeated fields with the same Read*Array call; // the two generated cases are the packed and unpacked tags. - // TODO(jonskeet): Check that is_packable is equivalent to is_repeated && wt in { VARINT, FIXED32, FIXED64 }. + // TODO(jonskeet): Check that is_packable is equivalent to + // is_repeated && wt in { VARINT, FIXED32, FIXED64 }. // It looks like it is... if (field->is_packable()) { printer->Print( @@ -490,7 +495,7 @@ int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( const FieldDescriptor* descriptor) { - return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor)); + return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor), this->options()); } } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h index f0c49ac9..f794d68d 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.h +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -47,7 +47,7 @@ class FieldGeneratorBase; class MessageGenerator : public SourceGeneratorBase { public: - MessageGenerator(const Descriptor* descriptor); + MessageGenerator(const Descriptor* descriptor, const Options* options); ~MessageGenerator(); void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index f81f769b..338692f8 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -41,6 +41,7 @@ #include <google/protobuf/compiler/csharp/csharp_doc_comment.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> #include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> namespace google { namespace protobuf { @@ -48,8 +49,9 @@ namespace compiler { namespace csharp { MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, + const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { variables_["has_property_check"] = name() + "_ != null"; variables_["has_not_property_check"] = name() + "_ == null"; } @@ -143,9 +145,11 @@ void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) { "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)"); } -MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : MessageFieldGenerator(descriptor, fieldOrdinal) { +MessageOneofFieldGenerator::MessageOneofFieldGenerator( + const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options) + : MessageFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h index dc6e4dc5..7d614756 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -43,7 +43,9 @@ namespace csharp { class MessageFieldGenerator : public FieldGeneratorBase { public: - MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~MessageFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -65,7 +67,9 @@ class MessageFieldGenerator : public FieldGeneratorBase { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: - MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~MessageOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h new file mode 100644 index 00000000..4079bf7f --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -0,0 +1,86 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ + +#include <string> + +#include <google/protobuf/stubs/common.h> +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Generator options (used by csharp_generator.cc): +struct Options { + Options() : + file_extension(".cs"), + base_namespace(""), + base_namespace_specified(false), + internal_access(false), + legacy_enum_values(false) { + } + // Extension of the generated file. Defaults to ".cs" + string file_extension; + // Base namespace to use to create directory hierarchy. Defaults to "". + // This option allows the simple creation of a conventional C# file layout, + // where directories are created relative to a project-specific base + // namespace. For example, in a project with a base namespace of PetShop, a + // proto of user.proto with a C# namespace of PetShop.Model.Shared would + // generate Model/Shared/User.cs underneath the specified --csharp_out + // directory. + // + // If no base namespace is specified, all files are generated in the + // --csharp_out directory, with no subdirectories created automatically. + string base_namespace; + // Whether the base namespace has been explicitly specified by the user. + // This is required as the base namespace can be explicitly set to the empty + // string, meaning "create a full directory hierarchy, starting from the first + // segment of the namespace." + bool base_namespace_specified; + // Whether the generated classes should have accessibility level of "internal". + // Defaults to false that generates "public" classes. + bool internal_access; + // By default, C# codegen now uses PascalCased enum values names, after + // removing the enum type name as a prefix (if it *is* a prefix of the value). + // Setting this option reverts to the previous behavior of just copying the + // value name specified in the .proto file, allowing gradual migration. + // This option will be removed before final release. + bool legacy_enum_values; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf + + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index 60afd892..3b7ca75a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -40,6 +40,7 @@ #include <google/protobuf/compiler/csharp/csharp_doc_comment.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_primitive_field.h> namespace google { @@ -48,8 +49,8 @@ namespace compiler { namespace csharp { PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { // TODO(jonskeet): Make this cleaner... is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING && descriptor->type() != FieldDescriptor::TYPE_BYTES; @@ -163,8 +164,8 @@ void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) { } PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h index 8b87ebc4..5f466fc4 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -41,9 +41,13 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class PrimitiveFieldGenerator : public FieldGeneratorBase { public: - PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~PrimitiveFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -67,7 +71,9 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: - PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~PrimitiveOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index 22dae43b..f7397c0f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -43,6 +43,7 @@ #include <google/protobuf/compiler/csharp/csharp_helpers.h> #include <google/protobuf/compiler/csharp/csharp_message.h> #include <google/protobuf/compiler/csharp/csharp_names.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_reflection_class.h> namespace google { @@ -50,8 +51,9 @@ namespace protobuf { namespace compiler { namespace csharp { -ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file) - : SourceGeneratorBase(file), +ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file, + const Options* options) + : SourceGeneratorBase(file, options), file_(file) { namespace_ = GetFileNamespace(file); reflectionClassname_ = GetReflectionClassUnqualifiedName(file); @@ -72,7 +74,7 @@ void ReflectionClassGenerator::Generate(io::Printer* printer) { if (file_->enum_type_count() > 0) { printer->Print("#region Enums\n"); for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator enumGenerator(file_->enum_type(i)); + EnumGenerator enumGenerator(file_->enum_type(i), this->options()); enumGenerator.Generate(printer); } printer->Print("#endregion\n"); @@ -83,7 +85,7 @@ void ReflectionClassGenerator::Generate(io::Printer* printer) { if (file_->message_type_count() > 0) { printer->Print("#region Messages\n"); for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator messageGenerator(file_->message_type(i)); + MessageGenerator messageGenerator(file_->message_type(i), this->options()); messageGenerator.Generate(printer); } printer->Print("#endregion\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h index 0a5b8ed5..e0c69f31 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h @@ -43,7 +43,7 @@ namespace csharp { class ReflectionClassGenerator : public SourceGeneratorBase { public: - ReflectionClassGenerator(const FileDescriptor* file); + ReflectionClassGenerator(const FileDescriptor* file, const Options* options); ~ReflectionClassGenerator(); void Generate(io::Printer* printer); @@ -56,7 +56,9 @@ class ReflectionClassGenerator : public SourceGeneratorBase { void WriteIntroduction(io::Printer* printer); void WriteDescriptor(io::Printer* printer); - void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last); + void WriteGeneratedCodeInfo(const Descriptor* descriptor, + io::Printer* printer, + bool last); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator); }; diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc index 3a11b75d..1befdc15 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -48,8 +48,8 @@ namespace compiler { namespace csharp { RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h index ee50eef0..819b5832 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -45,7 +45,9 @@ namespace csharp { // should probably have a RepeatedFieldGeneratorBase. class RepeatedEnumFieldGenerator : public FieldGeneratorBase { public: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~RepeatedEnumFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc index fc12faed..d51e638a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -49,8 +49,8 @@ namespace compiler { namespace csharp { RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() { @@ -66,10 +66,12 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) { // "create single field generator for this repeated field" // function, but it doesn't seem worth it for just this. if (IsWrapperType(descriptor_)) { - scoped_ptr<FieldGeneratorBase> single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_)); + scoped_ptr<FieldGeneratorBase> single_generator( + new WrapperFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } else { - scoped_ptr<FieldGeneratorBase> single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_)); + scoped_ptr<FieldGeneratorBase> single_generator( + new MessageFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } printer->Print(";\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h index cf601c7e..6e33648b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -41,9 +41,13 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class RepeatedMessageFieldGenerator : public FieldGeneratorBase { public: - RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~RepeatedMessageFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc index 5fe0b203..bee3f363 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -48,8 +48,8 @@ namespace compiler { namespace csharp { RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h index f1ceeb50..a59348a9 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -43,7 +43,7 @@ namespace csharp { class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { public: - RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~RepeatedPrimitiveFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc index 735d164a..16411e49 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -39,14 +39,17 @@ #include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_names.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> namespace google { namespace protobuf { namespace compiler { namespace csharp { -SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor) - : descriptor_(descriptor) { +SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor, + const Options *options) + : descriptor_(descriptor), options_(options) { } SourceGeneratorBase::~SourceGeneratorBase() { @@ -57,7 +60,11 @@ void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) { } std::string SourceGeneratorBase::class_access_level() { - return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on. + return (IsDescriptorProto(descriptor_) || this->options()->internal_access) ? "internal" : "public"; +} + +const Options* SourceGeneratorBase::options() { + return this->options_; } } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h index 6caef171..2e734581 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h @@ -40,17 +40,21 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class SourceGeneratorBase { protected: - SourceGeneratorBase(const FileDescriptor* descriptor); + SourceGeneratorBase(const FileDescriptor* descriptor, const Options* options); virtual ~SourceGeneratorBase(); std::string class_access_level(); + const Options* options(); void WriteGeneratedCodeAttributes(io::Printer* printer); private: const FileDescriptor* descriptor_; + const Options *options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase); }; diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc index 6a3750e0..5cb86b6b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc @@ -39,6 +39,7 @@ #include <google/protobuf/compiler/csharp/csharp_doc_comment.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> #include <google/protobuf/compiler/csharp/csharp_wrapper_field.h> namespace google { @@ -47,8 +48,8 @@ namespace compiler { namespace csharp { WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { variables_["has_property_check"] = name() + "_ != null"; variables_["has_not_property_check"] = name() + "_ == null"; const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); @@ -151,9 +152,9 @@ void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) { } } -WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : WrapperFieldGenerator(descriptor, fieldOrdinal) { +WrapperOneofFieldGenerator::WrapperOneofFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : WrapperFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h index 6e2414af..250dfd25 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h @@ -41,9 +41,13 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class WrapperFieldGenerator : public FieldGeneratorBase { public: - WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + WrapperFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~WrapperFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -65,7 +69,9 @@ class WrapperFieldGenerator : public FieldGeneratorBase { class WrapperOneofFieldGenerator : public WrapperFieldGenerator { public: - WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~WrapperOneofFieldGenerator(); virtual void GenerateMembers(io::Printer* printer); diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index be19aa2e..1b6e9700 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -32,25 +32,26 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/compiler/importer.h> + #include <google/protobuf/stubs/hash.h> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif -#include <google/protobuf/compiler/importer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/testing/file.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> - -#include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> +#include <google/protobuf/stubs/map_util.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc index 7d21fe61..0a112888 100644 --- a/src/google/protobuf/compiler/java/java_context.cc +++ b/src/google/protobuf/compiler/java/java_context.cc @@ -43,7 +43,7 @@ namespace compiler { namespace java { Context::Context(const FileDescriptor* file) - : name_resolver_(new ClassNameResolver) { + : name_resolver_(new ClassNameResolver), enforce_lite_(false) { InitializeFieldGeneratorInfo(file); } @@ -189,6 +189,13 @@ const OneofGeneratorInfo* Context::GetOneofGeneratorInfo( return result; } +// Does this message class have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +bool Context::HasGeneratedMethods(const Descriptor* descriptor) const { + return enforce_lite_ || descriptor->file()->options().optimize_for() != + FileOptions::CODE_SIZE; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h index 5b595d07..a480e45d 100644 --- a/src/google/protobuf/compiler/java/java_context.h +++ b/src/google/protobuf/compiler/java/java_context.h @@ -46,6 +46,7 @@ namespace protobuf { class FieldDescriptor; class OneofDescriptor; class Descriptor; + class EnumDescriptor; namespace compiler { namespace java { class ClassNameResolver; // name_resolver.h @@ -78,6 +79,20 @@ class Context { const OneofGeneratorInfo* GetOneofGeneratorInfo( const OneofDescriptor* oneof) const; + // Enforces all the files (including transitive dependencies) to use + // LiteRuntime. + void SetEnforceLite(bool enforce_lite) { + enforce_lite_ = enforce_lite; + } + + bool EnforceLite() const { + return enforce_lite_; + } + + // Does this message class have generated parsing, serialization, and other + // standard methods for which reflection-based fallback implementations exist? + bool HasGeneratedMethods(const Descriptor* descriptor) const; + private: void InitializeFieldGeneratorInfo(const FileDescriptor* file); void InitializeFieldGeneratorInfoForMessage(const Descriptor* message); @@ -87,6 +102,7 @@ class Context { google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_; map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_; map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_; + bool enforce_lite_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context); }; diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc index 663f0c97..0b5caba4 100644 --- a/src/google/protobuf/compiler/java/java_doc_comment.cc +++ b/src/google/protobuf/compiler/java/java_doc_comment.cc @@ -120,9 +120,7 @@ static void WriteDocCommentBodyForLocation( lines.pop_back(); } - printer->Print( - " *\n" - " * <pre>\n"); + printer->Print(" * <pre>\n"); for (int i = 0; i < lines.size(); i++) { // Most lines should start with a space. Watch out for lines that start // with a /, since putting that right after the leading asterisk will @@ -133,7 +131,9 @@ static void WriteDocCommentBodyForLocation( printer->Print(" *$line$\n", "line", lines[i]); } } - printer->Print(" * </pre>\n"); + printer->Print( + " * </pre>\n" + " *\n"); } } @@ -163,12 +163,12 @@ static string FirstLineOf(const string& value) { } void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, message); printer->Print( - "/**\n" - " * Protobuf type {@code $fullname$}\n", + " * Protobuf type {@code $fullname$}\n" + " */\n", "fullname", EscapeJavadoc(message->full_name())); - WriteDocCommentBody(printer, message); - printer->Print(" */\n"); } void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { @@ -176,55 +176,55 @@ void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { // etc., but in practice everyone already knows the difference between these // so it's redundant information. - // We use the field declaration as the first line of the comment, e.g.: + // We start the comment with the main body based on the comments from the + // .proto file (if present). We then end with the field declaration, e.g.: // optional string foo = 5; - // This communicates a lot of information about the field in a small space. // If the field is a group, the debug string might end with {. + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); printer->Print( - "/**\n" " * <code>$def$</code>\n", "def", EscapeJavadoc(FirstLineOf(field->DebugString()))); - WriteDocCommentBody(printer, field); printer->Print(" */\n"); } void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, enum_); printer->Print( - "/**\n" - " * Protobuf enum {@code $fullname$}\n", + " * Protobuf enum {@code $fullname$}\n" + " */\n", "fullname", EscapeJavadoc(enum_->full_name())); - WriteDocCommentBody(printer, enum_); - printer->Print(" */\n"); } void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, value); printer->Print( - "/**\n" - " * <code>$def$</code>\n", + " * <code>$def$</code>\n" + " */\n", "def", EscapeJavadoc(FirstLineOf(value->DebugString()))); - WriteDocCommentBody(printer, value); - printer->Print(" */\n"); } void WriteServiceDocComment(io::Printer* printer, const ServiceDescriptor* service) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, service); printer->Print( - "/**\n" - " * Protobuf service {@code $fullname$}\n", + " * Protobuf service {@code $fullname$}\n" + " */\n", "fullname", EscapeJavadoc(service->full_name())); - WriteDocCommentBody(printer, service); - printer->Print(" */\n"); } void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) { + printer->Print("/**\n"); + WriteDocCommentBody(printer, method); printer->Print( - "/**\n" - " * <code>$def$</code>\n", + " * <code>$def$</code>\n" + " */\n", "def", EscapeJavadoc(FirstLineOf(method->DebugString()))); - WriteDocCommentBody(printer, method); - printer->Print(" */\n"); } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 5fc9b002..947b80e4 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -64,6 +64,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api, Context* context) : descriptor_(descriptor), immutable_api_(immutable_api), + context_(context), name_resolver_(context->GetNameResolver()) { for (int i = 0; i < descriptor_->value_count(); i++) { const EnumValueDescriptor* value = descriptor_->value(i); @@ -91,6 +92,16 @@ void EnumGenerator::Generate(io::Printer* printer) { "classname", descriptor_->name()); printer->Indent(); + bool ordinal_is_index = true; + string index_text = "ordinal()"; + for (int i = 0; i < canonical_values_.size(); i++) { + if (canonical_values_[i]->index() != i) { + ordinal_is_index = false; + index_text = "index"; + break; + } + } + for (int i = 0; i < canonical_values_.size(); i++) { map<string, string> vars; vars["name"] = canonical_values_[i]->name(); @@ -100,12 +111,21 @@ void EnumGenerator::Generate(io::Printer* printer) { if (canonical_values_[i]->options().deprecated()) { printer->Print("@java.lang.Deprecated\n"); } - printer->Print(vars, - "$name$($index$, $number$),\n"); + if (ordinal_is_index) { + printer->Print(vars, + "$name$($number$),\n"); + } else { + printer->Print(vars, + "$name$($index$, $number$),\n"); + } } if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print("UNRECOGNIZED(-1, -1),\n"); + if (ordinal_is_index) { + printer->Print("UNRECOGNIZED(-1),\n"); + } else { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } } printer->Print( @@ -140,17 +160,33 @@ void EnumGenerator::Generate(io::Printer* printer) { "\n" "public final int getNumber() {\n"); if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print( - " if (index == -1) {\n" - " throw new java.lang.IllegalArgumentException(\n" - " \"Can't get the number of an unknown enum value.\");\n" - " }\n"); + if (ordinal_is_index) { + printer->Print( + " if (this == UNRECOGNIZED) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } else { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } } printer->Print( " return value;\n" "}\n" "\n" + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -178,7 +214,7 @@ void EnumGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", @@ -187,18 +223,19 @@ void EnumGenerator::Generate(io::Printer* printer) { // ----------------------------------------------------------------- // Reflection - if (HasDescriptorMethods(descriptor_)) { + if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) { printer->Print( "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n" " getValueDescriptor() {\n" - " return getDescriptor().getValues().get(index);\n" + " return getDescriptor().getValues().get($index_text$);\n" "}\n" "public final com.google.protobuf.Descriptors.EnumDescriptor\n" " getDescriptorForType() {\n" " return getDescriptor();\n" "}\n" "public static final com.google.protobuf.Descriptors.EnumDescriptor\n" - " getDescriptor() {\n"); + " getDescriptor() {\n", + "index_text", index_text); // TODO(kenton): Cache statically? Note that we can't access descriptors // at module init time because it wouldn't work with descriptor.proto, but @@ -229,7 +266,7 @@ void EnumGenerator::Generate(io::Printer* printer) { " (com.google.protobuf.Descriptors.FileDescriptor)\n" " m.invoke(immutableFileClass);\n" " return file.getEnumTypes().get($index$);\n" - "} catch (Exception e) {\n" + "} catch (java.lang.Exception e) {\n" // Immutable classes cannot be found. Proceed as if custom options // don't exist. "}\n", @@ -304,16 +341,27 @@ void EnumGenerator::Generate(io::Printer* printer) { "}\n" "\n"); - printer->Print("private final int index;\n"); + if (!ordinal_is_index) { + printer->Print("private final int index;\n"); + } } // ----------------------------------------------------------------- printer->Print( - "private final int value;\n\n" - "private $classname$(int index, int value) {\n", - "classname", descriptor_->name()); - if (HasDescriptorMethods(descriptor_)) { + "private final int value;\n\n"); + + if (ordinal_is_index) { + printer->Print( + "private $classname$(int value) {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "private $classname$(int index, int value) {\n", + "classname", descriptor_->name()); + } + if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) && + !ordinal_is_index) { printer->Print(" this.index = index;\n"); } printer->Print( diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 558da968..3e54be3d 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -68,21 +68,14 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_number"] = SimpleItoa( descriptor->default_value_enum()->number()); - if (descriptor->is_packed()) { - (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag( - descriptor->number(), - internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); - } else { - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - } + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -198,7 +191,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); } @@ -231,7 +224,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -311,7 +304,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -405,7 +398,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -443,7 +436,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -500,7 +493,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -613,7 +606,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -649,7 +642,7 @@ GenerateMembers(io::Printer* printer) const { } if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); } @@ -846,7 +839,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index e3e87c58..908d6db4 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -75,8 +75,6 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -179,7 +177,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); @@ -228,7 +226,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" " copyOnWrite();\n" - " instance.set$capitalized_name$Value(int value);\n" + " instance.set$capitalized_name$Value(value);\n" " return this;\n" "}\n"); } @@ -264,17 +262,15 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableEnumFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visitInt(has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "if (other.$name$_ != $default_number$) {\n" - " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" - "}\n"); + "$name$_ = visitor.visitInt($name$_ != $default_number$, $name$_," + " other.$name$_ != $default_number$, other.$name$_);\n"); } else { GOOGLE_LOG(FATAL) << "Can't reach here."; } @@ -295,7 +291,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -389,7 +385,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -468,14 +464,10 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableEnumOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print(variables_, - "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); - } else { - printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); - } +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$oneof_name$_ = visitor.visitOneofInt(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutableEnumOneofFieldLiteGenerator:: @@ -488,7 +480,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -602,7 +594,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -638,7 +630,7 @@ GenerateMembers(io::Printer* printer) const { } if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); } @@ -647,7 +639,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newIntList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -807,22 +800,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableEnumFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - " $on_changed$\n" - "}\n"); +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_= visitor.visitIntList($name$_, other.$name$_);\n"); } void RepeatedImmutableEnumFieldLiteGenerator:: @@ -834,27 +814,23 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { // Read and store the enum + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "int rawValue = input.readEnum();\n" - "if (!$is_mutable$) {\n" - " $name$_ = newIntList();\n" - "}\n" - "$name$_.addInt(rawValue);\n"); + "$name$_.addInt(input.readEnum());\n"); } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" - "if (value == null) {\n"); - if (PreserveUnknownFields(descriptor_->containing_type())) { - printer->Print(variables_, - " super.mergeVarintField($number$, rawValue);\n"); - } - printer->Print(variables_, + "$type$ value = $type$.forNumber(rawValue);\n" + "if (value == null) {\n" + // We store the unknown value in unknown fields. + " super.mergeVarintField($number$, rawValue);\n" "} else {\n" - " if (!$is_mutable$) {\n" - " $name$_ = newIntList();\n" - " }\n" " $name$_.addInt(rawValue);\n" "}\n"); } @@ -862,7 +838,11 @@ GenerateParsingCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateParsingCodeFromPacked(io::Printer* printer) const { - // Wrap GenerateParsingCode's contents with a while loop. + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" + "}\n"); printer->Print(variables_, "int length = input.readRawVarint32();\n" @@ -870,7 +850,21 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "while(input.getBytesUntilLimit() > 0) {\n"); printer->Indent(); - GenerateParsingCode(printer); + // Read and store the enum + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "$name$_.addInt(input.readEnum());\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.forNumber(rawValue);\n" + "if (value == null) {\n" + // We store the unknown value in unknown fields. + " super.mergeVarintField($number$, rawValue);\n" + "} else {\n" + " $name$_.addInt(rawValue);\n" + "}\n"); + } printer->Outdent(); printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h index 2c41c3e4..9201b8d6 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.h +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h @@ -67,7 +67,7 @@ class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -101,7 +101,7 @@ class ImmutableEnumOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -127,7 +127,7 @@ class RepeatedImmutableEnumFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingCodeFromPacked(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index ed415eee..c22da8d7 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -141,7 +141,15 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { " return value;\n" "}\n" "\n" + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -169,7 +177,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 4db7085e..46b5faaa 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -118,75 +118,38 @@ void ImmutableExtensionGenerator::Generate(io::Printer* printer) { "public static final int $constant_name$ = $number$;\n"); WriteFieldDocComment(printer, descriptor_); - if (HasDescriptorMethods(descriptor_->file())) { - // Non-lite extensions - if (descriptor_->extension_scope() == NULL) { - // Non-nested - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" - " .newFileScopedGeneratedExtension(\n" - " $singular_type$.class,\n" - " $prototype$);\n"); - } else { - // Nested - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" - " .newMessageScopedGeneratedExtension(\n" - " $scope$.getDefaultInstance(),\n" - " $index$,\n" - " $singular_type$.class,\n" - " $prototype$);\n"); - } + if (descriptor_->extension_scope() == NULL) { + // Non-nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newFileScopedGeneratedExtension(\n" + " $singular_type$.class,\n" + " $prototype$);\n"); } else { - // Lite extensions - if (descriptor_->is_repeated()) { - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" - " .newRepeatedGeneratedExtension(\n" - " $containing_type$.getDefaultInstance(),\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $packed$,\n" - " $singular_type$.class);\n"); - } else { - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" - " .newSingularGeneratedExtension(\n" - " $containing_type$.getDefaultInstance(),\n" - " $default$,\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $singular_type$.class);\n"); - } + // Nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newMessageScopedGeneratedExtension(\n" + " $scope$.getDefaultInstance(),\n" + " $index$,\n" + " $singular_type$.class,\n" + " $prototype$);\n"); } } int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( io::Printer* printer) { int bytecode_estimate = 0; - if (descriptor_->extension_scope() == NULL && - HasDescriptorMethods(descriptor_->file())) { - // Only applies to non-nested, non-lite extensions. + if (descriptor_->extension_scope() == NULL) { + // Only applies to non-nested extensions. printer->Print( "$name$.internalInit(descriptor.getExtensions().get($index$));\n", "name", UnderscoresToCamelCase(descriptor_), diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc index e69de29b..23261bac 100644 --- a/src/google/protobuf/compiler/java/java_extension_lite.cc +++ b/src/google/protobuf/compiler/java/java_extension_lite.cc @@ -0,0 +1,118 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/compiler/java/java_extension_lite.h> + +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator( + const FieldDescriptor* descriptor, Context* context) + : descriptor_(descriptor), context_(context), + name_resolver_(context->GetNameResolver()) { + if (descriptor_->extension_scope() != NULL) { + scope_ = name_resolver_->GetImmutableClassName( + descriptor_->extension_scope()); + } else { + scope_ = name_resolver_->GetImmutableClassName(descriptor_->file()); + } +} + +ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {} + +void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) { + map<string, string> vars; + const bool kUseImmutableNames = true; + InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_, + &vars); + printer->Print(vars, + "public static final int $constant_name$ = $number$;\n"); + + WriteFieldDocComment(printer, descriptor_); + if (descriptor_->is_repeated()) { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newRepeatedGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $packed$,\n" + " $singular_type$.class);\n"); + } else { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newSingularGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $default$,\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $singular_type$.class);\n"); + } +} + +int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode( + io::Printer* printer) { + return 0; +} + +int ImmutableExtensionLiteGenerator::GenerateRegistrationCode( + io::Printer* printer) { + printer->Print( + "registry.add($scope$.$name$);\n", + "scope", scope_, + "name", UnderscoresToCamelCase(descriptor_)); + return 7; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h index e69de29b..4cd49bda 100644 --- a/src/google/protobuf/compiler/java/java_extension_lite.h +++ b/src/google/protobuf/compiler/java/java_extension_lite.h @@ -0,0 +1,76 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ + +#include <map> +#include <string> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/java/java_extension.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Generates code for a lite extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ImmutableExtensionLiteGenerator : public ExtensionGenerator { + public: + explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor, + Context* context); + virtual ~ImmutableExtensionLiteGenerator(); + + virtual void Generate(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateNonNestedInitializationCode(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateRegistrationCode(io::Printer* printer); + + private: + const FieldDescriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + string scope_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index c5434767..3c7bc5c4 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -77,7 +77,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( return new ImmutableMapFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new RepeatedImmutableLazyMessageFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -99,7 +99,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( if (field->containing_oneof()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageOneofFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -119,7 +119,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( } else { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -150,7 +150,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( return new ImmutableMapFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new RepeatedImmutableLazyMessageFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -172,7 +172,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( if (field->containing_oneof()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageOneofFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -192,7 +192,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( } else { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 0e24da24..4dd4f57f 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -105,7 +105,7 @@ class ImmutableFieldLiteGenerator { virtual void GenerateMembers(io::Printer* printer) const = 0; virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; virtual void GenerateInitializationCode(io::Printer* printer) const = 0; - virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateVisitCode(io::Printer* printer) const = 0; virtual void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index c8172330..c53aae6b 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -177,7 +177,7 @@ void MaybeRestartJavaMethod(io::Printer* printer, // since otherwise we hit a hardcoded limit in the jvm and javac will // then fail with the error "code too large". This limit lets our // estimates be off by a factor of two and still we're okay. - static const int bytesPerMethod = 1<<15; // aka 32K + static const int bytesPerMethod = kMaxStaticSize; if ((*bytecode_estimate) > bytesPerMethod) { ++(*method_num); @@ -193,7 +193,8 @@ void MaybeRestartJavaMethod(io::Printer* printer, } // namespace -FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) +FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api, + bool enforce_lite) : file_(file), java_package_(FileJavaPackage(file, immutable_api)), message_generators_( @@ -204,6 +205,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) name_resolver_(context_->GetNameResolver()), immutable_api_(immutable_api) { classname_ = name_resolver_->GetFileClassName(file, immutable_api); + context_->SetEnforceLite(enforce_lite); generator_factory_.reset( new ImmutableGeneratorFactory(context_.get())); for (int i = 0; i < file_->message_type_count(); ++i) { @@ -262,7 +264,8 @@ void FileGenerator::Generate(io::Printer* printer) { printer->Print( "public static void registerAllExtensions(\n" " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n", - "lite", HasDescriptorMethods(file_) ? "" : "Lite"); + "lite", + HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite"); printer->Indent(); @@ -282,7 +285,7 @@ void FileGenerator::Generate(io::Printer* printer) { if (!MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) .Generate(printer); } else { @@ -294,7 +297,7 @@ void FileGenerator::Generate(io::Printer* printer) { message_generators_[i]->GenerateInterface(printer); message_generators_[i]->Generate(printer); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, context_->EnforceLite())) { for (int i = 0; i < file_->service_count(); i++) { google::protobuf::scoped_ptr<ServiceGenerator> generator( generator_factory_->NewServiceGenerator(file_->service(i))); @@ -309,14 +312,18 @@ void FileGenerator::Generate(io::Printer* printer) { extension_generators_[i]->Generate(printer); } - // Static variables. + // Static variables. We'd like them to be final if possible, but due to + // the JVM's 64k size limit on static blocks, we have to initialize some + // of them in methods; thus they cannot be final. + int static_block_bytecode_estimate = 0; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateStaticVariables(printer); + message_generators_[i]->GenerateStaticVariables( + printer, &static_block_bytecode_estimate); } printer->Print("\n"); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { if (immutable_api_) { GenerateDescriptorInitializationCodeForImmutable(printer); } else { @@ -358,9 +365,11 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( " getDescriptor() {\n" " return descriptor;\n" "}\n" - "private static com.google.protobuf.Descriptors.FileDescriptor\n" + "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" - "static {\n"); + "static {\n", + // TODO(dweis): Mark this as final. + "final", ""); printer->Indent(); SharedCodeGenerator shared_code_generator(file_); @@ -453,7 +462,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* " getDescriptor() {\n" " return descriptor;\n" "}\n" - "private static com.google.protobuf.Descriptors.FileDescriptor\n" + "private static final com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" "static {\n"); printer->Indent(); @@ -549,7 +558,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir, vector<string>* file_list) { if (MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { EnumGenerator generator(file_->enum_type(i), immutable_api_, context_.get()); GenerateSibling<EnumGenerator>(package_dir, java_package_, @@ -582,7 +591,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir, message_generators_[i].get(), &MessageGenerator::Generate); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, context_->EnforceLite())) { for (int i = 0; i < file_->service_count(); i++) { google::protobuf::scoped_ptr<ServiceGenerator> generator( generator_factory_->NewServiceGenerator(file_->service(i))); diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index 080b3424..7dbeb94e 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -67,7 +67,8 @@ namespace java { class FileGenerator { public: - FileGenerator(const FileDescriptor* file, bool immutable_api = true); + FileGenerator(const FileDescriptor* file, bool immutable_api = true, + bool enforce_lite = false); ~FileGenerator(); // Checks for problems that would otherwise lead to cryptic compile errors. diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index 6c6f7286..a46c7fc4 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -75,6 +75,7 @@ bool JavaGenerator::Generate(const FileDescriptor* file, bool generate_immutable_code = false; bool generate_mutable_code = false; bool generate_shared_code = false; + bool enforce_lite = false; for (int i = 0; i < options.size(); i++) { if (options[i].first == "output_list_file") { output_list_file = options[i].second; @@ -84,12 +85,21 @@ bool JavaGenerator::Generate(const FileDescriptor* file, generate_mutable_code = true; } else if (options[i].first == "shared") { generate_shared_code = true; + } else if (options[i].first == "lite") { + // When set, the protoc will generate the current files and all the + // transitive dependencies as lite runtime. + enforce_lite = true; } else { *error = "Unknown generator option: " + options[i].first; return false; } } + if (enforce_lite && generate_mutable_code) { + *error = "lite runtime generator option cannot be used with mutable API."; + return false; + } + // By default we generate immutable code and shared code for immutable API. if (!generate_immutable_code && !generate_mutable_code && !generate_shared_code) { @@ -105,10 +115,12 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector<FileGenerator*> file_generators; if (generate_immutable_code) { - file_generators.push_back(new FileGenerator(file, /* immutable = */ true)); + file_generators.push_back( + new FileGenerator(file, /* immutable = */ true, enforce_lite)); } if (generate_mutable_code) { - file_generators.push_back(new FileGenerator(file, /* mutable = */ false)); + file_generators.push_back( + new FileGenerator(file, /* mutable = */ false, enforce_lite)); } for (int i = 0; i < file_generators.size(); ++i) { if (!file_generators[i]->Validate(error)) { diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc index 92ef851b..3218b410 100644 --- a/src/google/protobuf/compiler/java/java_generator_factory.cc +++ b/src/google/protobuf/compiler/java/java_generator_factory.cc @@ -35,6 +35,7 @@ #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum_field.h> #include <google/protobuf/compiler/java/java_extension.h> +#include <google/protobuf/compiler/java/java_extension_lite.h> #include <google/protobuf/compiler/java/java_field.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_message.h> @@ -58,17 +59,20 @@ ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {} MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator( const Descriptor* descriptor) const { - if (descriptor->file()->options().optimize_for() == - FileOptions::LITE_RUNTIME) { - return new ImmutableMessageLiteGenerator(descriptor, context_); - } else { + if (HasDescriptorMethods(descriptor, context_->EnforceLite())) { return new ImmutableMessageGenerator(descriptor, context_); + } else { + return new ImmutableMessageLiteGenerator(descriptor, context_); } } ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator( const FieldDescriptor* descriptor) const { - return new ImmutableExtensionGenerator(descriptor, context_); + if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) { + return new ImmutableExtensionGenerator(descriptor, context_); + } else { + return new ImmutableExtensionLiteGenerator(descriptor, context_); + } } ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 5392d6d7..c850423e 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -170,44 +170,41 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field, } bool IsDefaultValueJavaDefault(const FieldDescriptor* field); -// Does this message class have generated parsing, serialization, and other -// standard methods for which reflection-based fallback implementations exist? -inline bool HasGeneratedMethods(const Descriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::CODE_SIZE; -} - // Does this message have specialized equals() and hashCode() methods? inline bool HasEqualsAndHashCode(const Descriptor* descriptor) { return descriptor->file()->options().java_generate_equals_and_hash(); } // Does this message class have descriptor and reflection methods? -inline bool HasDescriptorMethods(const Descriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const Descriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME; } -inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const EnumDescriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME; } -inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { - return descriptor->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const FileDescriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->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, bool enforce_lite) { return file->service_count() > 0 && - file->options().optimize_for() != FileOptions::LITE_RUNTIME && + HasDescriptorMethods(file, enforce_lite) && file->options().java_generic_services(); } -inline bool IsLazy(const FieldDescriptor* descriptor) { +inline bool IsLazy(const FieldDescriptor* descriptor, bool enforce_lite) { // Currently, the proto-lite version suports lazy field. // TODO(niwasaki): Support lazy fields also for other proto runtimes. - if (descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME) { + if (HasDescriptorMethods(descriptor->file(), enforce_lite)) { return false; } return descriptor->options().lazy(); diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc index 283ba1d3..62f39302 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc @@ -182,18 +182,17 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableLazyMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " $name$_.merge(other.$name$_);\n" - " $set_has_field_bit_message$;\n" - "}\n"); + "$name$_ = visitor.visitLazyMessage(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } void ImmutableLazyMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_.setByteString(input.readBytes(), extensionRegistry);\n"); + "$name$_.mergeFrom(input, extensionRegistry);\n"); printer->Print(variables_, "$set_has_field_bit_message$;\n"); } @@ -362,14 +361,12 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableLazyMessageOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!($has_oneof_case_message$)) {\n" - " $oneof_name$_ = new $lazy_type$();\n" - "}\n" - "(($lazy_type$) $oneof_name$_).merge(\n" - " ($lazy_type$) other.$oneof_name$_);\n" - "$set_oneof_case_message$;\n"); + "$oneof_name$_ = visitor.visitOneofLazyMessage(\n" + " $has_oneof_case_message$,\n" + " ($lazy_type$) $oneof_name$_,\n" + " ($lazy_type$) other.$oneof_name$_);\n"); } void ImmutableLazyMessageOneofFieldLiteGenerator:: @@ -378,8 +375,7 @@ GenerateParsingCode(io::Printer* printer) const { "if (!($has_oneof_case_message$)) {\n" " $oneof_name$_ = new $lazy_type$();\n" "}\n" - "(($lazy_type$) $oneof_name$_).setByteString(\n" - " input.readBytes(), extensionRegistry);\n" + "(($lazy_type$) $oneof_name$_).mergeFrom(input, extensionRegistry);\n" "$set_oneof_case_message$;\n"); } @@ -464,7 +460,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n" "\n"); @@ -679,7 +676,8 @@ void RepeatedImmutableLazyMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n" "$name$_.add(new com.google.protobuf.LazyFieldLite(\n" " extensionRegistry, input.readBytes()));\n"); diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h index e85ec0f3..47ebeb49 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h @@ -63,7 +63,7 @@ class ImmutableLazyMessageFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -82,7 +82,7 @@ class ImmutableLazyMessageOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 3e035c89..2a551ca4 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -79,9 +79,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, const FieldGeneratorInfo* info, - ClassNameResolver* name_resolver, + Context* context, map<string, string>* variables) { SetCommonFieldVariables(descriptor, info, variables); + ClassNameResolver* name_resolver = context->GetNameResolver(); (*variables)["type"] = name_resolver->GetImmutableClassName(descriptor->message_type()); @@ -123,8 +124,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; // For repeated fields, one bit is used for whether the array is immutable // in the parsing constructor. @@ -135,18 +135,12 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["default_entry"] = (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; - if (HasDescriptorMethods(descriptor->file())) { - (*variables)["lite"] = ""; - (*variables)["map_field_parameter"] = (*variables)["default_entry"]; - (*variables)["descriptor"] = - name_resolver->GetImmutableClassName(descriptor->file()) + - ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + - "_descriptor, "; - } else { - (*variables)["lite"] = "Lite"; - (*variables)["map_field_parameter"] = ""; - (*variables)["descriptor"] = ""; - } + (*variables)["lite"] = ""; + (*variables)["map_field_parameter"] = (*variables)["default_entry"]; + (*variables)["descriptor"] = + name_resolver->GetImmutableClassName(descriptor->file()) + + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + + "_descriptor, "; } } // namespace @@ -159,7 +153,7 @@ ImmutableMapFieldGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, context->GetFieldGeneratorInfo(descriptor), - name_resolver_, &variables_); + context, &variables_); } ImmutableMapFieldGenerator:: @@ -221,7 +215,7 @@ GenerateMembers(io::Printer* printer) const { " if ($name$_ == null) {\n" " return com.google.protobuf.MapField$lite$.emptyMapField(\n" " $map_field_parameter$);\n" - " }\n" + " }\n" " return $name$_;\n" "}\n"); if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { @@ -276,7 +270,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " if ($name$_ == null) {\n" " return com.google.protobuf.MapField$lite$.emptyMapField(\n" " $map_field_parameter$);\n" - " }\n" + " }\n" " return $name$_;\n" "}\n" "private com.google.protobuf.MapField$lite$<$type_parameters$>\n" @@ -424,7 +418,7 @@ GenerateParsingCode(io::Printer* printer) const { "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, - "if ($value_enum_type$.valueOf($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" 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 d2039403..b80d4139 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -79,10 +79,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, const FieldGeneratorInfo* info, - ClassNameResolver* name_resolver, + Context* context, map<string, string>* variables) { SetCommonFieldVariables(descriptor, info, variables); + ClassNameResolver* name_resolver = context->GetNameResolver(); (*variables)["type"] = name_resolver->GetImmutableClassName(descriptor->message_type()); const FieldDescriptor* key = KeyField(descriptor); @@ -123,8 +124,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; (*variables)["default_entry"] = (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; @@ -142,7 +141,7 @@ ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, context->GetFieldGeneratorInfo(descriptor), - name_resolver_, &variables_); + context, &variables_); } ImmutableMapFieldLiteGenerator:: @@ -375,10 +374,10 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableMapFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print( variables_, - "internalGetMutable$capitalized_name$().mergeFrom(\n" + "$name$_ = visitor.visitMap(internalGetMutable$capitalized_name$(),\n" " other.internalGet$capitalized_name$());\n"); } @@ -404,7 +403,7 @@ GenerateParsingCode(io::Printer* printer) const { "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, - "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n" " super.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h index a09cd536..555b5c5b 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.h +++ b/src/google/protobuf/compiler/java/java_map_field_lite.h @@ -52,7 +52,7 @@ class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 22a70c32..4c474a48 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -89,19 +89,20 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor) MessageGenerator::~MessageGenerator() {} // =================================================================== -// TODO(api): Move this class to a separate immutable_message.cc file. ImmutableMessageGenerator::ImmutableMessageGenerator( const Descriptor* descriptor, Context* context) : MessageGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_NE( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; } ImmutableMessageGenerator::~ImmutableMessageGenerator() {} -void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { +void ImmutableMessageGenerator::GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) { // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is // used in the construction of descriptors, we have a tricky bootstrapping // problem. To help control static initialization order, we make sure all @@ -124,23 +125,29 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { } else { vars["private"] = "private "; } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } // The descriptor for this type. printer->Print(vars, // TODO(teboring): final needs to be added back. The way to fix it is to // generate methods that can construct the types, and then still declare the // types, and then init them in clinit with the new method calls. - "$private$static com.google.protobuf.Descriptors.Descriptor\n" + "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n" " internal_$identifier$_descriptor;\n"); + *bytecode_estimate += 30; // And the FieldAccessorTable. - GenerateFieldAccessorTable(printer); + GenerateFieldAccessorTable(printer, bytecode_estimate); // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? ImmutableMessageGenerator(descriptor_->nested_type(i), context_) - .GenerateStaticVariables(printer); + .GenerateStaticVariables(printer, bytecode_estimate); } } @@ -183,7 +190,7 @@ int ImmutableMessageGenerator::GenerateStaticVariableInitializers( } void ImmutableMessageGenerator:: -GenerateFieldAccessorTable(io::Printer* printer) { +GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate) { map<string, string> vars; vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { @@ -193,10 +200,19 @@ GenerateFieldAccessorTable(io::Printer* printer) { } else { vars["private"] = "private "; } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } printer->Print(vars, - "$private$static\n" + "$private$static $final$\n" " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" " internal_$identifier$_fieldAccessorTable;\n"); + + // 6 bytes per field and oneof + *bytecode_estimate += 10 + 6 * descriptor_->field_count() + + 6 * descriptor_->oneof_decl_count(); } int ImmutableMessageGenerator:: @@ -342,7 +358,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print( "}\n"); - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateParsingConstructor(printer); } @@ -408,12 +424,20 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "cap_oneof_name", ToUpper(vars["oneof_name"])); printer->Print(vars, - "private int value = 0;\n" + "private final int value;\n" "private $oneof_capitalized_name$Case(int value) {\n" " this.value = value;\n" "}\n"); printer->Print(vars, + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -426,8 +450,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { } printer->Print( " case 0: return $cap_oneof_name$_NOT_SET;\n" - " default: throw new java.lang.IllegalArgumentException(\n" - " \"Value is undefined for this oneof enum.\");\n" + " default: return null;\n" " }\n" "}\n" "public int getNumber() {\n" @@ -440,7 +463,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n"); @@ -459,7 +482,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); } @@ -664,34 +687,40 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseDelimitedWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -1049,22 +1078,52 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); + // hashCode non-oneofs. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateHashCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } + } + } + + // hashCode oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "if (has$name$()) {\n", - "name", info->capitalized_name); + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); printer->Indent(); - } - field_generators_.get(field).GenerateHashCode(printer); - if (check_has_bits) { + field_generators_.get(field).GenerateHashCode(printer); + printer->Print("break;\n"); printer->Outdent(); - printer->Print("}\n"); } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); } + if (descriptor_->extension_range_count() > 0) { printer->Print( "hash = hashFields(hash, getExtensionFields());\n"); @@ -1105,7 +1164,8 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Print( "private $classname$(\n" " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n", + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", "classname", descriptor_->name()); printer->Indent(); @@ -1165,7 +1225,8 @@ GenerateParsingConstructor(io::Printer* printer) { "default: {\n" " if (!input.skipField(tag)) {\n" " done = true;\n" // it's an endgroup tag - " }\n" + " }\n"); + printer->Print( " break;\n" "}\n"); } @@ -1215,10 +1276,10 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Outdent(); printer->Print( "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" - " throw new RuntimeException(e.setUnfinishedMessage(this));\n" + " throw e.setUnfinishedMessage(this);\n" "} catch (java.io.IOException e) {\n" - " throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n" - " .setUnfinishedMessage(this));\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e).setUnfinishedMessage(this);\n" "} finally {\n"); printer->Indent(); @@ -1260,20 +1321,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n", "classname", descriptor_->name()); - if (HasGeneratedMethods(descriptor_)) { - // The parsing constructor throws an InvalidProtocolBufferException via a - // RuntimeException to aid in method pruning. We unwrap it here. + if (context_->HasGeneratedMethods(descriptor_)) { printer->Print( - " try {\n" - " return new $classname$(input, extensionRegistry);\n" - " } catch (RuntimeException e) {\n" - " if (e.getCause() instanceof\n" - " com.google.protobuf.InvalidProtocolBufferException) {\n" - " throw (com.google.protobuf.InvalidProtocolBufferException)\n" - " e.getCause();\n" - " }\n" - " throw e;\n" - " }\n", + " return new $classname$(input, extensionRegistry);\n", "classname", descriptor_->name()); } else { // When parsing constructor isn't generated, use builder to parse @@ -1328,14 +1378,39 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { printer->Print( "private static String getTypeUrl(\n" + " java.lang.String typeUrlPrefix,\n" " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" - " return \"type.googleapis.com/\" + descriptor.getFullName();\n" + " return typeUrlPrefix.endsWith(\"/\")\n" + " ? typeUrlPrefix + descriptor.getFullName()\n" + " : typeUrlPrefix + \"/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "private static String getTypeNameFromTypeUrl(\n" + " java.lang.String typeUrl) {\n" + " int pos = typeUrl.lastIndexOf('/');\n" + " return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n" "}\n" "\n" "public static <T extends com.google.protobuf.Message> Any pack(\n" " T message) {\n" " return Any.newBuilder()\n" - " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n" + " .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n" + " message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "/**\n" + " * Packs a message uisng the given type URL prefix. The type URL will\n" + " * be constructed by concatenating the message type's full name to the\n" + " * prefix with an optional \"/\" separator if the prefix doesn't end\n" + " * with \"/\" already.\n" + " */\n" + "public static <T extends com.google.protobuf.Message> Any pack(\n" + " T message, java.lang.String typeUrlPrefix) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(typeUrlPrefix,\n" + " message.getDescriptorForType()))\n" " .setValue(message.toByteString())\n" " .build();\n" "}\n" @@ -1344,8 +1419,8 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { " java.lang.Class<T> clazz) {\n" " T defaultInstance =\n" " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" - " return getTypeUrl().equals(\n" - " getTypeUrl(defaultInstance.getDescriptorForType()));\n" + " return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n" + " defaultInstance.getDescriptorForType().getFullName());\n" "}\n" "\n" "private volatile com.google.protobuf.Message cachedUnpackValue;\n" diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index be5bfb07..e9fc57c2 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -56,6 +56,8 @@ namespace protobuf { namespace compiler { namespace java { +static const int kMaxStaticSize = 1 << 15; // aka 32k + class MessageGenerator { public: explicit MessageGenerator(const Descriptor* descriptor); @@ -64,7 +66,8 @@ class MessageGenerator { // All static variables have to be declared at the top-level of the file // so that we can control initialization order, which is important for // DescriptorProto bootstrapping to work. - virtual void GenerateStaticVariables(io::Printer* printer) = 0; + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) = 0; // Output code which initializes the static variables generated by // GenerateStaticVariables(). Returns an estimate of bytecode size. @@ -96,14 +99,15 @@ class ImmutableMessageGenerator : public MessageGenerator { virtual void Generate(io::Printer* printer); virtual void GenerateInterface(io::Printer* printer); virtual void GenerateExtensionRegistrationCode(io::Printer* printer); - virtual void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate); // Returns an estimate of the number of bytes the printed code will compile to virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: - void GenerateFieldAccessorTable(io::Printer* printer); + void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate); // Returns an estimate of the number of bytes the printed code will compile to int GenerateFieldAccessorTableInitializer(io::Printer* printer); diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc index 5d535034..b3e9e986 100644 --- a/src/google/protobuf/compiler/java/java_message_builder.cc +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -81,8 +81,9 @@ MessageBuilderGenerator::MessageBuilderGenerator( : descriptor_(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_NE( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; } MessageBuilderGenerator::~MessageBuilderGenerator() {} @@ -113,7 +114,7 @@ Generate(io::Printer* printer) { GenerateDescriptorMethods(printer); GenerateCommonBuilderMethods(printer); - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateBuilderParsingMethods(printer); } @@ -134,7 +135,7 @@ Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" " get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" @@ -439,7 +440,7 @@ GenerateCommonBuilderMethods(io::Printer* printer) { // ----------------------------------------------------------------- - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { printer->Print( "public Builder mergeFrom(com.google.protobuf.Message other) {\n" " if (other instanceof $classname$) {\n" diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc index 8719d00d..dd429dc9 100644 --- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc @@ -81,8 +81,9 @@ MessageBuilderLiteGenerator::MessageBuilderLiteGenerator( : descriptor_(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_EQ( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; } MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {} @@ -148,20 +149,6 @@ Generate(io::Printer* printer) { .GenerateBuilderMembers(printer); } - if (!PreserveUnknownFields(descriptor_)) { - printer->Print( - "public final Builder setUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n" - "public final Builder mergeUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n"); - } - printer->Print( "\n" "// @@protoc_insertion_point(builder_scope:$full_name$)\n", diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b5f8e626..455516f6 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -70,8 +70,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. 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 356520ec..14281816 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -70,8 +70,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -288,11 +286,9 @@ void ImmutableMessageFieldLiteGenerator:: GenerateInitializationCode(io::Printer* printer) const {} void ImmutableMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " merge$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visitMessage($name$_, other.$name$_);\n"); } void ImmutableMessageFieldLiteGenerator:: @@ -302,11 +298,18 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { void ImmutableMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "$type$.Builder subBuilder = null;\n" - "if ($is_field_present_message$) {\n" - " subBuilder = $name$_.toBuilder();\n" - "}\n"); + // TODO(dweis): Update this code to avoid the builder allocation and instead + // only allocate a submessage that isn't made immutable. Rely on the top + // message calling makeImmutable once done to actually traverse the tree and + // finalize state. This will avoid: + // - transitive builder allocations + // - the extra transitive iteration for streamed fields + // - reallocations for copying repeated fields + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($is_field_present_message$) {\n" + " subBuilder = $name$_.toBuilder();\n" + "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, @@ -506,9 +509,12 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableMessageOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "merge$capitalized_name$(other.get$capitalized_name$());\n"); + "$oneof_name$_ = visitor.visitOneofMessage(\n" + " $has_oneof_case_message$,\n" + " $oneof_name$_,\n" + " other.$oneof_name$_);\n"); } void ImmutableMessageOneofFieldLiteGenerator:: @@ -635,7 +641,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n" "\n"); @@ -853,22 +860,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations (non-nested builder case): - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - " $on_changed$\n" - "}\n"); +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_= visitor.visitList($name$_, other.$name$_);\n"); } void RepeatedImmutableMessageFieldLiteGenerator:: @@ -881,7 +875,8 @@ void RepeatedImmutableMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h index ae26c06a..61321547 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.h +++ b/src/google/protobuf/compiler/java/java_message_field_lite.h @@ -67,7 +67,7 @@ class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -101,7 +101,7 @@ class ImmutableMessageOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -125,7 +125,7 @@ class RepeatedImmutableMessageFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 94ed2c39..d4d2593a 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -46,7 +46,7 @@ #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_enum_lite.h> -#include <google/protobuf/compiler/java/java_extension.h> +#include <google/protobuf/compiler/java/java_extension_lite.h> #include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_message_builder.h> @@ -87,19 +87,20 @@ ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator( : MessageGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_EQ( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; } ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {} void ImmutableMessageLiteGenerator::GenerateStaticVariables( - io::Printer* printer) { + io::Printer* printer, int* bytecode_estimate) { // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) - .GenerateStaticVariables(printer); + .GenerateStaticVariables(printer, bytecode_estimate); } } @@ -197,7 +198,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { } printer->Indent(); - GenerateParsingConstructor(printer); + + GenerateConstructor(printer); // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { @@ -259,12 +261,20 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { "cap_oneof_name", ToUpper(vars["oneof_name"])); printer->Print(vars, - "private int value = 0;\n" + "private final int value;\n" "private $oneof_capitalized_name$Case(int value) {\n" " this.value = value;\n" "}\n"); printer->Print(vars, + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -277,8 +287,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { } printer->Print( " case 0: return $cap_oneof_name$_NOT_SET;\n" - " default: throw new java.lang.IllegalArgumentException(\n" - " \"Value is undefined for this oneof enum.\");\n" + " default: return null;\n" " }\n" "}\n" "public int getNumber() {\n" @@ -291,7 +300,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" @@ -313,11 +322,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateMessageSerializationMethods(printer); - if (HasEqualsAndHashCode(descriptor_)) { - GenerateEqualsAndHashCode(printer); - } - - GenerateParseFromMethods(printer); GenerateBuilder(printer); @@ -334,16 +338,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" " Object arg0, Object arg1) {\n" " switch (method) {\n" - " case PARSE_PARTIAL_FROM: {\n" - " return new $classname$(" - " (com.google.protobuf.CodedInputStream) arg0,\n" - " (com.google.protobuf.ExtensionRegistryLite) arg1);\n" - " }\n" - " case NEW_INSTANCE: {\n" - " return new $classname$(\n" - " com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" + " case NEW_MUTABLE_INSTANCE: {\n" + " return new $classname$();\n" " }\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -374,10 +370,18 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "}\n" - "case MERGE_FROM: {\n"); + "case VISIT: {\n"); printer->Indent(); - GenerateDynamicMethodMergeFrom(printer); + GenerateDynamicMethodVisit(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case MERGE_FROM_STREAM: {\n"); + + printer->Indent(); + GenerateDynamicMethodMergeFromStream(printer); printer->Outdent(); printer->Print( @@ -425,11 +429,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "static {\n" - " DEFAULT_INSTANCE = new $classname$(\n" - " com.google.protobuf.Internal\n" - " .EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" + " DEFAULT_INSTANCE = new $classname$();\n" + " DEFAULT_INSTANCE.makeImmutable();\n" "}\n" "\n", "classname", descriptor_->name()); @@ -446,7 +447,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. for (int i = 0; i < descriptor_->extension_count(); i++) { - ImmutableExtensionGenerator(descriptor_->extension(i), context_) + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) .Generate(printer); } @@ -557,9 +558,6 @@ GenerateMessageSerializationMethods(io::Printer* printer) { " return size;\n" "}\n" "\n"); - - printer->Print( - "private static final long serialVersionUID = 0L;\n"); } void ImmutableMessageLiteGenerator:: @@ -571,54 +569,62 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseDelimitedFrom(input);\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseDelimitedFrom(input, extensionRegistry);\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -789,11 +795,13 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( io::Printer* printer) { + // Output generation code for each field. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) .GenerateDynamicMethodMakeImmutableCode(printer); } + printer->Print( "return null;\n"); } @@ -808,19 +816,17 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( // =================================================================== -void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( +void ImmutableMessageLiteGenerator::GenerateDynamicMethodVisit( io::Printer* printer) { printer->Print( - // Optimization: If other is the default instance, we know none of its - // fields are set so we can skip the merge. - "if (arg0 == $classname$.getDefaultInstance()) return this;\n" - "$classname$ other = ($classname$) arg0;\n", + "Visitor visitor = (Visitor) arg0;\n" + "$classname$ other = ($classname$) arg1;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { field_generators_.get( - descriptor_->field(i)).GenerateMergingCode(printer); + descriptor_->field(i)).GenerateVisitCode(printer); } } @@ -839,7 +845,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( "field_name", ToUpper(field->name())); printer->Indent(); - field_generators_.get(field).GenerateMergingCode(printer); + field_generators_.get(field).GenerateVisitCode(printer); printer->Print( "break;\n"); printer->Outdent(); @@ -848,188 +854,66 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( } printer->Print( "case $cap_oneof_name$_NOT_SET: {\n" + " visitor.visitOneofNotSet($oneof_name$Case_ != 0);\n" " break;\n" "}\n", "cap_oneof_name", ToUpper(context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name)); + descriptor_->oneof_decl(i))->name), + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); printer->Outdent(); printer->Print( "}\n"); } - // if message type has extensions - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "this.mergeExtensionFields(other);\n"); - } - - if (PreserveUnknownFields(descriptor_)) { - printer->Print( - "this.mergeUnknownFields(other.unknownFields);\n"); - } - printer->Print( - "return this;\n"); -} - -// =================================================================== - -namespace { -bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { - if (field->is_repeated()) { - return false; - } - if (SupportFieldPresence(field->file())) { - return true; - } - return GetJavaType(field) == JAVATYPE_MESSAGE && - field->containing_oneof() == NULL; -} -} // namespace - -void ImmutableMessageLiteGenerator:: -GenerateEqualsAndHashCode(io::Printer* printer) { - printer->Print( - "@java.lang.Override\n" - "public boolean equals(final java.lang.Object obj) {\n"); + "if (visitor == com.google.protobuf.GeneratedMessageLite.MergeFromVisitor\n" + " .INSTANCE) {\n"); printer->Indent(); - printer->Print( - "if (obj == this) {\n" - " return true;\n" - "}\n" - "if (!(obj instanceof $classname$)) {\n" - " return super.equals(obj);\n" - "}\n" - "$classname$ other = ($classname$) obj;\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - printer->Print("boolean result = true;\n"); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { - printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print( - "}\n"); - } - } - if (PreserveUnknownFields(descriptor_)) { - // Always consider unknown fields for equality. This will sometimes return - // false for non-canonical ordering when running in LITE_RUNTIME but it's - // the best we can do. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + const OneofDescriptor* field = descriptor_->oneof_decl(i); printer->Print( - "result = result && unknownFields.equals(other.unknownFields);\n"); + "if (other.$oneof_name$Case_ != 0) {\n" + " $oneof_name$Case_ = other.$oneof_name$Case_;\n" + "}\n", + "oneof_name", context_->GetOneofGeneratorInfo(field)->name); } - printer->Print( - "return result;\n"); - printer->Outdent(); - printer->Print( - "}\n" - "\n"); - - printer->Print( - "@java.lang.Override\n" - "public int hashCode() {\n"); - printer->Indent(); - printer->Print( - "if (memoizedHashCode != 0) {\n"); - printer->Indent(); - printer->Print( - "return memoizedHashCode;\n"); - printer->Outdent(); - printer->Print( - "}\n" - "int hash = 41;\n"); - // Include the hash of the class so that two objects with different types - // but the same field values will probably have different hashes. - printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + for (int i = 0; i < totalInts; i++) { printer->Print( - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateHashCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print("}\n"); + "$bit_field_name$ |= other.$bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); } } - - printer->Print( - "hash = (29 * hash) + unknownFields.hashCode();\n"); - printer->Print( - "memoizedHashCode = hash;\n" - "return hash;\n"); printer->Outdent(); printer->Print( - "}\n" - "\n"); -} + "}\n"); -// =================================================================== -void ImmutableMessageLiteGenerator:: -GenerateExtensionRegistrationCode(io::Printer* printer) { - for (int i = 0; i < descriptor_->extension_count(); i++) { - ImmutableExtensionGenerator(descriptor_->extension(i), context_) - .GenerateRegistrationCode(printer); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) - .GenerateExtensionRegistrationCode(printer); - } + printer->Print( + "return this;\n"); } // =================================================================== -void ImmutableMessageLiteGenerator:: -GenerateParsingConstructor(io::Printer* printer) { - google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields( - SortFieldsByNumber(descriptor_)); - - printer->Print( - "private $classname$(\n" - " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n", - "classname", descriptor_->name()); - printer->Indent(); - - // Initialize all fields to default. - GenerateInitializers(printer); - - // Use builder bits to track mutable repeated fields. - int totalBuilderBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - const ImmutableFieldLiteGenerator& field = - field_generators_.get(descriptor_->field(i)); - totalBuilderBits += field.GetNumBitsForBuilder(); - } - int totalBuilderInts = (totalBuilderBits + 31) / 32; - for (int i = 0; i < totalBuilderInts; i++) { - printer->Print("int mutable_$bit_field_name$ = 0;\n", - "bit_field_name", GetBitFieldName(i)); - } +void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream( + io::Printer* printer) { printer->Print( + "com.google.protobuf.CodedInputStream input =\n" + " (com.google.protobuf.CodedInputStream) arg0;\n" + "com.google.protobuf.ExtensionRegistryLite extensionRegistry =\n" + " (com.google.protobuf.ExtensionRegistryLite) arg1;\n" "try {\n"); printer->Indent(); @@ -1077,6 +961,8 @@ GenerateParsingConstructor(io::Printer* printer) { "}\n"); } + google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields( + SortFieldsByNumber(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormatLite::MakeTag(field->number(), @@ -1130,19 +1016,54 @@ GenerateParsingConstructor(io::Printer* printer) { "} finally {\n"); printer->Indent(); - // Make repeated field list immutable. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = sorted_fields[i]; - field_generators_.get(field).GenerateParsingDoneCode(printer); + printer->Outdent(); + printer->Print( + "}\n"); // finally +} + +// =================================================================== + +namespace { +bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { + if (field->is_repeated()) { + return false; + } + if (SupportFieldPresence(field->file())) { + return true; + } + return GetJavaType(field) == JAVATYPE_MESSAGE && + field->containing_oneof() == NULL; +} +} // namespace + +// =================================================================== + +void ImmutableMessageLiteGenerator:: +GenerateExtensionRegistrationCode(io::Printer* printer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) + .GenerateRegistrationCode(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateExtensionRegistrationCode(printer); } +} +// =================================================================== +void ImmutableMessageLiteGenerator:: +GenerateConstructor(io::Printer* printer) { printer->Print( - "doneParsing();\n"); + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + GenerateInitializers(printer); - printer->Outdent(); printer->Outdent(); printer->Print( - " }\n" // finally "}\n"); } @@ -1167,7 +1088,6 @@ void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) { } } - } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h index 2bd3cdd4..292c1c56 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.h +++ b/src/google/protobuf/compiler/java/java_message_lite.h @@ -54,7 +54,8 @@ class ImmutableMessageLiteGenerator : public MessageGenerator { virtual void Generate(io::Printer* printer); virtual void GenerateInterface(io::Printer* printer); virtual void GenerateExtensionRegistrationCode(io::Printer* printer); - virtual void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate); virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: @@ -69,12 +70,13 @@ class ImmutableMessageLiteGenerator : public MessageGenerator { void GenerateBuilder(io::Printer* printer); void GenerateDynamicMethodIsInitialized(io::Printer* printer); void GenerateDynamicMethodMakeImmutable(io::Printer* printer); - void GenerateDynamicMethodMergeFrom(io::Printer* printer); + void GenerateDynamicMethodVisit(io::Printer* printer); + void GenerateDynamicMethodMergeFromStream(io::Printer* printer); void GenerateDynamicMethodNewBuilder(io::Printer* printer); void GenerateInitializers(io::Printer* printer); void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); - void GenerateParsingConstructor(io::Printer* printer); + void GenerateConstructor(io::Printer* printer); Context* context_; ClassNameResolver* name_resolver_; diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc index 0c363f9f..bffe4f16 100644 --- a/src/google/protobuf/compiler/java/java_name_resolver.cc +++ b/src/google/protobuf/compiler/java/java_name_resolver.cc @@ -259,6 +259,13 @@ string ClassNameResolver::GetJavaImmutableClassName( descriptor->file(), true); } +string ClassNameResolver::GetJavaImmutableClassName( + const EnumDescriptor* descriptor) { + return GetJavaClassFullName( + ClassNameWithoutPackage(descriptor, true), + descriptor->file(), true); +} + } // namespace java } // namespace compiler diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h index ab60b0a0..570d8d8f 100644 --- a/src/google/protobuf/compiler/java/java_name_resolver.h +++ b/src/google/protobuf/compiler/java/java_name_resolver.h @@ -98,6 +98,7 @@ class ClassNameResolver { // For example: // com.package.OuterClass$OuterMessage$InnerMessage string GetJavaImmutableClassName(const Descriptor* descriptor); + string GetJavaImmutableClassName(const EnumDescriptor* descriptor); private: // Get the full name of a Java class by prepending the Java package name // or outer class name. diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc index fe527623..3e4910c8 100644 --- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -44,9 +44,10 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -#include <google/protobuf/testing/file.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 178bbe19..e42ec280 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -75,12 +75,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); (*variables)["capitalized_type"] = GetCapitalizedType(descriptor, /* immutable = */ true); - if (descriptor->is_packed()) { - (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag( - descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); - } else { - (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); - } + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { @@ -99,8 +94,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -606,7 +600,7 @@ GenerateMembers(io::Printer* printer) const { "}\n"); if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 5a7bf82d..690dad12 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -86,9 +86,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, case JAVATYPE_BOOLEAN: (*variables)["field_list_type"] = "com.google.protobuf.Internal." + capitalized_type + "List"; - (*variables)["new_list"] = "new" + capitalized_type + "List"; - (*variables)["new_list_with_capacity"] = - "new" + capitalized_type + "ListWithCapacity"; (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; @@ -98,19 +95,21 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["name"] + "_.add" + capitalized_type; (*variables)["repeated_set"] = (*variables)["name"] + "_.set" + capitalized_type; + (*variables)["visit_type"] = capitalized_type; + (*variables)["visit_type_list"] = "visit" + capitalized_type + "List"; break; default: (*variables)["field_list_type"] = "com.google.protobuf.Internal.ProtobufList<" + (*variables)["boxed_type"] + ">"; - (*variables)["new_list"] = "newProtobufList"; - (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity"; (*variables)["empty_list"] = "emptyProtobufList()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; (*variables)["repeated_get"] = (*variables)["name"] + "_.get"; (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; + (*variables)["visit_type"] = "ByteString"; + (*variables)["visit_type_list"] = "visitList"; } if (IsReferenceType(GetJavaType(descriptor))) { @@ -129,8 +128,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -299,17 +296,16 @@ GenerateBuilderClearCode(io::Printer* printer) const { } void ImmutablePrimitiveFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visit$visit_type$(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else { printer->Print(variables_, - "if (other.get$capitalized_name$() != $default$) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visit$visit_type$($name$_ != $default$, $name$_,\n" + " other.$name$_ != $default$, other.$name$_);\n"); } } @@ -541,9 +537,10 @@ GenerateBuildingCode(io::Printer* printer) const { } void ImmutablePrimitiveOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); + "$oneof_name$_ = visitor.visitOneof$visit_type$(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutablePrimitiveOneofFieldLiteGenerator:: @@ -635,7 +632,7 @@ GenerateMembers(io::Printer* printer) const { "}\n"); if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); } @@ -643,7 +640,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = $new_list$($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); @@ -744,22 +742,9 @@ GenerateBuilderClearCode(io::Printer* printer) const { } void RepeatedImmutablePrimitiveFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - " $on_changed$\n" - "}\n"); +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_= visitor.$visit_type_list$($name$_, other.$name$_);\n"); } void RepeatedImmutablePrimitiveFieldLiteGenerator:: @@ -780,7 +765,8 @@ GenerateParsingCode(io::Printer* printer) const { // TODO(dweis): Scan the input buffer to count and ensure capacity. printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = $new_list$();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n" "$repeated_add$(input.read$capitalized_type$());\n"); } @@ -797,10 +783,13 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { // TODO(dweis): Scan the input buffer to count, then initialize // appropriately. printer->Print(variables_, - " $name$_ = $new_list$();\n"); + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"); } else { printer->Print(variables_, - " $name$_ = $new_list_with_capacity$(length/$fixed_size$);\n"); + " final int currentSize = $name$_.size();\n" + " $name$_ = $name$_.mutableCopyWithCapacity(\n" + " currentSize + (length/$fixed_size$));\n"); } // TODO(dweis): Scan the input buffer to count and ensure capacity. diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h index ad603c2a..6cfbbb98 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.h +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h @@ -69,7 +69,7 @@ class ImmutablePrimitiveFieldLiteGenerator void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; void GenerateBuilderClearCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -105,7 +105,7 @@ class ImmutablePrimitiveOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -130,7 +130,7 @@ class RepeatedImmutablePrimitiveFieldLiteGenerator void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; void GenerateBuilderClearCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; 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 70177367..74253c3f 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -52,8 +52,9 @@ namespace compiler { namespace java { SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file) - : name_resolver_(new ClassNameResolver), file_(file) { -} + : name_resolver_(new ClassNameResolver), + enforce_lite_(false), + file_(file) {} SharedCodeGenerator::~SharedCodeGenerator() { } @@ -63,7 +64,7 @@ void SharedCodeGenerator::Generate(GeneratorContext* context, string java_package = FileJavaPackage(file_); string package_dir = JavaPackageToDir(java_package); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, enforce_lite_)) { // Generate descriptors. string classname = name_resolver_->GetDescriptorClassName(file_); string filename = package_dir + classname + ".java"; diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h index 38a32fc2..3b573c07 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.h +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h @@ -72,6 +72,10 @@ class SharedCodeGenerator { void Generate(GeneratorContext* generator_context, vector<string>* file_list); + void SetEnforceLite(bool value) { + enforce_lite_ = value; + } + void GenerateDescriptors(io::Printer* printer); private: @@ -81,6 +85,7 @@ class SharedCodeGenerator { bool ShouldIncludeDependency(const FileDescriptor* descriptor); google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_; + bool enforce_lite_; const FileDescriptor* file_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator); }; diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 7f757e47..b67eeb53 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -87,8 +87,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -408,15 +407,6 @@ GenerateParsingCode(io::Printer* printer) const { "java.lang.String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n" - "$set_has_field_bit_message$\n" - "$name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -668,15 +658,6 @@ GenerateParsingCode(io::Printer* printer) const { "java.lang.String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n" - "$set_oneof_case_message$;\n" - "$oneof_name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -934,13 +915,6 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "java.lang.String s = input.readStringRequireUtf8();\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n"); @@ -950,7 +924,7 @@ GenerateParsingCode(io::Printer* printer) const { " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" "}\n"); - if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { + if (CheckUtf8(descriptor_)) { printer->Print(variables_, "$name$_.add(s);\n"); } else { diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index eb5964bd..0b92c021 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -84,8 +84,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -103,7 +101,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_message"] = ""; (*variables)["is_field_present_message"] = - "!get" + (*variables)["capitalized_name"] + ".isEmpty()"; + "!" + (*variables)["name"] + "_.isEmpty()"; } // For repeated builders, the underlying list tracks mutability state. @@ -301,22 +299,16 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableStringFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { - // Allow a slight breach of abstraction here in order to avoid forcing - // all string fields to Strings when copying fields from a Message. printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " $set_has_field_bit_message$\n" - " $name$_ = other.$name$_;\n" - " $on_changed$\n" - "}\n"); + "$name$_ = visitor.visitString(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else { printer->Print(variables_, - "if (!other.get$capitalized_name$().isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " $on_changed$\n" - "}\n"); + "$name$_ = visitor.visitString(!$name$_.isEmpty(), $name$_,\n" + " !other.$name$_.isEmpty(), other.$name$_);\n"); } } @@ -523,13 +515,10 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableStringOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // Allow a slight breach of abstraction here in order to avoid forcing - // all string fields to Strings when copying fields from a Message. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "$set_oneof_case_message$;\n" - "$oneof_name$_ = other.$oneof_name$_;\n" - "$on_changed$\n"); + "$oneof_name$_ = visitor.visitOneofString(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutableStringOneofFieldLiteGenerator:: @@ -650,8 +639,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n" - " $name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); @@ -778,22 +767,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableStringFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - " $on_changed$\n" - "}\n"); +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_= visitor.visitList($name$_, other.$name$_);\n"); } void RepeatedImmutableStringFieldLiteGenerator:: @@ -817,15 +793,11 @@ GenerateParsingCode(io::Printer* printer) const { } printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n"); - if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { - printer->Print(variables_, - "$name$_.add(s);\n"); - } else { - printer->Print(variables_, - "$name$_.add(bs);\n"); - } + printer->Print(variables_, + "$name$_.add(s);\n"); } void RepeatedImmutableStringFieldLiteGenerator:: diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h index 4d9b4bd7..4148aa4d 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.h +++ b/src/google/protobuf/compiler/java/java_string_field_lite.h @@ -68,7 +68,7 @@ class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -103,7 +103,7 @@ class ImmutableStringOneofFieldLiteGenerator private: void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -126,7 +126,7 @@ class RepeatedImmutableStringFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index a33eba1b..7c3a0421 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -68,12 +68,10 @@ void UpdateParamsRecursively(Params& params, } if (file->options().has_java_package()) { string result = file->options().java_package(); - if (!file->options().javanano_use_deprecated_package()) { - if (!result.empty()) { - result += "."; - } - result += "nano"; + if (!result.empty()) { + result += "."; } + result += "nano"; params.set_java_package( file->name(), result); } diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc index 5465655f..02811a24 100644 --- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -201,12 +201,10 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) { result += file->package(); } - if (!file->options().javanano_use_deprecated_package()) { - if (!result.empty()) { - result += "."; - } - result += "nano"; + if (!result.empty()) { + result += "."; } + result += "nano"; return result; } diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index 0de7e2c6..3de61e80 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/js/js_generator.h> +#include "google/protobuf/compiler/js/js_generator.h" #include <assert.h> #include <algorithm> @@ -123,6 +123,16 @@ static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*); namespace { +// The mode of operation for bytes fields. Historically JSPB always carried +// bytes as JS {string}, containing base64 content by convention. With binary +// and proto3 serialization the new convention is to represent it as binary +// data in Uint8Array. See b/26173701 for background on the migration. +enum BytesMode { + BYTES_DEFAULT, // Default type for getBytesField to return. + BYTES_B64, // Explicitly coerce to base64 string where needed. + BYTES_U8, // Explicitly coerce to Uint8Array where needed. +}; + bool IsReserved(const string& ident) { for (int i = 0; i < kNumKeyword; i++) { if (ident == kKeyword[i]) { @@ -134,7 +144,7 @@ bool IsReserved(const string& ident) { // Returns a copy of |filename| with any trailing ".protodevel" or ".proto // suffix stripped. -// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc. +// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. string StripProto(const string& filename) { const char* suffix = HasSuffixString(filename, ".protodevel") ? ".protodevel" : ".proto"; @@ -144,9 +154,7 @@ string StripProto(const string& filename) { // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript // file foo/bar/baz.js. string GetJSFilename(const string& filename) { - const char* suffix = HasSuffixString(filename, ".protodevel") - ? ".protodevel" : ".proto"; - return StripSuffixString(filename, suffix) + "_pb.js"; + return StripProto(filename) + "_pb.js"; } // Given a filename like foo/bar/baz.proto, returns the root directory @@ -385,15 +393,47 @@ string ToFileName(const string& input) { return result; } +// When we're generating one output file per type name, this is the filename +// that top-level extensions should go in. +string GetExtensionFileName(const GeneratorOptions& options, + const FileDescriptor* file) { + return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js"; +} + +// 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"; +} + +// 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"; +} + // Returns the message/response ID, if set. string GetMessageId(const Descriptor* desc) { return string(); } +bool IgnoreExtensionField(const FieldDescriptor* field) { + // Exclude descriptor extensions from output "to avoid clutter" (from original + // codegen). + return field->is_extension() && + field->containing_type()->file()->name() == + "google/protobuf/descriptor.proto"; +} + // Used inside Google only -- do not remove. bool IsResponse(const Descriptor* desc) { return false; } -bool IgnoreField(const FieldDescriptor* field) { return false; } + +bool IgnoreField(const FieldDescriptor* field) { + return IgnoreExtensionField(field); +} // Does JSPB ignore this entire oneof? True only if all fields are ignored. @@ -438,12 +478,32 @@ string JSObjectFieldName(const FieldDescriptor* field) { return name; } +string JSByteGetterSuffix(BytesMode bytes_mode) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return ""; + case BYTES_B64: + return "B64"; + case BYTES_U8: + return "U8"; + default: + assert(false); + } +} + // Returns the field name as a capitalized portion of a getter/setter method // name, e.g. MyField for .getMyField(). -string JSGetterName(const FieldDescriptor* field) { +string JSGetterName(const FieldDescriptor* field, + BytesMode bytes_mode = BYTES_DEFAULT) { string name = JSIdent(field, /* is_upper_camel = */ true, /* is_map = */ false); + if (field->type() == FieldDescriptor::TYPE_BYTES) { + string suffix = JSByteGetterSuffix(bytes_mode); + if (!suffix.empty()) { + name += "_as" + suffix; + } + } if (name == "Extension" || name == "JsPbMessageId") { // Avoid conflicts with base-class names. name += "$"; @@ -504,8 +564,7 @@ string JSOneofIndex(const OneofDescriptor* oneof) { return SimpleItoa(index); } -// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only -// need to handle the BMP (16-bit range) here. +// Decodes a codepoint in \x0000 -- \xFFFF. uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { if (*length == 0) { return 0; @@ -542,80 +601,56 @@ uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { } // Escapes the contents of a string to be included within double-quotes ("") in -// JavaScript. |is_utf8| determines whether the input data (in a C++ string of -// chars) is UTF-8 encoded (in which case codepoints become JavaScript string -// characters, escaped with 16-bit hex escapes where necessary) or raw binary -// (in which case bytes become JavaScript string characters 0 -- 255). -string EscapeJSString(const string& in, bool is_utf8) { - string result; +// JavaScript. The input data should be a UTF-8 encoded C++ string of chars. +// Returns false if |out| was truncated because |in| contained invalid UTF-8 or +// codepoints outside the BMP. +// TODO(lukestebbing): Support codepoints outside the BMP. +bool EscapeJSString(const string& in, string* out) { size_t decoded = 0; for (size_t i = 0; i < in.size(); i += decoded) { uint16 codepoint = 0; - if (is_utf8) { - // Decode the next UTF-8 codepoint. - size_t have_bytes = in.size() - i; - uint8 bytes[3] = { + // Decode the next UTF-8 codepoint. + size_t have_bytes = in.size() - i; + uint8 bytes[3] = { static_cast<uint8>(in[i]), static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0), static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0), - }; - codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); - if (have_bytes == 0) { - break; - } - decoded = have_bytes; - } else { - codepoint = static_cast<uint16>(static_cast<uint8>(in[i])); - decoded = 1; + }; + codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); + if (have_bytes == 0) { + return false; } - - // Next byte -- used for minimal octal escapes below. - char next_byte = (i + decoded) < in.size() ? - in[i + decoded] : 0; - bool pad_octal = (next_byte >= '0' && next_byte <= '7'); + decoded = have_bytes; switch (codepoint) { - case '\0': result += pad_octal ? "\\000" : "\\0"; break; - case '\b': result += "\\\b"; break; - case '\t': result += "\\\t"; break; - case '\n': result += "\\\n"; break; - case '\r': result += "\\\r"; break; - case '\f': result += "\\\f"; break; - case '\\': result += "\\\\"; break; - case '"': result += pad_octal ? "\\042" : "\\42"; break; - case '&': result += pad_octal ? "\\046" : "\\46"; break; - case '\'': result += pad_octal ? "\\047" : "\\47"; break; - case '<': result += pad_octal ? "\\074" : "\\74"; break; - case '=': result += pad_octal ? "\\075" : "\\75"; break; - case '>': result += pad_octal ? "\\076" : "\\76"; break; + case '\'': *out += "\\x27"; break; + case '"': *out += "\\x22"; break; + case '<': *out += "\\x3c"; break; + case '=': *out += "\\x3d"; break; + case '>': *out += "\\x3e"; break; + case '&': *out += "\\x26"; break; + case '\b': *out += "\\b"; break; + case '\t': *out += "\\t"; break; + case '\n': *out += "\\n"; break; + case '\f': *out += "\\f"; break; + case '\r': *out += "\\r"; break; + case '\\': *out += "\\\\"; break; default: - // All other non-ASCII codepoints are escaped. - // Original codegen uses hex for >= 0x100 and octal for others. + // TODO(lukestebbing): Once we're supporting codepoints outside the BMP, + // use a single Unicode codepoint escape if the output language is + // ECMAScript 2015 or above. Otherwise, use a surrogate pair. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals if (codepoint >= 0x20 && codepoint <= 0x7e) { - result += static_cast<char>(codepoint); + *out += static_cast<char>(codepoint); + } else if (codepoint >= 0x100) { + *out += StringPrintf("\\u%04x", codepoint); } else { - if (codepoint >= 0x100) { - result += StringPrintf("\\u%04x", codepoint); - } else { - if (pad_octal || codepoint >= 0100) { - result += "\\"; - result += ('0' + ((codepoint >> 6) & 07)); - result += ('0' + ((codepoint >> 3) & 07)); - result += ('0' + ((codepoint >> 0) & 07)); - } else if (codepoint >= 010) { - result += "\\"; - result += ('0' + ((codepoint >> 3) & 07)); - result += ('0' + ((codepoint >> 0) & 07)); - } else { - result += "\\"; - result += ('0' + ((codepoint >> 0) & 07)); - } - } + *out += StringPrintf("\\x%02x", codepoint); } break; } } - return result; + return true; } string EscapeBase64(const string& in) { @@ -740,11 +775,17 @@ string JSFieldDefault(const FieldDescriptor* field) { return DoubleToString(field->default_value_double()); case FieldDescriptor::CPPTYPE_STRING: if (field->type() == FieldDescriptor::TYPE_STRING) { - return "\"" + EscapeJSString(field->default_value_string(), true) + - "\""; - } else { - return "\"" + EscapeBase64(field->default_value_string()) + - "\""; + string out; + bool is_valid = EscapeJSString(field->default_value_string(), &out); + if (!is_valid) { + // TODO(lukestebbing): Decide whether this should be a hard error. + GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name() + << " was truncated since it contained invalid UTF-8 or" + " codepoints outside the basic multilingual plane."; + } + return "\"" + out + "\""; + } else { // Bytes + return "\"" + EscapeBase64(field->default_value_string()) + "\""; } case FieldDescriptor::CPPTYPE_MESSAGE: return "null"; @@ -801,8 +842,27 @@ string JSIntegerTypeName(const FieldDescriptor* field) { return "number"; } +string JSStringTypeName(const GeneratorOptions& options, + const FieldDescriptor* field, + BytesMode bytes_mode) { + if (field->type() == FieldDescriptor::TYPE_BYTES) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return "(string|Uint8Array)"; + case BYTES_B64: + return "string"; + case BYTES_U8: + return "Uint8Array"; + default: + assert(false); + } + } + return "string"; +} + string JSTypeName(const GeneratorOptions& options, - const FieldDescriptor* field) { + const FieldDescriptor* field, + BytesMode bytes_mode) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_BOOL: return "boolean"; @@ -819,7 +879,7 @@ string JSTypeName(const GeneratorOptions& options, case FieldDescriptor::CPPTYPE_DOUBLE: return "number"; case FieldDescriptor::CPPTYPE_STRING: - return "string"; + return JSStringTypeName(options, field, bytes_mode); case FieldDescriptor::CPPTYPE_ENUM: return GetPath(options, field->enum_type()); case FieldDescriptor::CPPTYPE_MESSAGE: @@ -836,20 +896,26 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options, bool force_optional, bool force_present, bool singular_if_not_packed, - bool always_singular) { + BytesMode bytes_mode = BYTES_DEFAULT) { bool is_primitive = (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && - field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE); + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && + (field->type() != FieldDescriptor::TYPE_BYTES || + bytes_mode == BYTES_B64)); - string jstype = JSTypeName(options, field); + string jstype = JSTypeName(options, field, bytes_mode); if (field->is_repeated() && - !always_singular && (field->is_packed() || !singular_if_not_packed)) { - if (!is_primitive) { - jstype = "!" + jstype; + if (field->type() == FieldDescriptor::TYPE_BYTES && + bytes_mode == BYTES_DEFAULT) { + jstype = "(Array<!Uint8Array>|Array<string>)"; + } else { + if (!is_primitive) { + jstype = "!" + jstype; + } + jstype = "Array.<" + jstype + ">"; } - jstype = "Array.<" + jstype + ">"; if (!force_optional) { jstype = "!" + jstype; } @@ -884,10 +950,6 @@ string JSBinaryReaderMethodType(const FieldDescriptor* field) { string JSBinaryReadWriteMethodName(const FieldDescriptor* field, bool is_writer) { string name = JSBinaryReaderMethodType(field); - if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) { - // Override for `bytes` fields: treat string as raw bytes, not base64. - name = "BytesRawString"; - } if (field->is_packed()) { name = "Packed" + name; } else if (is_writer && field->is_repeated()) { @@ -1044,7 +1106,7 @@ string FieldDefinition(const GeneratorOptions& options, field->number()); } -string FieldComments(const FieldDescriptor* field) { +string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { string comments; if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { comments += @@ -1060,6 +1122,11 @@ string FieldComments(const FieldDescriptor* field) { " * replace the array itself, then you must call the setter to " "update it.\n"; } + if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) { + comments += + " * Note that Uint8Array is not supported on all browsers.\n" + " * @see http://caniuse.com/Uint8Array\n"; + } return comments; } @@ -1070,8 +1137,10 @@ bool ShouldGenerateExtension(const FieldDescriptor* field) { } bool HasExtensions(const Descriptor* desc) { - if (desc->extension_count() > 0) { - return true; + for (int i = 0; i < desc->extension_count(); i++) { + if (ShouldGenerateExtension(desc->extension(i))) { + return true; + } } for (int i = 0; i < desc->nested_type_count(); i++) { if (HasExtensions(desc->nested_type(i))) { @@ -1123,7 +1192,7 @@ string GetPivot(const Descriptor* desc) { } // Returns true for fields that represent "null" as distinct from the default -// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information. +// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. bool HasFieldPresence(const FieldDescriptor* field) { return (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || @@ -1132,7 +1201,7 @@ bool HasFieldPresence(const FieldDescriptor* field) { } // For proto3 fields without presence, returns a string representing the default -// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more +// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more // information. string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { switch (field->cpp_type()) { @@ -1151,16 +1220,153 @@ string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_BOOL: return "false"; - case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: // includes BYTES return "\"\""; default: - // BYTES and MESSAGE are handled separately. + // MESSAGE is handled separately. assert(false); return ""; } } +// We use this to implement the semantics that same file can be generated +// multiple times, but the last one wins. We never actually write the files, +// but we keep a set of which descriptors were the final one for a given +// filename. +class FileDeduplicator { + public: + explicit FileDeduplicator(const GeneratorOptions& options) + : error_on_conflict_(options.error_on_name_conflict) {} + + bool AddFile(const string& filename, const void* desc, string* error) { + if (descs_by_filename_.find(filename) != descs_by_filename_.end()) { + if (error_on_conflict_) { + *error = "Name conflict: file name " + filename + + " would be generated by two descriptors"; + return false; + } + allowed_descs_.erase(descs_by_filename_[filename]); + } + + descs_by_filename_[filename] = desc; + allowed_descs_.insert(desc); + return true; + } + + void GetAllowedSet(set<const void*>* allowed_set) { + *allowed_set = allowed_descs_; + } + + private: + bool error_on_conflict_; + map<string, const void*> descs_by_filename_; + set<const void*> allowed_descs_; +}; + +void DepthFirstSearch(const FileDescriptor* file, + vector<const FileDescriptor*>* list, + set<const FileDescriptor*>* seen) { + if (!seen->insert(file).second) { + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + DepthFirstSearch(file->dependency(i), list, seen); + } + + // Add this file. + list->push_back(file); +} + +// A functor for the predicate to remove_if() below. Returns true if a given +// FileDescriptor is not in the given set. +class NotInSet { + public: + explicit NotInSet(const set<const FileDescriptor*>& file_set) + : file_set_(file_set) {} + + bool operator()(const FileDescriptor* file) { + return file_set_.count(file) == 0; + } + + private: + const set<const FileDescriptor*>& file_set_; +}; + +// This function generates an ordering of the input FileDescriptors that matches +// the logic of the old code generator. The order is significant because two +// different input files can generate the same output file, and the last one +// needs to win. +void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input, + vector<const FileDescriptor*>* ordered) { + // First generate an ordering of all reachable files (including dependencies) + // with depth-first search. This mimics the behavior of --include_imports, + // which is what the old codegen used. + ordered->clear(); + set<const FileDescriptor*> seen; + set<const FileDescriptor*> input_set; + for (int i = 0; i < input.size(); i++) { + DepthFirstSearch(input[i], ordered, &seen); + input_set.insert(input[i]); + } + + // Now remove the entries that are not actually in our input list. + ordered->erase( + std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)), + ordered->end()); +} + +// If we're generating code in file-per-type mode, avoid overwriting files +// by choosing the last descriptor that writes each filename and permitting +// only those to generate code. + +bool GenerateJspbAllowedSet(const GeneratorOptions& options, + const vector<const FileDescriptor*>& files, + set<const void*>* allowed_set, + string* error) { + vector<const FileDescriptor*> files_ordered; + GenerateJspbFileOrder(files, &files_ordered); + + // Choose the last descriptor for each filename. + FileDeduplicator dedup(options); + for (int i = 0; i < files_ordered.size(); i++) { + for (int j = 0; j < files_ordered[i]->message_type_count(); j++) { + const Descriptor* desc = files_ordered[i]->message_type(j); + if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) { + return false; + } + } + for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) { + const EnumDescriptor* desc = files_ordered[i]->enum_type(j); + if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) { + return false; + } + } + + // Pull out all free-floating extensions and generate files for those too. + bool has_extension = false; + + for (int j = 0; j < files_ordered[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files_ordered[i]->extension(j))) { + has_extension = true; + } + } + + if (has_extension) { + if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]), + files_ordered[i], error)) { + return false; + } + } + } + + dedup.GetAllowedSet(allowed_set); + + return true; +} + } // anonymous namespace void Generator::GenerateHeader(const GeneratorOptions& options, @@ -1251,10 +1457,10 @@ void Generator::GenerateProvides(const GeneratorOptions& options, } } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const Descriptor* desc, - std::set<string>* provided) const { +void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set<string>* provided) const { std::set<string> required; std::set<string> forwards; bool have_message = false; @@ -1266,55 +1472,50 @@ void Generator::GenerateRequires(const GeneratorOptions& options, /* require_extension = */ HasExtensions(desc)); } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector<const FileDescriptor*>& files, - std::set<string>* provided) const { - if (options.import_style == GeneratorOptions::IMPORT_BROWSER) { - return; - } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { - // For Closure imports we need to import every message type individually. - std::set<string> required; - std::set<string> forwards; - bool have_extensions = false; - bool have_message = false; +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); + // For Closure imports we need to import every message type individually. + std::set<string> required; + std::set<string> forwards; + bool have_extensions = false; + bool have_message = false; - for (int i = 0; i < files.size(); i++) { - for (int j = 0; j < files[i]->message_type_count(); j++) { - FindRequiresForMessage(options, - files[i]->message_type(j), - &required, &forwards, &have_message); - } - if (!have_extensions && HasExtensions(files[i])) { - have_extensions = true; - } + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->message_type_count(); j++) { + FindRequiresForMessage(options, + files[i]->message_type(j), + &required, &forwards, &have_message); + } + if (!have_extensions && HasExtensions(files[i])) { + have_extensions = true; + } - for (int j = 0; j < files[i]->extension_count(); j++) { - const FieldDescriptor* extension = files[i]->extension(j); - if (IgnoreField(extension)) { - continue; - } - if (extension->containing_type()->full_name() != - "google.protobuf.bridge.MessageSet") { - required.insert(GetPath(options, extension->containing_type())); - } - FindRequiresForField(options, extension, &required, &forwards); - have_extensions = true; + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + if (IgnoreField(extension)) { + continue; + } + if (extension->containing_type()->full_name() != + "google.protobuf.bridge.MessageSet") { + required.insert(GetPath(options, extension->containing_type())); } + FindRequiresForField(options, extension, &required, &forwards); + have_extensions = true; } - - GenerateRequiresImpl(options, printer, &required, &forwards, provided, - /* require_jspb = */ have_message, - /* require_extension = */ have_extensions); - } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { - // CommonJS imports are based on files } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ have_extensions); } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector<const FieldDescriptor*>& fields, - std::set<string>* provided) const { +void Generator::GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const vector<const FieldDescriptor*>& fields, + std::set<string>* provided) const { std::set<string> required; std::set<string> forwards; for (int i = 0; i < fields.size(); i++) { @@ -1708,7 +1909,7 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options, printer->Print( " if (includeInstance) {\n" - " obj.$$jspbMessageInstance = msg\n" + " obj.$$jspbMessageInstance = msg;\n" " }\n" " return obj;\n" "};\n" @@ -1741,17 +1942,34 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, } } else { // Simple field (singular or repeated). - if (!HasFieldPresence(field) && !field->is_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 logic here. + // the proto3-field-default-value or byte-coercion logic here. printer->Print("msg.get$getter$()", - "getter", JSGetterName(field)); + "getter", JSGetterName(field, BYTES_B64)); } else { if (field->has_default_value()) { - printer->Print("jspb.Message.getField(msg, $index$) != null ? " - "jspb.Message.getField(msg, $index$) : $defaultValue$", + printer->Print("jspb.Message.getField(msg, $index$) == null ? " + "$defaultValue$ : ", "index", JSFieldIndex(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)); @@ -1860,6 +2078,40 @@ void Generator::GenerateClassFields(const GeneratorOptions& options, } } +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); + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * This is a type-conversion wrapper around `get$defname$()`\n" + " * @return {$type$}\n" + " */\n" + "$class$.prototype.get$name$ = function() {\n" + " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" + " this.get$defname$()));\n" + "};\n" + "\n" + "\n", + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field, bytes_mode), + "type", type, + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field, bytes_mode), + "list", field->is_repeated() ? "List" : "", + "suffix", JSByteGetterSuffix(bytes_mode), + "defname", JSGetterName(field, BYTES_DEFAULT)); +} + + void Generator::GenerateClassField(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { @@ -1871,12 +2123,11 @@ void Generator::GenerateClassField(const GeneratorOptions& options, " * @return {$type$}\n" " */\n", "fielddef", FieldDefinition(options, field), - "comment", FieldComments(field), + "comment", FieldComments(field, BYTES_DEFAULT), "type", JSFieldTypeAnnotation(options, field, /* force_optional = */ false, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false)); + /* singular_if_not_packed = */ false)); printer->Print( "$class$.prototype.get$name$ = function() {\n" " return /** @type{$type$} */ (\n" @@ -1890,8 +2141,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "type", JSFieldTypeAnnotation(options, field, /* force_optional = */ false, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "rpt", (field->is_repeated() ? "Repeated" : ""), "index", JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field), @@ -1905,8 +2155,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, JSFieldTypeAnnotation(options, field, /* force_optional = */ true, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field), "class", GetPath(options, field->containing_type()), "name", JSGetterName(field), @@ -1935,15 +2184,29 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "returnvalue", JSReturnClause(field)); } else { - string typed_annotation; + bool untyped = + false; // Simple (primitive) field, either singular or repeated. - { - typed_annotation = JSFieldTypeAnnotation(options, field, + + // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; + // at this point we "lie" to non-binary users and tell the the return + // type is always base64 string, pending a LSC to migrate to typed getters. + 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, - /* always_singular = */ false), + /* bytes_mode = */ bytes_mode); + if (untyped) { + printer->Print( + "/**\n" + " * @return {?} Raw field, untyped.\n" + " */\n"); + } else { printer->Print( "/**\n" " * $fielddef$\n" @@ -1951,7 +2214,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, " * @return {$type$}\n" " */\n", "fielddef", FieldDefinition(options, field), - "comment", FieldComments(field), + "comment", FieldComments(field, bytes_mode), "type", typed_annotation); } @@ -1960,7 +2223,10 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "class", GetPath(options, field->containing_type()), "name", JSGetterName(field)); - { + if (untyped) { + printer->Print( + " return "); + } else { printer->Print( " return /** @type {$type$} */ (", "type", typed_annotation); @@ -1975,17 +2241,39 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "default", Proto3PrimitiveFieldDefault(field)); } else { if (field->has_default_value()) { - printer->Print("jspb.Message.getField(this, $index$) != null ? " - "jspb.Message.getField(this, $index$) : $defaultValue$", + printer->Print("jspb.Message.getField(this, $index$) == null ? " + "$defaultValue$ : ", "index", JSFieldIndex(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 if (field->is_optional() && !field->has_default_value()) { + printer->Print("jspb.Message.getOptionalFloatingPointField(" + "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)); } } - { + if (untyped) { + printer->Print( + ";\n" + "};\n" + "\n" + "\n"); + } else { printer->Print( ");\n" "};\n" @@ -1993,18 +2281,27 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "\n"); } - { + if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { + GenerateBytesWrapper(options, printer, field, BYTES_B64); + GenerateBytesWrapper(options, printer, field, BYTES_U8); + } + + if (untyped) { + printer->Print( + "/**\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, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field)); } - printer->Print( "$class$.prototype.set$name$ = function(value) {\n" " jspb.Message.set$oneoftag$Field(this, $index$", @@ -2017,14 +2314,22 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "};\n" "\n" "\n", - "type", "", - "typeclose", "", + "type", + untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), "returnvalue", JSReturnClause(field), "rptvalueinit", (field->is_repeated() ? " || []" : "")); + if (untyped) { + printer->Print( + "/**\n" + " * Clears the value. $returndoc$\n" + " */\n", + "returndoc", JSReturnDoc(options, field)); + } if (HasFieldPresence(field)) { printer->Print( @@ -2162,16 +2467,18 @@ void Generator::GenerateClassDeserializeBinaryField( " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", "fieldtype", JSFieldTypeAnnotation(options, field, false, true, /* singular_if_not_packed = */ true, - /* always_singular = */ false), + BYTES_U8), "reader", JSBinaryReaderMethodName(field)); } if (field->is_repeated() && !field->is_packed()) { // Repeated fields receive a |value| one at at a time; append to array - // returned by get$name$(). - printer->Print( - " msg.get$name$().push(value);\n", - "name", JSGetterName(field)); + // returned by get$name$(). Annoyingly, we have to call 'set' after + // changing the array. + printer->Print(" msg.get$name$().push(value);\n", "name", + JSGetterName(field)); + printer->Print(" msg.set$name$(msg.get$name$());\n", "name", + JSGetterName(field)); } 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 this as @@ -2244,7 +2551,7 @@ void Generator::GenerateClassSerializeBinaryField( const FieldDescriptor* field) const { printer->Print( " f = this.get$name$();\n", - "name", JSGetterName(field)); + "name", JSGetterName(field, BYTES_U8)); if (field->is_repeated()) { printer->Print( @@ -2294,7 +2601,6 @@ void Generator::GenerateClassSerializeBinaryField( " $index$,\n" " f", "writer", JSBinaryWriterMethodName(field), - "name", JSGetterName(field), "index", SimpleItoa(field->number())); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { @@ -2356,8 +2662,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options, options, field, /* force_optional = */ false, /* force_present = */ true, - /* singular_if_not_packed = */ false, - /* always_singular = */ false)); + /* singular_if_not_packed = */ false)); printer->Print( " $index$,\n" " {$name$: 0},\n" @@ -2528,7 +2833,7 @@ void Generator::GenerateFile(const GeneratorOptions& options, printer->Print("var global = Function('return this')();\n\n"); for (int i = 0; i < file->dependency_count(); i++) { - const std::string& name = file->dependency(i)->name(); + const string& name = file->dependency(i)->name(); printer->Print( "var $alias$ = require('$file$');\n", "alias", ModuleAlias(name), @@ -2543,7 +2848,7 @@ void Generator::GenerateFile(const GeneratorOptions& options, // // // Later generated code expects foo.bar = {} to exist: // foo.bar.Baz = function() { /* ... */ } - std::set<std::string> provided; + 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 @@ -2615,7 +2920,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, FindProvidesForFields(options, &printer, extensions, &provided); GenerateProvides(options, &printer, &provided); GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, files, &provided); + GenerateRequiresForLibrary(options, &printer, files, &provided); GenerateFilesInDepOrder(options, &printer, files); @@ -2629,66 +2934,20 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, return false; } } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { - // Collect all types, and print each type to a separate file. Pull out - // free-floating extensions while we make this pass. - map< string, vector<const FieldDescriptor*> > extensions_by_namespace; - - // If we're generating code in file-per-type mode, avoid overwriting files - // by choosing the last descriptor that writes each filename and permitting - // only those to generate code. - - // Current descriptor that will generate each filename, indexed by filename. - map<string, const void*> desc_by_filename; - // Set of descriptors allowed to generate files. - set<const void*> allowed_descs; - - for (int i = 0; i < files.size(); i++) { - // Collect all (descriptor, filename) pairs. - map<const void*, string> descs_in_file; - for (int j = 0; j < files[i]->message_type_count(); j++) { - const Descriptor* desc = files[i]->message_type(j); - string filename = - options.output_dir + "/" + ToFileName(desc->name()) + ".js"; - descs_in_file[desc] = filename; - } - for (int j = 0; j < files[i]->enum_type_count(); j++) { - const EnumDescriptor* desc = files[i]->enum_type(j); - string filename = - options.output_dir + "/" + ToFileName(desc->name()) + ".js"; - descs_in_file[desc] = filename; - } - - // For each (descriptor, filename) pair, update the - // descriptors-by-filename map, and if a previous descriptor was already - // writing the filename, remove it from the allowed-descriptors set. - map<const void*, string>::iterator it; - for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) { - const void* desc = it->first; - const string& filename = it->second; - if (desc_by_filename.find(filename) != desc_by_filename.end()) { - if (options.error_on_name_conflict) { - *error = "Name conflict: file name " + filename + - " would be generated by two descriptors"; - return false; - } - allowed_descs.erase(desc_by_filename[filename]); - } - desc_by_filename[filename] = desc; - allowed_descs.insert(desc); - } + set<const void*> allowed_set; + if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { + return false; } - // Generate code. for (int i = 0; i < files.size(); i++) { const FileDescriptor* file = files[i]; for (int j = 0; j < file->message_type_count(); j++) { const Descriptor* desc = file->message_type(j); - if (allowed_descs.find(desc) == allowed_descs.end()) { + if (allowed_set.count(desc) == 0) { continue; } - string filename = options.output_dir + "/" + - ToFileName(desc->name()) + ".js"; + string filename = GetMessageFileName(options, desc); google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( context->Open(filename)); GOOGLE_CHECK(output.get()); @@ -2700,7 +2959,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, FindProvidesForMessage(options, &printer, desc, &provided); GenerateProvides(options, &printer, &provided); GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, desc, &provided); + GenerateRequiresForMessage(options, &printer, desc, &provided); GenerateClass(options, &printer, desc); @@ -2710,13 +2969,11 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, } for (int j = 0; j < file->enum_type_count(); j++) { const EnumDescriptor* enumdesc = file->enum_type(j); - if (allowed_descs.find(enumdesc) == allowed_descs.end()) { + if (allowed_set.count(enumdesc) == 0) { continue; } - string filename = options.output_dir + "/" + - ToFileName(enumdesc->name()) + ".js"; - + string filename = GetEnumFileName(options, enumdesc); google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( context->Open(filename)); GOOGLE_CHECK(output.get()); @@ -2735,38 +2992,36 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, return false; } } - // Pull out all free-floating extensions and generate files for those too. - for (int j = 0; j < file->extension_count(); j++) { - const FieldDescriptor* extension = file->extension(j); - extensions_by_namespace[GetPath(options, files[i])] - .push_back(extension); - } - } + // File-level extensions (message-level extensions are generated under + // the enclosing message). + if (allowed_set.count(file) == 1) { + string filename = GetExtensionFileName(options, file); - // Generate extensions in separate files. - map< string, vector<const FieldDescriptor*> >::iterator it; - for (it = extensions_by_namespace.begin(); - it != extensions_by_namespace.end(); - ++it) { - string filename = options.output_dir + "/" + - ToFileName(it->first) + ".js"; + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( - context->Open(filename)); - GOOGLE_CHECK(output.get()); - io::Printer printer(output.get(), '$'); + GenerateHeader(options, &printer); + + std::set<string> provided; + vector<const FieldDescriptor*> fields; - GenerateHeader(options, &printer); + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + fields.push_back(files[i]->extension(j)); + } + } - std::set<string> provided; - FindProvidesForFields(options, &printer, it->second, &provided); - GenerateProvides(options, &printer, &provided); - GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, it->second, &provided); + FindProvidesForFields(options, &printer, fields, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForExtensions(options, &printer, fields, &provided); - for (int j = 0; j < it->second.size(); j++) { - if (ShouldGenerateExtension(it->second[j])) { - GenerateExtension(options, &printer, it->second[j]); + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + GenerateExtension(options, &printer, files[i]->extension(j)); + } } } } @@ -2777,8 +3032,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, const google::protobuf::FileDescriptor* file = files[i]; string filename = options.output_dir + "/" + GetJSFilename(file->name()); - google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( - context->Open(filename)); + 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 db9178d3..6fd7ca50 100755 --- a/src/google/protobuf/compiler/js/js_generator.h +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -146,19 +146,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { io::Printer* printer) const; // Generate goog.requires() calls. - void GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector<const FileDescriptor*>& file, - std::set<string>* provided) const; - void GenerateRequires(const GeneratorOptions& options, + void GenerateRequiresForLibrary(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& files, + std::set<string>* provided) const; + void GenerateRequiresForMessage(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc, std::set<string>* provided) const; // For extension fields at file scope. - void GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector<const FieldDescriptor*>& fields, - std::set<string>* provided) const; + void GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const vector<const FieldDescriptor*>& fields, + std::set<string>* provided) const; void GenerateRequiresImpl(const GeneratorOptions& options, io::Printer* printer, std::set<string>* required, diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc index 121d917b..82bb3427 100644 --- a/src/google/protobuf/compiler/mock_code_generator.cc +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -32,20 +32,26 @@ #include <google/protobuf/compiler/mock_code_generator.h> +#include <stdlib.h> +#include <iostream> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <vector> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <gtest/gtest.h> -#include <google/protobuf/stubs/stl_util.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h index 8c8348d8..e1665f88 100644 --- a/src/google/protobuf/compiler/mock_code_generator.h +++ b/src/google/protobuf/compiler/mock_code_generator.h @@ -34,10 +34,15 @@ #define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ #include <string> + #include <google/protobuf/compiler/code_generator.h> namespace google { namespace protobuf { +class FileDescriptor; +} // namespace protobuf + +namespace protobuf { namespace compiler { // A mock CodeGenerator, used by command_line_interface_unittest. This is in diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc index 857d24a4..e76f8e99 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -72,8 +72,9 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { "\n", "name", name_); - printer->Print("$comments$typedef GPB_ENUM($name$) {\n", + printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", "comments", enum_comments, + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_), "name", name_); printer->Indent(); @@ -99,8 +100,9 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { } printer->Print( - "$name$ = $value$,\n", + "$name$$deprecated_attribute$ = $value$,\n", "name", EnumValueName(all_values_[i]), + "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]), "value", SimpleItoa(all_values_[i]->number())); } printer->Outdent(); @@ -122,16 +124,6 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "\n", "name", name_); - printer->Print( - "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" - " static GPBEnumDescriptor *descriptor = NULL;\n" - " if (!descriptor) {\n" - " static GPBMessageEnumValueDescription values[] = {\n", - "name", name_); - printer->Indent(); - printer->Indent(); - printer->Indent(); - // Note: For the TextFormat decode info, we can't use the enum value as // the key because protocol buffer enums have 'allow_alias', which lets // a value be used more than once. Instead, the index into the list of @@ -139,41 +131,66 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { // will be zero. TextFormatDecodeData text_format_decode_data; int enum_value_description_key = -1; + string text_blob; for (int i = 0; i < all_values_.size(); i++) { ++enum_value_description_key; string short_name(EnumValueShortName(all_values_[i])); - printer->Print("{ .name = \"$short_name$\", .number = $name$ },\n", - "short_name", short_name, - "name", EnumValueName(all_values_[i])); + text_blob += short_name + '\0'; if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) { text_format_decode_data.AddString(enum_value_description_key, short_name, all_values_[i]->name()); } } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); + + printer->Print( + "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" + " static GPBEnumDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n", + "name", name_); + + static const int kBytesPerLine = 40; // allow for escaping + printer->Print( + " static const char *valueNames ="); + for (int i = 0; i < text_blob.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine)))); + } + printer->Print( + ";\n" + " static const int32_t values[] = {\n"); + for (int i = 0; i < all_values_.size(); i++) { + printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); + } printer->Print(" };\n"); + if (text_format_decode_data.num_entries() == 0) { printer->Print( - " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" - " values:values\n" - " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" - " enumVerifier:$name$_IsValidValue];\n", + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue];\n", "name", name_); } else { printer->Print( " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" - " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" - " values:values\n" - " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" - " enumVerifier:$name$_IsValidValue\n" - " extraTextFormatInfo:extraTextFormatInfo];\n", + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue\n" + " extraTextFormatInfo:extraTextFormatInfo];\n", "name", name_, "extraTextFormatInfo", CEscape(text_format_decode_data.Data())); } printer->Print( + " if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {\n" + " [worker release];\n" + " }\n" " }\n" " return descriptor;\n" "}\n\n"); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc index cfbb8c52..b63bc0de 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -59,6 +59,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["enum_verifier"] = type + "_IsValidValue"; (*variables)["enum_desc_func"] = type + "_EnumDescriptor"; + (*variables)["dataTypeSpecific_name"] = "enumDescFunc"; + (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"]; + const Descriptor* msg_descriptor = descriptor->containing_type(); (*variables)["owning_message_class"] = ClassName(msg_descriptor); } @@ -72,13 +75,6 @@ EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, EnumFieldGenerator::~EnumFieldGenerator() {} -void EnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n"); -} - void EnumFieldGenerator::GenerateCFunctionDeclarations( io::Printer* printer) const { if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { @@ -145,13 +141,6 @@ void RepeatedEnumFieldGenerator::FinishInitialization(void) { "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; } -void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n"); -} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h index ae2f57e3..946faa81 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -45,7 +45,6 @@ class EnumFieldGenerator : public SingleFieldGenerator { const Options& options); public: - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; virtual void GenerateCFunctionImplementations(io::Printer* printer) const; virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; @@ -64,7 +63,6 @@ class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { public: virtual void FinishInitialization(); - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc index 4e348393..3f7ab9d3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc @@ -114,14 +114,14 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( printer->Print(vars, "{\n" + " .defaultValue.$default_name$ = $default$,\n" " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" - " .dataType = $extension_type$,\n" " .extendedClass = GPBStringifySymbol($extended_type$),\n" - " .fieldNumber = $number$,\n" - " .defaultValue.$default_name$ = $default$,\n" " .messageOrGroupClassName = $type$,\n" - " .options = $options$,\n" " .enumDescriptorFunc = $enum_desc_func_name$,\n" + " .fieldNumber = $number$,\n" + " .dataType = $extension_type$,\n" + " .options = $options$,\n" "},\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 8697e225..66cb4a16 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include <iostream> + #include <google/protobuf/compiler/objectivec/objectivec_field.h> #include <google/protobuf/compiler/objectivec/objectivec_helpers.h> #include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> @@ -75,8 +77,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["field_number_name"] = classname + "_FieldNumber_" + capitalized_name; (*variables)["field_number"] = SimpleItoa(descriptor->number()); - (*variables)["has_index"] = SimpleItoa(descriptor->index()); (*variables)["field_type"] = GetCapitalizedType(descriptor); + (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); std::vector<string> field_flags; if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); @@ -99,18 +101,9 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["dataTypeSpecific_name"] = "className"; (*variables)["dataTypeSpecific_value"] = "NULL"; - string field_options = descriptor->options().SerializeAsString(); - // Must convert to a standard byte order for packing length into - // a cstring. - uint32 length = ghtonl(field_options.length()); - if (length > 0) { - string bytes((const char*)&length, sizeof(length)); - bytes.append(field_options); - string options_str = "\"" + CEscape(bytes) + "\""; - (*variables)["fieldoptions"] = "\"" + CEscape(bytes) + "\""; - } else { - (*variables)["fieldoptions"] = ""; - } + (*variables)["storage_offset_value"] = + "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; + (*variables)["storage_offset_comment"] = ""; // Clear some common things so they can be set just when needed. (*variables)["storage_attribute"] = ""; @@ -190,52 +183,54 @@ void FieldGenerator::DetermineForwardDeclarations( } void FieldGenerator::GenerateFieldDescription( - io::Printer* printer) const { - printer->Print( - variables_, - "{\n" - " .name = \"$name$\",\n" - " .number = $field_number_name$,\n" - " .hasIndex = $has_index$,\n" - " .flags = $fieldflags$,\n" - " .dataType = GPBDataType$field_type$,\n" - " .offset = offsetof($classname$__storage_, $name$),\n" - " .defaultValue.$default_name$ = $default$,\n"); - - // TODO(thomasvl): It might be useful to add a CPP wrapper to support - // compiling away the EnumDescriptors. To do that, we'd need a #if here - // to control setting the descriptor vs. the validator, and above in - // SetCommonFieldVariables() we'd want to wrap how we add - // GPBFieldHasDefaultValue to the flags. - - // " .dataTypeSpecific.value* = [something]," - GenerateFieldDescriptionTypeSpecific(printer); - - const string& field_options(variables_.find("fieldoptions")->second); - if (field_options.empty()) { - printer->Print(" .fieldOptions = NULL,\n"); + io::Printer* printer, bool include_default) const { + // Printed in the same order as the structure decl. + if (include_default) { + printer->Print( + variables_, + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .core.name = \"$name$\",\n" + " .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .core.number = $field_number_name$,\n" + " .core.hasIndex = $has_index$,\n" + " .core.offset = $storage_offset_value$,$storage_offset_comment$\n" + " .core.flags = $fieldflags$,\n" + " .core.dataType = GPBDataType$field_type$,\n" + "},\n"); } else { - // Can't use PrintRaw() here to get the #if/#else/#endif lines completely - // outdented because the need for indent captured on the previous - // printing of a \n and there is no way to get the current indent level - // to call the right number of Outdent()/Indents() to maintain state. printer->Print( variables_, - "#if GPBOBJC_INCLUDE_FIELD_OPTIONS\n" - " .fieldOptions = $fieldoptions$,\n" - "#else\n" - " .fieldOptions = NULL,\n" - "#endif // GPBOBJC_INCLUDE_FIELD_OPTIONS\n"); + "{\n" + " .name = \"$name$\",\n" + " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .number = $field_number_name$,\n" + " .hasIndex = $has_index$,\n" + " .offset = $storage_offset_value$,$storage_offset_comment$\n" + " .flags = $fieldflags$,\n" + " .dataType = GPBDataType$field_type$,\n" + "},\n"); } +} - printer->Print("},\n"); +void FieldGenerator::SetRuntimeHasBit(int has_index) { + variables_["has_index"] = SimpleItoa(has_index); } -void FieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"); +void FieldGenerator::SetNoHasBit(void) { + variables_["has_index"] = "GPBNoHasBit"; +} + +int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + return 0; +} + +void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { + // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some + // error cases, so it seems to be ok to use as a back door for errors. + cerr << "Error: should have overriden SetExtraRuntimeHasBitsBase()." << endl; + cerr.flush(); + abort(); } void FieldGenerator::SetOneofIndexBase(int index_base) { @@ -272,12 +267,12 @@ void SingleFieldGenerator::GeneratePropertyDeclaration( printer->Print(variables_, "$comments$"); printer->Print( variables_, - "@property(nonatomic, readwrite) $property_type$ $name$;\n" + "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" "\n"); if (WantsHasProperty()) { printer->Print( variables_, - "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); } } @@ -302,6 +297,14 @@ bool SingleFieldGenerator::WantsHasProperty(void) const { return false; } +bool SingleFieldGenerator::RuntimeUsesHasBit(void) const { + if (descriptor_->containing_oneof() != NULL) { + // The oneof tracks what is set instead. + return false; + } + return true; +} + ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor, const Options& options) : SingleFieldGenerator(descriptor, options) { @@ -328,18 +331,18 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( printer->Print(variables_, "$comments$"); printer->Print( variables_, - "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$;\n"); + "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); if (WantsHasProperty()) { printer->Print( variables_, "/// Test to see if @c $name$ has been set.\n" - "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); } if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -347,8 +350,6 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( RepeatedFieldGenerator::RepeatedFieldGenerator( const FieldDescriptor* descriptor, const Options& options) : ObjCObjFieldGenerator(descriptor, options) { - // Repeated fields don't use the has index. - variables_["has_index"] = "GPBNoHasBit"; // Default to no comment and let the cases needing it fill it in. variables_["array_comment"] = ""; } @@ -385,14 +386,14 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( variables_, "$comments$" "$array_comment$" - "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$;\n" + "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" "/// The number of items in @c $name$ without causing the array to be created.\n" - "@property(nonatomic, readonly) NSUInteger $name$_Count;\n"); + "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -402,6 +403,10 @@ bool RepeatedFieldGenerator::WantsHasProperty(void) const { return false; } +bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const { + return false; // The array having anything is what is used. +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Options& options) : descriptor_(descriptor), @@ -432,12 +437,40 @@ const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { return *extension_generators_[index]; } +int FieldGeneratorMap::CalculateHasBits(void) { + int total_bits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (field_generators_[i]->RuntimeUsesHasBit()) { + field_generators_[i]->SetRuntimeHasBit(total_bits); + ++total_bits; + } else { + field_generators_[i]->SetNoHasBit(); + } + int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded(); + if (extra_bits) { + field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits); + total_bits += extra_bits; + } + } + return total_bits; +} + void FieldGeneratorMap::SetOneofIndexBase(int index_base) { for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_[i]->SetOneofIndexBase(index_base); } } +bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (HasNonZeroDefaultValue(descriptor_->field(i))) { + return true; + } + } + + return false; +} + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h index e8a20a72..a3a4b1b6 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -61,7 +61,6 @@ class FieldGenerator { // Called by GenerateFieldDescription, exposed for classes that need custom // generation. - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; // Exposed for subclasses to extend, base does nothing. virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; @@ -71,9 +70,16 @@ class FieldGenerator { virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; // Used during generation, not intended to be extended by subclasses. - void GenerateFieldDescription(io::Printer* printer) const; + void GenerateFieldDescription( + io::Printer* printer, bool include_default) const; void GenerateFieldNumberConstant(io::Printer* printer) const; + // Exposed to get and set the has bits information. + virtual bool RuntimeUsesHasBit(void) const = 0; + void SetRuntimeHasBit(int has_index); + void SetNoHasBit(void); + virtual int ExtraRuntimeHasBitsNeeded(void) const; + virtual void SetExtraRuntimeHasBitsBase(int index_base); void SetOneofIndexBase(int index_base); string variable(const char* key) const { @@ -109,6 +115,8 @@ class SingleFieldGenerator : public FieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: SingleFieldGenerator(const FieldDescriptor* descriptor, const Options& options); @@ -143,6 +151,8 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: RepeatedFieldGenerator(const FieldDescriptor* descriptor, const Options& options); @@ -162,8 +172,14 @@ class FieldGeneratorMap { const FieldGenerator& get(const FieldDescriptor* field) const; const FieldGenerator& get_extension(int index) const; + // Assigns the has bits and returns the number of bits needed. + int CalculateHasBits(void); + void SetOneofIndexBase(int index_base); + // Check if any field of this message has a non zero default. + bool DoesAnyFieldHaveNonZeroDefault(void) const; + private: const Descriptor* descriptor_; scoped_array<scoped_ptr<FieldGenerator> > field_generators_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 16199884..ed4fc6a3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -45,7 +45,7 @@ namespace protobuf { // This is also found in GPBBootstrap.h, and needs to be kept in sync. It // is the version check done to ensure generated code works with the current // runtime being used. -const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000; +const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001; namespace compiler { namespace objectivec { @@ -115,6 +115,9 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" + "\n" "CF_EXTERN_C_BEGIN\n" "\n"); @@ -189,6 +192,8 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { "\n" "CF_EXTERN_C_END\n" "\n" + "#pragma clang diagnostic pop\n" + "\n" "// @@protoc_insertion_point(global_scope)\n"); } @@ -216,6 +221,9 @@ void FileGenerator::GenerateSource(io::Printer *printer) { } printer->Print( "// @@protoc_insertion_point(imports)\n" + "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" "\n"); printer->Print( @@ -343,6 +351,8 @@ void FileGenerator::GenerateSource(io::Printer *printer) { printer->Print( "\n" + "#pragma clang diagnostic pop\n" + "\n" "// @@protoc_insertion_point(global_scope)\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 613a511c..196b39dd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -220,11 +220,6 @@ string NameFromFieldDescriptor(const FieldDescriptor* field) { } } -// Escape C++ trigraphs by escaping question marks to \? -string EscapeTrigraphs(const string& to_escape) { - return StringReplace(to_escape, "?", "\\?", true); -} - void PathSplit(const string& path, string* directory, string* basename) { string::size_type last_slash = path.rfind('/'); if (last_slash == string::npos) { @@ -264,6 +259,11 @@ bool IsSpecialName(const string& name, const string* special_names, } // namespace +// Escape C++ trigraphs by escaping question marks to \? +string EscapeTrigraphs(const string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + string StripProto(const string& filename) { if (HasSuffixString(filename, ".protodevel")) { return StripSuffixString(filename, ".protodevel"); @@ -734,7 +734,7 @@ string DefaultValue(const FieldDescriptor* field) { uint32 length = ghtonl(default_string.length()); string bytes((const char*)&length, sizeof(length)); bytes.append(default_string); - return "(NSData*)\"" + CEscape(bytes) + "\""; + return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\""; } else { return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\""; } @@ -751,6 +751,51 @@ string DefaultValue(const FieldDescriptor* field) { return NULL; } +bool HasNonZeroDefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return false; + } + + // As much as checking field->has_default_value() seems useful, it isn't + // because of enums. proto2 syntax allows the first item in an enum (the + // default) to be non zero. So checking field->has_default_value() would + // result in missing this non zero default. See MessageWithOneBasedEnum in + // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. + + // Some proto file set the default to the zero value, so make sure the value + // isn't the zero case. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() != 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() != 0U; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() != 0LL; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() != 0ULL; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() != 0.0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() != 0.0f; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool(); + case FieldDescriptor::CPPTYPE_STRING: { + const string& default_string = field->default_value_string(); + return default_string.length() != 0; + } + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() != 0; + case FieldDescriptor::CPPTYPE_MESSAGE: + return false; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + string BuildFlagsString(const vector<string>& strings) { if (strings.size() == 0) { return "0"; @@ -969,7 +1014,8 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, } else { // ...it didn't match! *out_error = "error: Expected 'option objc_class_prefix = \"" + - package_match->second + "\";' in '" + file->name() + "'"; + package_match->second + "\";' for package '" + package + + "' in '" + file->name() + "'"; if (prefix.length()) { *out_error += "; but found '" + prefix + "' instead"; } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index a301493e..3f56d94b 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -48,6 +48,9 @@ struct Options { string expected_prefixes_path; }; +// Escape C++ trigraphs by escaping question marks to "\?". +string EscapeTrigraphs(const string& to_escape); + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); @@ -130,6 +133,22 @@ enum ObjectiveCType { OBJECTIVECTYPE_MESSAGE }; +template<class TDescriptor> +string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) { + if (descriptor->options().deprecated()) { + string result = "DEPRECATED_ATTRIBUTE"; + if (preSpace) { + result.insert(0, " "); + } + if (postNewline) { + result.append("\n"); + } + return result; + } else { + return ""; + } +} + string GetCapitalizedType(const FieldDescriptor* field); ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type); @@ -143,6 +162,7 @@ bool IsReferenceType(const FieldDescriptor* field); string GPBGenericValueFieldName(const FieldDescriptor* field); string DefaultValue(const FieldDescriptor* field); +bool HasNonZeroDefaultValue(const FieldDescriptor* field); string BuildFlagsString(const vector<string>& strings); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index 2751e936..ac5d8aea 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -140,13 +140,18 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, value_field_generator_->variable("storage_type") + "*>"; } } + + variables_["dataTypeSpecific_name"] = + value_field_generator_->variable("dataTypeSpecific_name"); + variables_["dataTypeSpecific_value"] = + value_field_generator_->variable("dataTypeSpecific_value"); } MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator::FinishInitialization(void) { RepeatedFieldGenerator::FinishInitialization(); - // Use the array_comment suport in RepeatedFieldGenerator to output what the + // Use the array_comment support in RepeatedFieldGenerator to output what the // values in the map are. const FieldDescriptor* value_descriptor = descriptor_->message_type()->FindFieldByName("value"); @@ -156,13 +161,6 @@ void MapFieldGenerator::FinishInitialization(void) { } } -void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - // Relay it to the value generator to provide enum validator, message - // class, etc. - value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer); -} - void MapFieldGenerator::DetermineForwardDeclarations( set<string>* fwd_decls) const { RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index 7351ea05..bc68a682 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -46,7 +46,6 @@ class MapFieldGenerator : public RepeatedFieldGenerator { public: virtual void FinishInitialization(void); - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index e0ea8bd2..bf272596 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -66,11 +66,12 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { // The first item in the object structure is our uint32[] for has bits. // We then want to order things to make the instances as small as // possible. So we follow the has bits with: - // 1. Bools (1 byte) - // 2. Anything always 4 bytes - float, *32, enums - // 3. Anything that is always a pointer (they will be 8 bytes on 64 bit + // 1. Anything always 4 bytes - float, *32, enums + // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit // builds and 4 bytes on 32bit builds. - // 4. Anything always 8 bytes - double, *64 + // 3. Anything always 8 bytes - double, *64 + // + // NOTE: Bools aren't listed, they were stored in the has bits. // // Why? Using 64bit builds as an example, this means worse case, we have // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes @@ -115,9 +116,9 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { case FieldDescriptor::TYPE_ENUM: return 2; - // 1 byte. + // 0 bytes. Stored in the has bits. case FieldDescriptor::TYPE_BOOL: - return 1; + return 99; // End of the list (doesn't really matter). } // Some compilers report reaching end of function even though all cases of @@ -320,8 +321,9 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { } printer->Print( - "$comments$@interface $classname$ : GPBMessage\n\n", + "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n", "classname", class_name_, + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, false, true), "comments", message_comments); vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0); @@ -404,32 +406,28 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { sort(sorted_extensions.begin(), sorted_extensions.end(), ExtensionRangeOrdering()); - // TODO(thomasvl): Finish optimizing has bit. The current behavior is as - // follows: - // 1. objectivec_field.cc's SetCommonFieldVariables() defaults the has_index - // to the field's index in the list of fields. - // 2. RepeatedFieldGenerator::RepeatedFieldGenerator() sets has_index to - // GPBNoHasBit because repeated fields & map<> fields don't use the has - // bit. - // 3. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative - // index that groups all the elements on of the oneof. - // So in has_storage, we need enough bits for the single fields that aren't - // in any oneof, and then one int32 for each oneof (to store the field - // number). So we could save a little space by not using the field's index - // and instead make a second pass only assigning indexes for the fields - // that would need it. The only savings would come when messages have over - // a multiple of 32 fields with some number being repeated or in oneofs to - // drop the count below that 32 multiple; so it hasn't seemed worth doing - // at the moment. - size_t num_has_bits = descriptor_->field_count(); + // Assign has bits: + // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing + // who needs has bits and assigning them. + // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative + // index that groups all the elements in the oneof. + size_t num_has_bits = field_generators_.CalculateHasBits(); size_t sizeof_has_storage = (num_has_bits + 31) / 32; + if (sizeof_has_storage == 0) { + // In the case where no field needs has bits, don't let the _has_storage_ + // end up as zero length (zero length arrays are sort of a grey area + // since it has to be at the start of the struct). This also ensures a + // field with only oneofs keeps the required negative indices they need. + sizeof_has_storage = 1; + } // Tell all the fields the oneof base. for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); iter != oneof_generators_.end(); ++iter) { (*iter)->SetOneofIndexBase(sizeof_has_storage); } field_generators_.SetOneofIndexBase(sizeof_has_storage); - // Add an int32 for each oneof to store which is set. + // sizeof_has_storage needs enough bits for the single fields that aren't in + // any oneof, and then one int32 for each oneof (to store the field number). sizeof_has_storage += descriptor_->oneof_decl_count(); printer->Print( @@ -456,47 +454,26 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " static GPBDescriptor *descriptor = nil;\n" " if (!descriptor) {\n"); - bool has_oneofs = oneof_generators_.size(); - if (has_oneofs) { - printer->Print( - " static GPBMessageOneofDescription oneofs[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); - iter != oneof_generators_.end(); ++iter) { - (*iter)->GenerateDescription(printer); - } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " };\n"); - } - TextFormatDecodeData text_format_decode_data; bool has_fields = descriptor_->field_count() > 0; + bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); + string field_description_type; + if (need_defaults) { + field_description_type = "GPBMessageFieldDescriptionWithDefault"; + } else { + field_description_type = "GPBMessageFieldDescription"; + } if (has_fields) { - // TODO(thomasvl): The plugin's FieldGenerator::GenerateFieldDescription() - // wraps the fieldOptions's value of this structure in an CPP gate so - // they can be compiled away; but that still results in a const char* in - // the structure for a NULL pointer for every message field. If the - // fieldOptions are moved to a separate payload like the TextFormat extra - // data is, then it would shrink that static data shrinking the binaries - // a little more. - // TODO(thomasvl): proto3 syntax doens't need a defaultValue in the - // structure because primitive types are always zero. If we add a second - // structure and a different initializer, we can avoid the wasted static - // storage for every field in a proto3 message. printer->Print( - " static GPBMessageFieldDescription fields[] = {\n"); + " static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); printer->Indent(); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); ++i) { const FieldGenerator& field_generator = field_generators_.get(sorted_fields[i]); - field_generator.GenerateFieldDescription(printer); + field_generator.GenerateFieldDescription(printer, need_defaults); if (field_generator.needs_textformat_name_support()) { text_format_decode_data.AddString(sorted_fields[i]->number(), field_generator.generated_objc_name(), @@ -510,111 +487,89 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " };\n"); } - bool has_enums = enum_generators_.size(); - if (has_enums) { + map<string, string> vars; + vars["classname"] = class_name_; + vars["rootclassname"] = root_classname_; + vars["fields"] = has_fields ? "fields" : "NULL"; + if (has_fields) { + vars["fields_count"] = + "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))"; + } else { + vars["fields_count"] = "0"; + } + + std::vector<string> init_flags; + if (need_defaults) { + init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); + } + if (descriptor_->options().message_set_wire_format()) { + init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); + } + vars["init_flags"] = BuildFlagsString(init_flags); + + printer->Print( + vars, + " GPBDescriptor *localDescriptor =\n" + " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" + " rootClass:[$rootclassname$ class]\n" + " file:$rootclassname$_FileDescriptor()\n" + " fields:$fields$\n" + " fieldCount:$fields_count$\n" + " storageSize:sizeof($classname$__storage_)\n" + " flags:$init_flags$];\n"); + if (oneof_generators_.size() != 0) { printer->Print( - " static GPBMessageEnumDescription enums[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); - iter != enum_generators_.end(); ++iter) { - printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n", - "name", (*iter)->name()); + " static const char *oneofs[] = {\n"); + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + printer->Print( + " \"$name$\",\n", + "name", (*iter)->DescriptorName()); } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); printer->Print( - " };\n"); + " };\n" + " [localDescriptor setupOneofs:oneofs\n" + " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n" + " firstHasIndex:$first_has_index$];\n", + "first_has_index", oneof_generators_[0]->HasIndexAsString()); } - - bool has_extensions = sorted_extensions.size(); - if (has_extensions) { + if (text_format_decode_data.num_entries() != 0) { + const string text_format_data_str(text_format_decode_data.Data()); printer->Print( - " static GPBExtensionRange ranges[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (int i = 0; i < sorted_extensions.size(); i++) { - printer->Print("{ .start = $start$, .end = $end$ },\n", - "start", SimpleItoa(sorted_extensions[i]->start), - "end", SimpleItoa(sorted_extensions[i]->end)); + "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " static const char *extraTextFormatInfo ="); + static const int kBytesPerLine = 40; // allow for escaping + for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs( + CEscape(text_format_data_str.substr(i, kBytesPerLine)))); } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); printer->Print( - " };\n"); + ";\n" + " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" + "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); } - - map<string, string> vars; - vars["classname"] = class_name_; - vars["rootclassname"] = root_classname_; - vars["fields"] = has_fields ? "fields" : "NULL"; - vars["fields_count"] = - has_fields ? "sizeof(fields) / sizeof(GPBMessageFieldDescription)" : "0"; - vars["oneofs"] = has_oneofs ? "oneofs" : "NULL"; - vars["oneof_count"] = - has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0"; - vars["enums"] = has_enums ? "enums" : "NULL"; - vars["enum_count"] = - has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0"; - vars["ranges"] = has_extensions ? "ranges" : "NULL"; - vars["range_count"] = - has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0"; - vars["wireformat"] = - descriptor_->options().message_set_wire_format() ? "YES" : "NO"; - - if (text_format_decode_data.num_entries() == 0) { + if (sorted_extensions.size() != 0) { printer->Print( - vars, - " GPBDescriptor *localDescriptor =\n" - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" - " rootClass:[$rootclassname$ class]\n" - " file:$rootclassname$_FileDescriptor()\n" - " fields:$fields$\n" - " fieldCount:$fields_count$\n" - " oneofs:$oneofs$\n" - " oneofCount:$oneof_count$\n" - " enums:$enums$\n" - " enumCount:$enum_count$\n" - " ranges:$ranges$\n" - " rangeCount:$range_count$\n" - " storageSize:sizeof($classname$__storage_)\n" - " wireFormat:$wireformat$];\n"); - } else { - vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data()); - printer->Print( - vars, - "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" - " const char *extraTextFormatInfo = NULL;\n" - "#else\n" - " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" - "#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" - " GPBDescriptor *localDescriptor =\n" - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" - " rootClass:[$rootclassname$ class]\n" - " file:$rootclassname$_FileDescriptor()\n" - " fields:$fields$\n" - " fieldCount:$fields_count$\n" - " oneofs:$oneofs$\n" - " oneofCount:$oneof_count$\n" - " enums:$enums$\n" - " enumCount:$enum_count$\n" - " ranges:$ranges$\n" - " rangeCount:$range_count$\n" - " storageSize:sizeof($classname$__storage_)\n" - " wireFormat:$wireformat$\n" - " extraTextFormatInfo:extraTextFormatInfo];\n"); + " static const GPBExtensionRange ranges[] = {\n"); + for (int i = 0; i < sorted_extensions.size(); i++) { + printer->Print(" { .start = $start$, .end = $end$ },\n", + "start", SimpleItoa(sorted_extensions[i]->start), + "end", SimpleItoa(sorted_extensions[i]->end)); } printer->Print( - " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" - " descriptor = localDescriptor;\n" - " }\n" - " return descriptor;\n" - "}\n\n" - "@end\n\n"); + " };\n" + " [localDescriptor setupExtensionRanges:ranges\n" + " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); + } + printer->Print( + " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" + " descriptor = localDescriptor;\n" + " }\n" + " return descriptor;\n" + "}\n\n" + "@end\n\n"); for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc index 24e6df07..44bafd7f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -120,17 +120,16 @@ void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" " GPBDescriptor *descriptor = [message descriptor];\n" " GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n" - " GPBMaybeClearOneof(message, oneof, 0);\n" + " GPBMaybeClearOneof(message, oneof, $index$, 0);\n" "}\n"); } -void OneofGenerator::GenerateDescription(io::Printer* printer) { - printer->Print( - variables_, - "{\n" - " .name = \"$name$\",\n" - " .index = $index$,\n" - "},\n"); +string OneofGenerator::DescriptorName(void) const { + return variables_.find("name")->second; +} + +string OneofGenerator::HasIndexAsString(void) const { + return variables_.find("index")->second; } } // namespace objectivec diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h index bcba82da..3d9df4db 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h @@ -61,7 +61,9 @@ class OneofGenerator { void GeneratePropertyImplementation(io::Printer* printer); void GenerateClearFunctionImplementation(io::Printer* printer); - void GenerateDescription(io::Printer* printer); + + string DescriptorName(void) const; + string HasIndexAsString(void) const; private: const OneofDescriptor* descriptor_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc index ea7f1b91..d49350f4 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -134,6 +134,32 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator( PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} +void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Nothing, BOOLs are stored in the has bits. + } else { + SingleFieldGenerator::GenerateFieldStorageDeclaration(printer); + } +} + +int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Reserve a bit for the storage of the boolean. + return 1; + } + return 0; +} + +void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Set into the offset the has bit to use for the actual value. + variables_["storage_offset_value"] = SimpleItoa(has_base); + variables_["storage_offset_comment"] = + " // Stored in _has_storage_ to save space."; + } +} + PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( const FieldDescriptor* descriptor, const Options& options) : ObjCObjFieldGenerator(descriptor, options) { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h index 87139afb..69bb1fdd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -49,6 +49,11 @@ class PrimitiveFieldGenerator : public SingleFieldGenerator { const Options& options); virtual ~PrimitiveFieldGenerator(); + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const; + + virtual int ExtraRuntimeHasBitsNeeded(void) const; + virtual void SetExtraRuntimeHasBitsBase(int index_base); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); }; diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index 2bebf1f3..2ff50f61 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -93,31 +93,15 @@ class GeneratorResponseContext : public GeneratorContext { const vector<const FileDescriptor*>& parsed_files_; }; -int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { - - if (argc > 1) { - std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl; - return 1; - } - -#ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); - _setmode(STDOUT_FILENO, _O_BINARY); -#endif - - CodeGeneratorRequest request; - if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { - std::cerr << argv[0] << ": protoc sent unparseable request to plugin." - << std::endl; - return 1; - } - +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, CodeGeneratorResponse* response, + string* error_msg) { DescriptorPool pool; for (int i = 0; i < request.proto_file_size(); i++) { const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); if (file == NULL) { // BuildFile() already wrote an error message. - return 1; + return false; } } @@ -125,19 +109,18 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { for (int i = 0; i < request.file_to_generate_size(); i++) { parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); if (parsed_files.back() == NULL) { - std::cerr << argv[0] << ": protoc asked plugin to generate a file but " - "did not provide a descriptor for the file: " - << request.file_to_generate(i) << std::endl; - return 1; + *error_msg = "protoc asked plugin to generate a file but " + "did not provide a descriptor for the file: " + + request.file_to_generate(i); + return false; } } - CodeGeneratorResponse response; - GeneratorResponseContext context(&response, parsed_files); + GeneratorResponseContext context(response, parsed_files); - if (generator->HasGenerateAll()) { + if (generator.HasGenerateAll()) { string error; - bool succeeded = generator->GenerateAll( + bool succeeded = generator.GenerateAll( parsed_files, request.parameter(), &context, &error); if (!succeeded && error.empty()) { @@ -145,14 +128,14 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { "description."; } if (!error.empty()) { - response.set_error(error); + 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( + bool succeeded = generator.Generate( file, request.parameter(), &context, &error); if (!succeeded && error.empty()) { @@ -160,14 +143,46 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { "description."; } if (!error.empty()) { - response.set_error(file->name() + ": " + error); + response->set_error(file->name() + ": " + error); break; } } } - if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { - std::cerr << argv[0] << ": Error writing to stdout." << std::endl; + return true; +} + +int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { + + if (argc > 1) { + std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl; + return 1; + } + +#ifdef _WIN32 + _setmode(STDIN_FILENO, _O_BINARY); + _setmode(STDOUT_FILENO, _O_BINARY); +#endif + + CodeGeneratorRequest request; + if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { + std::cerr << argv[0] << ": protoc sent unparseable request to plugin." + << std::endl; + return 1; + } + + string error_msg; + CodeGeneratorResponse response; + + if (GenerateCode(request, *generator, &response, &error_msg)) { + if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { + std::cerr << argv[0] << ": Error writing to stdout." << std::endl; + return 1; + } + } else { + if (!error_msg.empty()) { + std::cerr << argv[0] << ": " << error_msg << std::endl; + } return 1; } diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h index 679f9bdb..d2793a9f 100644 --- a/src/google/protobuf/compiler/plugin.h +++ b/src/google/protobuf/compiler/plugin.h @@ -40,6 +40,13 @@ // } // You must link your plugin against libprotobuf and libprotoc. // +// The core part of PluginMain is to invoke the given CodeGenerator on a +// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is +// abstracted out and made into function GenerateCode so that it can be reused, +// for example, to implement a variant of PluginMain that does some +// preprocessing on the input CodeGeneratorRequest before feeding the request +// to the given code generator. +// // To get protoc to use the plugin, do one of the following: // * Place the plugin binary somewhere in the PATH and give it the name // "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you @@ -55,16 +62,27 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ #define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#include <string> + #include <google/protobuf/stubs/common.h> namespace google { namespace protobuf { namespace compiler { class CodeGenerator; // code_generator.h +class CodeGeneratorRequest; +class CodeGeneratorResponse; // Implements main() for a protoc plugin exposing the given code generator. LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator); +// Generates code using the given code generator. Returns true if the code +// generation is successful. If the code geneartion fails, error_msg may be +// populated to describe the failure cause. +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, CodeGeneratorResponse* response, + string* error_msg); + } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index a2da8eee..e9d50a1d 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -240,6 +240,7 @@ CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena } void CodeGeneratorRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest) if (has_parameter()) { parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -253,7 +254,7 @@ void CodeGeneratorRequest::Clear() { bool CodeGeneratorRequest::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorRequest) for (;;) { @@ -412,6 +413,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( } int CodeGeneratorRequest::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest) int total_size = 0; // optional string parameter = 2; @@ -448,18 +450,22 @@ int CodeGeneratorRequest::ByteSize() const { } 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)) MergeFromFail(__LINE__); const CodeGeneratorRequest* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorRequest) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorRequest) MergeFrom(*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)) MergeFromFail(__LINE__); file_to_generate_.MergeFrom(from.file_to_generate_); proto_file_.MergeFrom(from.proto_file_); @@ -475,12 +481,14 @@ void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { } void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (&from == this) return; Clear(); MergeFrom(from); } 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); @@ -545,6 +553,7 @@ void CodeGeneratorRequest::clear_file_to_generate() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.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) { @@ -610,6 +619,7 @@ void CodeGeneratorRequest::clear_parameter() { return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::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()); } @@ -728,6 +738,7 @@ CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf:: } void CodeGeneratorResponse_File::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (_has_bits_[0 / 32] & 7u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -747,7 +758,7 @@ void CodeGeneratorResponse_File::Clear() { bool CodeGeneratorResponse_File::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse.File) for (;;) { @@ -912,6 +923,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( } int CodeGeneratorResponse_File::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File) int total_size = 0; if (_has_bits_[0 / 32] & 7u) { @@ -949,18 +961,22 @@ int CodeGeneratorResponse_File::ByteSize() const { } 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)) MergeFromFail(__LINE__); const CodeGeneratorResponse_File* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse.File) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse.File) MergeFrom(*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)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -982,12 +998,14 @@ void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& fro } void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (&from == this) return; Clear(); MergeFrom(from); } 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); @@ -1088,6 +1106,7 @@ CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* are } void CodeGeneratorResponse::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse) if (has_error()) { error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1100,7 +1119,7 @@ void CodeGeneratorResponse::Clear() { bool CodeGeneratorResponse::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse) for (;;) { @@ -1219,6 +1238,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( } int CodeGeneratorResponse::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse) int total_size = 0; // optional string error = 1; @@ -1248,18 +1268,22 @@ int CodeGeneratorResponse::ByteSize() const { } 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)) MergeFromFail(__LINE__); const CodeGeneratorResponse* source = ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse) MergeFrom(*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)) MergeFromFail(__LINE__); file_.MergeFrom(from.file_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -1274,12 +1298,14 @@ void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { } void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (&from == this) return; Clear(); MergeFrom(from); } 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); @@ -1353,6 +1379,7 @@ void CodeGeneratorResponse_File::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::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()); } @@ -1406,6 +1433,7 @@ void CodeGeneratorResponse_File::clear_insertion_point() { return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::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()); } @@ -1459,6 +1487,7 @@ void CodeGeneratorResponse_File::clear_content() { return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::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()); } @@ -1516,6 +1545,7 @@ void CodeGeneratorResponse::clear_error() { return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::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()); } diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 0a03e979..510202f0 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -437,6 +437,7 @@ inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* va // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } inline ::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(); } inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { @@ -502,6 +503,7 @@ inline ::std::string* CodeGeneratorRequest::mutable_parameter() { return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::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()); } @@ -589,6 +591,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::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()); } @@ -642,6 +645,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::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()); } @@ -695,6 +699,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_content() { return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::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()); } @@ -752,6 +757,7 @@ inline ::std::string* CodeGeneratorResponse::mutable_error() { return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::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()); } diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 4d500f90..0553dd0d 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -235,7 +235,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) { // infinity * 0 = nan return "(1e10000 * 0)"; } else { - return SimpleDtoa(value); + return "float(" + SimpleDtoa(value) + ")"; } } case FieldDescriptor::CPPTYPE_FLOAT: { @@ -251,7 +251,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) { // infinity - infinity = nan return "(1e10000 * 0)"; } else { - return SimpleFtoa(value); + return "float(" + SimpleFtoa(value) + ")"; } } case FieldDescriptor::CPPTYPE_BOOL: diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc index e82bbae7..23f2449c 100644 --- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc +++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc @@ -44,9 +44,10 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/testing/file.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> -#include <google/protobuf/testing/file.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index a30ac305..6e258664 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -361,7 +361,7 @@ bool Subprocess::Communicate(const Message& input, Message* output, string output_data; int input_pos = 0; - int max_fd = max(child_stdin_, child_stdout_); + int max_fd = std::max(child_stdin_, child_stdout_); while (child_stdout_ != -1) { fd_set read_fds; diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 78a34617..56e11fa9 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -357,13 +357,20 @@ void DeleteAllowedProto3Extendee() { void InitAllowedProto3Extendee() { allowed_proto3_extendees_ = new set<string>; - allowed_proto3_extendees_->insert("google.protobuf.FileOptions"); - allowed_proto3_extendees_->insert("google.protobuf.MessageOptions"); - allowed_proto3_extendees_->insert("google.protobuf.FieldOptions"); - allowed_proto3_extendees_->insert("google.protobuf.EnumOptions"); - allowed_proto3_extendees_->insert("google.protobuf.EnumValueOptions"); - allowed_proto3_extendees_->insert("google.protobuf.ServiceOptions"); - allowed_proto3_extendees_->insert("google.protobuf.MethodOptions"); + const char* kOptionNames[] = { + "FileOptions", "MessageOptions", "FieldOptions", "EnumOptions", + "EnumValueOptions", "ServiceOptions", "MethodOptions"}; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kOptionNames); ++i) { + // descriptor.proto has a different package name in opensource. We allow + // both so the opensource protocol compiler can also compile internal + // proto3 files with custom options. See: b/27567912 + allowed_proto3_extendees_->insert(string("google.protobuf.") + + kOptionNames[i]); + // Split the word to trick the opensource processing scripts so they + // will keep the origial package name. + allowed_proto3_extendees_->insert(string("proto") + "2." + kOptionNames[i]); + } + google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee); } @@ -2766,6 +2773,9 @@ class DescriptorBuilder { private: friend class OptionInterpreter; + // Non-recursive part of BuildFile functionality. + const FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto); + const DescriptorPool* pool_; DescriptorPool::Tables* tables_; // for convenience DescriptorPool::ErrorCollector* error_collector_; @@ -3834,7 +3844,11 @@ const FileDescriptor* DescriptorBuilder::BuildFile( } tables_->pending_files_.pop_back(); } + return BuildFileImpl(proto); +} +const FileDescriptor* DescriptorBuilder::BuildFileImpl( + const FileDescriptorProto& proto) { // Checkpoint the tables so that we can roll back if something goes wrong. tables_->AddCheckpoint(); @@ -5113,11 +5127,6 @@ void DescriptorBuilder::ValidateProto3( for (int i = 0; i < file->enum_type_count(); ++i) { ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i)); } - if (IsLite(file)) { - AddError(file->name(), proto, - DescriptorPool::ErrorCollector::OTHER, - "Lite runtime is not supported in proto3."); - } } static string ToLowercaseWithoutUnderscores(const string& name) { diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 7e3a7496..3ecc0a9c 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -127,6 +127,11 @@ namespace descriptor_unittest { class DescriptorTest; } // namespace descriptor_unittest +// Defined in printer.h +namespace io { +class Printer; +} // namespace io + // NB, all indices are zero-based. struct SourceLocation { int start_line; @@ -359,6 +364,9 @@ class LIBPROTOBUF_EXPORT Descriptor { // Allows tests to test CopyTo(proto, true). friend class ::google::protobuf::descriptor_unittest::DescriptorTest; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Fill the json_name field of FieldDescriptorProto. void CopyJsonNameTo(DescriptorProto* proto) const; @@ -644,6 +652,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { private: typedef FieldOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Fill the json_name field of FieldDescriptorProto. void CopyJsonNameTo(FieldDescriptorProto* proto) const; @@ -756,6 +767,9 @@ class LIBPROTOBUF_EXPORT OneofDescriptor { bool GetSourceLocation(SourceLocation* out_location) const; private: + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string* contents, const DebugStringOptions& options) const; @@ -846,6 +860,9 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { private: typedef EnumOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Looks up a value by number. If the value does not exist, dynamically // creates a new EnumValueDescriptor for that value, assuming that it was // unknown. If a new descriptor is created, this is done in a thread-safe way, @@ -942,6 +959,9 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { private: typedef EnumValueOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string *contents, const DebugStringOptions& options) const; @@ -1018,6 +1038,9 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor { private: typedef ServiceOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(string *contents, const DebugStringOptions& options) const; @@ -1096,6 +1119,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { private: typedef MethodOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string *contents, const DebugStringOptions& options) const; diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index ff0cfcf8..4d5c4d99 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -319,7 +319,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_), -1); FileOptions_descriptor_ = file->message_type(9); - static const int FileOptions_offsets_[16] = { + static const int FileOptions_offsets_[15] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), @@ -334,7 +334,6 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, csharp_namespace_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, javanano_use_deprecated_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -746,7 +745,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr" "otobuf.MethodOptions\022\037\n\020client_streaming" "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:" - "\005false\"\256\005\n\013FileOptions\022\024\n\014java_package\030\001" + "\005false\"\207\005\n\013FileOptions\022\024\n\014java_package\030\001" " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja" "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g" "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026" @@ -758,60 +757,59 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n" "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar" "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$" - " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022+\n\037javana" - "no_use_deprecated_package\030& \001(\010B\002\030\001\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\":\n\014OptimizeMode" - "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTI" - "ME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027me" - "ssage_set_wire_format\030\001 \001(\010:\005false\022.\n\037no" - "_standard_descriptor_accessor\030\002 \001(\010:\005fal" - "se\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_ent" - "ry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132" - "$.google.protobuf.UninterpretedOption*\t\010" - "\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\016" - "2#.google.protobuf.FieldOptions.CType:\006S" - "TRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$." - "google.protobuf.FieldOptions.JSType:\tJS_" - "NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecate" - "d\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\"/\n\005CType\022\n\n\006STR" - "ING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JST" - "ype\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_" - "NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013a" - "llow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fa" - "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" - "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200" - "\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 " - "\001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(" - "\0132$.google.protobuf.UninterpretedOption*" - "\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecat" - "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" - "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" - "tion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepr" - "ecated\030! \001(\010:\005false\022C\n\024uninterpreted_opt" - "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" - "edOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpt" - "ion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unin" - "terpretedOption.NamePart\022\030\n\020identifier_v" - "alue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032" - "\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_val" - "ue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggreg" - "ate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part" - "\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceC" - "odeInfo\022:\n\010location\030\001 \003(\0132(.google.proto" - "buf.SourceCodeInfo.Location\032\206\001\n\010Location" - "\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020" - "leading_comments\030\003 \001(\t\022\031\n\021trailing_comme" - "nts\030\004 \001(\t\022!\n\031leading_detached_comments\030\006" - " \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotation" - "\030\001 \003(\0132-.google.protobuf.GeneratedCodeIn" - "fo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003(" - "\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(" - "\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020D" - "escriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032Go" - "ogle.Protobuf.Reflection", 5184); + " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024uninte" + "rpreted_option\030\347\007 \003(\0132$.google.protobuf." + "UninterpretedOption\":\n\014OptimizeMode\022\t\n\005S" + "PEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*" + "\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOptions\022&\n\027m" + "essage_set_wire_format\030\001 \001(\010:\005false\022.\n\037n" + "o_standard_descriptor_accessor\030\002 \001(\010:\005fa" + "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_en" + "try\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\013" + "2$.google.protobuf.UninterpretedOption*\t" + "\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(" + "\0162#.google.protobuf.FieldOptions.CType:\006" + "STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$" + ".google.protobuf.FieldOptions.JSType:\tJS" + "_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecat" + "ed\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024" + "uninterpreted_option\030\347\007 \003(\0132$.google.pro" + "tobuf.UninterpretedOption\"/\n\005CType\022\n\n\006ST" + "RING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JS" + "Type\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS" + "_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013" + "allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f" + "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" + "\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001" + " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepreca" + "ted\030! \001(\010:\005false\022C\n\024uninterpreted_option" + "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO" + "ption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndep" + "recated\030! \001(\010:\005false\022C\n\024uninterpreted_op" + "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" + "tedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOp" + "tion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uni" + "nterpretedOption.NamePart\022\030\n\020identifier_" + "value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022" + "\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_va" + "lue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggre" + "gate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_par" + "t\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016Source" + "CodeInfo\022:\n\010location\030\001 \003(\0132(.google.prot" + "obuf.SourceCodeInfo.Location\032\206\001\n\010Locatio" + "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n" + "\020leading_comments\030\003 \001(\t\022\031\n\021trailing_comm" + "ents\030\004 \001(\t\022!\n\031leading_detached_comments\030" + "\006 \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotatio" + "n\030\001 \003(\0132-.google.protobuf.GeneratedCodeI" + "nfo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003" + "(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001" + "(\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020" + "DescriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032G" + "oogle.Protobuf.Reflection", 5145); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -946,6 +944,7 @@ FileDescriptorSet* FileDescriptorSet::New(::google::protobuf::Arena* arena) cons } void FileDescriptorSet::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorSet) file_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -955,7 +954,7 @@ void FileDescriptorSet::Clear() { bool FileDescriptorSet::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorSet) for (;;) { @@ -1036,6 +1035,7 @@ void FileDescriptorSet::SerializeWithCachedSizes( } int FileDescriptorSet::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet) int total_size = 0; // repeated .google.protobuf.FileDescriptorProto file = 1; @@ -1058,18 +1058,22 @@ int FileDescriptorSet::ByteSize() const { } void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorSet) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileDescriptorSet* source = ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorSet>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorSet) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorSet) MergeFrom(*source); } } void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); file_.MergeFrom(from.file_); if (from._internal_metadata_.have_unknown_fields()) { @@ -1078,12 +1082,14 @@ void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { } void FileDescriptorSet::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorSet) if (&from == this) return; Clear(); MergeFrom(from); } void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorSet) if (&from == this) return; Clear(); MergeFrom(from); @@ -1237,6 +1243,7 @@ FileDescriptorProto* FileDescriptorProto::New(::google::protobuf::Arena* arena) } void FileDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorProto) if (_has_bits_[0 / 32] & 3u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -1271,7 +1278,7 @@ void FileDescriptorProto::Clear() { bool FileDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorProto) for (;;) { @@ -1706,6 +1713,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( } int FileDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -1818,18 +1826,22 @@ int FileDescriptorProto::ByteSize() const { } void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorProto) MergeFrom(*source); } } void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); dependency_.MergeFrom(from.dependency_); public_dependency_.MergeFrom(from.public_dependency_); @@ -1866,12 +1878,14 @@ void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { } void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -1962,6 +1976,7 @@ void FileDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2015,6 +2030,7 @@ void FileDescriptorProto::clear_package() { return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package) clear_has_package(); return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2057,6 +2073,7 @@ void FileDescriptorProto::clear_dependency() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency) } ::std::string* FileDescriptorProto::add_dependency() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency) return dependency_.Add(); } void FileDescriptorProto::add_dependency(const ::std::string& value) { @@ -2289,6 +2306,7 @@ const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { return options_; } ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options) clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; @@ -2332,6 +2350,7 @@ const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info( return source_code_info_; } ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info) clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; @@ -2388,6 +2407,7 @@ void FileDescriptorProto::clear_syntax() { return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_syntax() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax) clear_has_syntax(); return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2470,8 +2490,17 @@ DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New(::google::pr } void DescriptorProto_ExtensionRange::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ExtensionRange) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(DescriptorProto_ExtensionRange, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<DescriptorProto_ExtensionRange*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -2491,7 +2520,7 @@ void DescriptorProto_ExtensionRange::Clear() { bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ExtensionRange) for (;;) { @@ -2592,6 +2621,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( } int DescriptorProto_ExtensionRange::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -2622,18 +2652,22 @@ int DescriptorProto_ExtensionRange::ByteSize() const { } void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto_ExtensionRange* source = ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ExtensionRange>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ExtensionRange) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ExtensionRange) MergeFrom(*source); } } void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_start()) { @@ -2649,12 +2683,14 @@ void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRa } void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (&from == this) return; Clear(); MergeFrom(from); @@ -2753,8 +2789,17 @@ DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::New(::google::prot } void DescriptorProto_ReservedRange::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ReservedRange) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(DescriptorProto_ReservedRange, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<DescriptorProto_ReservedRange*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -2774,7 +2819,7 @@ void DescriptorProto_ReservedRange::Clear() { bool DescriptorProto_ReservedRange::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ReservedRange) for (;;) { @@ -2875,6 +2920,7 @@ void DescriptorProto_ReservedRange::SerializeWithCachedSizes( } int DescriptorProto_ReservedRange::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -2905,18 +2951,22 @@ int DescriptorProto_ReservedRange::ByteSize() const { } void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ReservedRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto_ReservedRange* source = ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ReservedRange>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ReservedRange) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ReservedRange) MergeFrom(*source); } } void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_start()) { @@ -2932,12 +2982,14 @@ void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRang } void DescriptorProto_ReservedRange::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ReservedRange) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ReservedRange) if (&from == this) return; Clear(); MergeFrom(from); @@ -3048,6 +3100,7 @@ DescriptorProto* DescriptorProto::New(::google::protobuf::Arena* arena) const { } void DescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto) if (_has_bits_[0 / 32] & 129u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -3072,7 +3125,7 @@ void DescriptorProto::Clear() { bool DescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto) for (;;) { @@ -3431,6 +3484,7 @@ void DescriptorProto::SerializeWithCachedSizes( } int DescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 129u) { @@ -3524,18 +3578,22 @@ int DescriptorProto::ByteSize() const { } void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto) MergeFrom(*source); } } void DescriptorProto::MergeFrom(const DescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); field_.MergeFrom(from.field_); extension_.MergeFrom(from.extension_); @@ -3560,12 +3618,14 @@ void DescriptorProto::MergeFrom(const DescriptorProto& from) { } void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto::CopyFrom(const DescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -3758,6 +3818,7 @@ void DescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* DescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3978,6 +4039,7 @@ const ::google::protobuf::MessageOptions& DescriptorProto::options() const { return options_; } ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options) clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; @@ -4053,6 +4115,7 @@ void DescriptorProto::clear_reserved_name() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) } ::std::string* DescriptorProto::add_reserved_name() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name) return reserved_name_.Add(); } void DescriptorProto::add_reserved_name(const ::std::string& value) { @@ -4247,6 +4310,7 @@ FieldDescriptorProto* FieldDescriptorProto::New(::google::protobuf::Arena* arena } void FieldDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldDescriptorProto) if (_has_bits_[0 / 32] & 255u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -4281,7 +4345,7 @@ void FieldDescriptorProto::Clear() { bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldDescriptorProto) for (;;) { @@ -4662,6 +4726,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( } int FieldDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 255u) { @@ -4748,18 +4813,22 @@ int FieldDescriptorProto::ByteSize() const { } void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const FieldDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldDescriptorProto) MergeFrom(*source); } } void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -4806,12 +4875,14 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { } void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -4896,6 +4967,7 @@ void FieldDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5023,6 +5095,7 @@ void FieldDescriptorProto::clear_type_name() { return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_type_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name) clear_has_type_name(); return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5076,6 +5149,7 @@ void FieldDescriptorProto::clear_extendee() { return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_extendee() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee) clear_has_extendee(); return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5129,6 +5203,7 @@ void FieldDescriptorProto::clear_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value) clear_has_default_value(); return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5206,6 +5281,7 @@ void FieldDescriptorProto::clear_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name) clear_has_json_name(); return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5246,6 +5322,7 @@ const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { return options_; } ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options) clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; @@ -5331,6 +5408,7 @@ OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena } void OneofDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto) if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5342,7 +5420,7 @@ void OneofDescriptorProto::Clear() { bool OneofDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.OneofDescriptorProto) for (;;) { @@ -5431,6 +5509,7 @@ void OneofDescriptorProto::SerializeWithCachedSizes( } int OneofDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto) int total_size = 0; // optional string name = 1; @@ -5452,18 +5531,22 @@ int OneofDescriptorProto::ByteSize() const { } void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const OneofDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const OneofDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.OneofDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.OneofDescriptorProto) MergeFrom(*source); } } void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -5477,12 +5560,14 @@ void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) { } void OneofDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.OneofDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -5555,6 +5640,7 @@ void OneofDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* OneofDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5642,6 +5728,7 @@ EnumDescriptorProto* EnumDescriptorProto::New(::google::protobuf::Arena* arena) } void EnumDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto) if (_has_bits_[0 / 32] & 5u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -5659,7 +5746,7 @@ void EnumDescriptorProto::Clear() { bool EnumDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumDescriptorProto) for (;;) { @@ -5804,6 +5891,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( } int EnumDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 5u) { @@ -5842,18 +5930,22 @@ int EnumDescriptorProto::ByteSize() const { } void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const EnumDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumDescriptorProto) MergeFrom(*source); } } void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); value_.MergeFrom(from.value_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -5871,12 +5963,14 @@ void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { } void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -5955,6 +6049,7 @@ void EnumDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6025,6 +6120,7 @@ const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { return options_; } ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; @@ -6116,6 +6212,7 @@ EnumValueDescriptorProto* EnumValueDescriptorProto::New(::google::protobuf::Aren } void EnumValueDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueDescriptorProto) if (_has_bits_[0 / 32] & 7u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -6133,7 +6230,7 @@ void EnumValueDescriptorProto::Clear() { bool EnumValueDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueDescriptorProto) for (;;) { @@ -6273,6 +6370,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( } int EnumValueDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 7u) { @@ -6310,18 +6408,22 @@ int EnumValueDescriptorProto::ByteSize() const { } void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValueDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueDescriptorProto) MergeFrom(*source); } } void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -6341,12 +6443,14 @@ void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { } void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -6424,6 +6528,7 @@ void EnumValueDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumValueDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6488,6 +6593,7 @@ const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() return options_; } ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; @@ -6578,6 +6684,7 @@ ServiceDescriptorProto* ServiceDescriptorProto::New(::google::protobuf::Arena* a } void ServiceDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceDescriptorProto) if (_has_bits_[0 / 32] & 5u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -6595,7 +6702,7 @@ void ServiceDescriptorProto::Clear() { bool ServiceDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ServiceDescriptorProto) for (;;) { @@ -6740,6 +6847,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( } int ServiceDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 5u) { @@ -6778,18 +6886,22 @@ int ServiceDescriptorProto::ByteSize() const { } void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ServiceDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const ServiceDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceDescriptorProto) MergeFrom(*source); } } void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); method_.MergeFrom(from.method_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -6807,12 +6919,14 @@ void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { } void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -6891,6 +7005,7 @@ void ServiceDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* ServiceDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6961,6 +7076,7 @@ const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() cons return options_; } ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options) clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; @@ -7060,8 +7176,17 @@ MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* are } void MethodDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodDescriptorProto) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(MethodDescriptorProto, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<MethodDescriptorProto*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -7095,7 +7220,7 @@ void MethodDescriptorProto::Clear() { bool MethodDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MethodDescriptorProto) for (;;) { @@ -7336,6 +7461,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( } int MethodDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 63u) { @@ -7390,18 +7516,22 @@ int MethodDescriptorProto::ByteSize() const { } void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MethodDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated<const MethodDescriptorProto>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodDescriptorProto) MergeFrom(*source); } } void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -7432,12 +7562,14 @@ void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { } void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -7518,6 +7650,7 @@ void MethodDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7571,6 +7704,7 @@ void MethodDescriptorProto::clear_input_type() { return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_input_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type) clear_has_input_type(); return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7624,6 +7758,7 @@ void MethodDescriptorProto::clear_output_type() { return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_output_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type) clear_has_output_type(); return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7664,6 +7799,7 @@ const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const return options_; } ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options) clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; @@ -7770,7 +7906,6 @@ const int FileOptions::kDeprecatedFieldNumber; const int FileOptions::kCcEnableArenasFieldNumber; const int FileOptions::kObjcClassPrefixFieldNumber; const int FileOptions::kCsharpNamespaceFieldNumber; -const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !defined(_MSC_VER) || _MSC_VER >= 1900 @@ -7808,7 +7943,6 @@ void FileOptions::SharedCtor() { cc_enable_arenas_ = false; objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); csharp_namespace_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - javanano_use_deprecated_package_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -7853,9 +7987,18 @@ FileOptions* FileOptions::New(::google::protobuf::Arena* arena) const { } void FileOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileOptions) _extensions_.Clear(); +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(FileOptions, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<FileOptions*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -7875,8 +8018,8 @@ void FileOptions::Clear() { go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } } - if (_has_bits_[8 / 32] & 32512u) { - ZR_(java_generic_services_, javanano_use_deprecated_package_); + if (_has_bits_[8 / 32] & 16128u) { + ZR_(java_generic_services_, cc_enable_arenas_); if (has_objc_class_prefix()) { objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7897,7 +8040,7 @@ void FileOptions::Clear() { bool FileOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileOptions) for (;;) { @@ -8125,21 +8268,6 @@ bool FileOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(304)) goto parse_javanano_use_deprecated_package; - break; - } - - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - case 38: { - if (tag == 304) { - parse_javanano_use_deprecated_package: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &javanano_use_deprecated_package_))); - set_has_javanano_use_deprecated_package(); - } else { - goto handle_unusual; - } if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } @@ -8287,11 +8415,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), output); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output); - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( @@ -8413,11 +8536,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), target); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target); - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -8438,6 +8556,7 @@ void FileOptions::SerializeWithCachedSizes( } int FileOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions) int total_size = 0; if (_has_bits_[0 / 32] & 255u) { @@ -8489,7 +8608,7 @@ int FileOptions::ByteSize() const { } } - if (_has_bits_[8 / 32] & 32512u) { + if (_has_bits_[8 / 32] & 16128u) { // optional bool java_generic_services = 17 [default = false]; if (has_java_generic_services()) { total_size += 2 + 1; @@ -8524,11 +8643,6 @@ int FileOptions::ByteSize() const { this->csharp_namespace()); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - total_size += 2 + 1; - } - } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -8552,18 +8666,22 @@ int FileOptions::ByteSize() const { } void FileOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const FileOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileOptions) MergeFrom(*source); } } void FileOptions::MergeFrom(const FileOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -8616,9 +8734,6 @@ void FileOptions::MergeFrom(const FileOptions& from) { set_has_csharp_namespace(); csharp_namespace_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.csharp_namespace_); } - if (from.has_javanano_use_deprecated_package()) { - set_javanano_use_deprecated_package(from.javanano_use_deprecated_package()); - } } _extensions_.MergeFrom(from._extensions_); if (from._internal_metadata_.have_unknown_fields()) { @@ -8627,12 +8742,14 @@ void FileOptions::MergeFrom(const FileOptions& from) { } void FileOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileOptions) if (&from == this) return; Clear(); MergeFrom(from); } void FileOptions::CopyFrom(const FileOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -8664,7 +8781,6 @@ void FileOptions::InternalSwap(FileOptions* other) { std::swap(cc_enable_arenas_, other->cc_enable_arenas_); objc_class_prefix_.Swap(&other->objc_class_prefix_); csharp_namespace_.Swap(&other->csharp_namespace_); - std::swap(javanano_use_deprecated_package_, other->javanano_use_deprecated_package_); uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); @@ -8723,6 +8839,7 @@ void FileOptions::clear_java_package() { return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_java_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package) clear_has_java_package(); return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -8776,6 +8893,7 @@ void FileOptions::clear_java_outer_classname() { return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_java_outer_classname() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname) clear_has_java_outer_classname(); return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -8926,6 +9044,7 @@ void FileOptions::clear_go_package() { return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_go_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package) clear_has_go_package(); return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9099,6 +9218,7 @@ void FileOptions::clear_objc_class_prefix() { return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_objc_class_prefix() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix) clear_has_objc_class_prefix(); return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9152,6 +9272,7 @@ void FileOptions::clear_csharp_namespace() { return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_csharp_namespace() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace) clear_has_csharp_namespace(); return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9165,30 +9286,6 @@ void FileOptions::clear_csharp_namespace() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) } -// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; -bool FileOptions::has_javanano_use_deprecated_package() const { - return (_has_bits_[0] & 0x00004000u) != 0; -} -void FileOptions::set_has_javanano_use_deprecated_package() { - _has_bits_[0] |= 0x00004000u; -} -void FileOptions::clear_has_javanano_use_deprecated_package() { - _has_bits_[0] &= ~0x00004000u; -} -void FileOptions::clear_javanano_use_deprecated_package() { - javanano_use_deprecated_package_ = false; - clear_has_javanano_use_deprecated_package(); -} - bool FileOptions::javanano_use_deprecated_package() const { - // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package) - return javanano_use_deprecated_package_; -} - void FileOptions::set_javanano_use_deprecated_package(bool value) { - set_has_javanano_use_deprecated_package(); - javanano_use_deprecated_package_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.javanano_use_deprecated_package) -} - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -9293,9 +9390,18 @@ MessageOptions* MessageOptions::New(::google::protobuf::Arena* arena) const { } void MessageOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MessageOptions) _extensions_.Clear(); +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(MessageOptions, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<MessageOptions*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -9316,7 +9422,7 @@ void MessageOptions::Clear() { bool MessageOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MessageOptions) for (;;) { @@ -9510,6 +9616,7 @@ void MessageOptions::SerializeWithCachedSizes( } int MessageOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions) int total_size = 0; if (_has_bits_[0 / 32] & 15u) { @@ -9556,18 +9663,22 @@ int MessageOptions::ByteSize() const { } void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MessageOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MessageOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const MessageOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MessageOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MessageOptions) MergeFrom(*source); } } void MessageOptions::MergeFrom(const MessageOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -9591,12 +9702,14 @@ void MessageOptions::MergeFrom(const MessageOptions& from) { } void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MessageOptions) if (&from == this) return; Clear(); MergeFrom(from); } void MessageOptions::CopyFrom(const MessageOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MessageOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -9886,9 +9999,18 @@ FieldOptions* FieldOptions::New(::google::protobuf::Arena* arena) const { } void FieldOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldOptions) _extensions_.Clear(); +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(FieldOptions, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<FieldOptions*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -9912,7 +10034,7 @@ void FieldOptions::Clear() { bool FieldOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldOptions) for (;;) { @@ -10170,6 +10292,7 @@ void FieldOptions::SerializeWithCachedSizes( } int FieldOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions) int total_size = 0; if (_has_bits_[0 / 32] & 63u) { @@ -10228,18 +10351,22 @@ int FieldOptions::ByteSize() const { } void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const FieldOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldOptions) MergeFrom(*source); } } void FieldOptions::MergeFrom(const FieldOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -10269,12 +10396,14 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { } void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldOptions) if (&from == this) return; Clear(); MergeFrom(from); } void FieldOptions::CopyFrom(const FieldOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -10562,9 +10691,18 @@ EnumOptions* EnumOptions::New(::google::protobuf::Arena* arena) const { } void EnumOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumOptions) _extensions_.Clear(); +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(EnumOptions, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<EnumOptions*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -10585,7 +10723,7 @@ void EnumOptions::Clear() { bool EnumOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumOptions) for (;;) { @@ -10729,6 +10867,7 @@ void EnumOptions::SerializeWithCachedSizes( } int EnumOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -10765,18 +10904,22 @@ int EnumOptions::ByteSize() const { } void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const EnumOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumOptions) MergeFrom(*source); } } void EnumOptions::MergeFrom(const EnumOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -10794,12 +10937,14 @@ void EnumOptions::MergeFrom(const EnumOptions& from) { } void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumOptions) if (&from == this) return; Clear(); MergeFrom(from); } void EnumOptions::CopyFrom(const EnumOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -10983,6 +11128,7 @@ EnumValueOptions* EnumValueOptions::New(::google::protobuf::Arena* arena) const } void EnumValueOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -10994,7 +11140,7 @@ void EnumValueOptions::Clear() { bool EnumValueOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueOptions) for (;;) { @@ -11113,6 +11259,7 @@ void EnumValueOptions::SerializeWithCachedSizes( } int EnumValueOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions) int total_size = 0; // optional bool deprecated = 1 [default = false]; @@ -11142,18 +11289,22 @@ int EnumValueOptions::ByteSize() const { } void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValueOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueOptions) MergeFrom(*source); } } void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11168,12 +11319,14 @@ void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { } void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueOptions) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValueOptions::CopyFrom(const EnumValueOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -11332,6 +11485,7 @@ ServiceOptions* ServiceOptions::New(::google::protobuf::Arena* arena) const { } void ServiceOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -11343,7 +11497,7 @@ void ServiceOptions::Clear() { bool ServiceOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ServiceOptions) for (;;) { @@ -11462,6 +11616,7 @@ void ServiceOptions::SerializeWithCachedSizes( } int ServiceOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions) int total_size = 0; // optional bool deprecated = 33 [default = false]; @@ -11491,18 +11646,22 @@ int ServiceOptions::ByteSize() const { } void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ServiceOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const ServiceOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceOptions) MergeFrom(*source); } } void ServiceOptions::MergeFrom(const ServiceOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11517,12 +11676,14 @@ void ServiceOptions::MergeFrom(const ServiceOptions& from) { } void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceOptions) if (&from == this) return; Clear(); MergeFrom(from); } void ServiceOptions::CopyFrom(const ServiceOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -11681,6 +11842,7 @@ MethodOptions* MethodOptions::New(::google::protobuf::Arena* arena) const { } void MethodOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -11692,7 +11854,7 @@ void MethodOptions::Clear() { bool MethodOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MethodOptions) for (;;) { @@ -11811,6 +11973,7 @@ void MethodOptions::SerializeWithCachedSizes( } int MethodOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions) int total_size = 0; // optional bool deprecated = 33 [default = false]; @@ -11840,18 +12003,22 @@ int MethodOptions::ByteSize() const { } void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MethodOptions* source = ::google::protobuf::internal::DynamicCastToGenerated<const MethodOptions>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodOptions) MergeFrom(*source); } } void MethodOptions::MergeFrom(const MethodOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11866,12 +12033,14 @@ void MethodOptions::MergeFrom(const MethodOptions& from) { } void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodOptions) if (&from == this) return; Clear(); MergeFrom(from); } void MethodOptions::CopyFrom(const MethodOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -12033,6 +12202,7 @@ UninterpretedOption_NamePart* UninterpretedOption_NamePart::New(::google::protob } void UninterpretedOption_NamePart::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption.NamePart) if (_has_bits_[0 / 32] & 3u) { if (has_name_part()) { name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -12047,7 +12217,7 @@ void UninterpretedOption_NamePart::Clear() { bool UninterpretedOption_NamePart::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption.NamePart) for (;;) { @@ -12161,6 +12331,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( } int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { +// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart) int total_size = 0; if (has_name_part()) { @@ -12178,6 +12349,7 @@ int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { return total_size; } int UninterpretedOption_NamePart::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart) int total_size = 0; if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) { // All required fields are present. @@ -12204,18 +12376,22 @@ int UninterpretedOption_NamePart::ByteSize() const { } void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption.NamePart) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UninterpretedOption_NamePart* source = ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption_NamePart>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption.NamePart) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption.NamePart) MergeFrom(*source); } } void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name_part()) { @@ -12232,12 +12408,14 @@ void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& } void UninterpretedOption_NamePart::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption.NamePart) if (&from == this) return; Clear(); MergeFrom(from); } void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption.NamePart) if (&from == this) return; Clear(); MergeFrom(from); @@ -12350,8 +12528,17 @@ UninterpretedOption* UninterpretedOption::New(::google::protobuf::Arena* arena) } void UninterpretedOption::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(UninterpretedOption, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<UninterpretedOption*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -12383,7 +12570,7 @@ void UninterpretedOption::Clear() { bool UninterpretedOption::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption) for (;;) { @@ -12641,6 +12828,7 @@ void UninterpretedOption::SerializeWithCachedSizes( } int UninterpretedOption::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption) int total_size = 0; if (_has_bits_[1 / 32] & 126u) { @@ -12705,18 +12893,22 @@ int UninterpretedOption::ByteSize() const { } void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UninterpretedOption* source = ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption) MergeFrom(*source); } } void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); name_.MergeFrom(from.name_); if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { @@ -12748,12 +12940,14 @@ void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { } void UninterpretedOption::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption) if (&from == this) return; Clear(); MergeFrom(from); } void UninterpretedOption::CopyFrom(const UninterpretedOption& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption) if (&from == this) return; Clear(); MergeFrom(from); @@ -12833,6 +13027,7 @@ void UninterpretedOption_NamePart::clear_name_part() { return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption_NamePart::release_name_part() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part) clear_has_name_part(); return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -12944,6 +13139,7 @@ void UninterpretedOption::clear_identifier_value() { return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_identifier_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value) clear_has_identifier_value(); return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13069,6 +13265,7 @@ void UninterpretedOption::clear_string_value() { return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value) clear_has_string_value(); return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13122,6 +13319,7 @@ void UninterpretedOption::clear_aggregate_value() { return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_aggregate_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value) clear_has_aggregate_value(); return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13210,6 +13408,7 @@ SourceCodeInfo_Location* SourceCodeInfo_Location::New(::google::protobuf::Arena* } void SourceCodeInfo_Location::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo.Location) if (_has_bits_[0 / 32] & 12u) { if (has_leading_comments()) { leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -13229,7 +13428,7 @@ void SourceCodeInfo_Location::Clear() { bool SourceCodeInfo_Location::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo.Location) for (;;) { @@ -13479,6 +13678,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( } int SourceCodeInfo_Location::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location) int total_size = 0; if (_has_bits_[2 / 32] & 12u) { @@ -13550,18 +13750,22 @@ int SourceCodeInfo_Location::ByteSize() const { } void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo.Location) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceCodeInfo_Location* source = ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo_Location>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo.Location) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo.Location) MergeFrom(*source); } } void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); path_.MergeFrom(from.path_); span_.MergeFrom(from.span_); @@ -13582,12 +13786,14 @@ void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { } void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo.Location) if (&from == this) return; Clear(); MergeFrom(from); } void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo.Location) if (&from == this) return; Clear(); MergeFrom(from); @@ -13686,6 +13892,7 @@ SourceCodeInfo* SourceCodeInfo::New(::google::protobuf::Arena* arena) const { } void SourceCodeInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo) location_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -13695,7 +13902,7 @@ void SourceCodeInfo::Clear() { bool SourceCodeInfo::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo) for (;;) { @@ -13776,6 +13983,7 @@ void SourceCodeInfo::SerializeWithCachedSizes( } int SourceCodeInfo::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo) int total_size = 0; // repeated .google.protobuf.SourceCodeInfo.Location location = 1; @@ -13798,18 +14006,22 @@ int SourceCodeInfo::ByteSize() const { } void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceCodeInfo* source = ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo) MergeFrom(*source); } } void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); location_.MergeFrom(from.location_); if (from._internal_metadata_.have_unknown_fields()) { @@ -13818,12 +14030,14 @@ void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { } void SourceCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); } void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); @@ -13956,6 +14170,7 @@ void SourceCodeInfo_Location::clear_leading_comments() { return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceCodeInfo_Location::release_leading_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments) clear_has_leading_comments(); return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -14009,6 +14224,7 @@ void SourceCodeInfo_Location::clear_trailing_comments() { return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceCodeInfo_Location::release_trailing_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments) clear_has_trailing_comments(); return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -14051,6 +14267,7 @@ void SourceCodeInfo_Location::clear_leading_detached_comments() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) } ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) return leading_detached_comments_.Add(); } void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) { @@ -14184,8 +14401,17 @@ GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::New(::google::protob } void GeneratedCodeInfo_Annotation::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo.Annotation) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(GeneratedCodeInfo_Annotation, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<GeneratedCodeInfo_Annotation*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -14211,7 +14437,7 @@ void GeneratedCodeInfo_Annotation::Clear() { bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo.Annotation) for (;;) { @@ -14392,6 +14618,7 @@ void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes( } int GeneratedCodeInfo_Annotation::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation) int total_size = 0; if (_has_bits_[1 / 32] & 14u) { @@ -14446,18 +14673,22 @@ int GeneratedCodeInfo_Annotation::ByteSize() const { } void GeneratedCodeInfo_Annotation::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const GeneratedCodeInfo_Annotation* source = ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo.Annotation) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo.Annotation) MergeFrom(*source); } } void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); path_.MergeFrom(from.path_); if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { @@ -14478,12 +14709,14 @@ void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& } void GeneratedCodeInfo_Annotation::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (&from == this) return; Clear(); MergeFrom(from); } void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (&from == this) return; Clear(); MergeFrom(from); @@ -14581,6 +14814,7 @@ GeneratedCodeInfo* GeneratedCodeInfo::New(::google::protobuf::Arena* arena) cons } void GeneratedCodeInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo) annotation_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -14590,7 +14824,7 @@ void GeneratedCodeInfo::Clear() { bool GeneratedCodeInfo::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo) for (;;) { @@ -14671,6 +14905,7 @@ void GeneratedCodeInfo::SerializeWithCachedSizes( } int GeneratedCodeInfo::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo) int total_size = 0; // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; @@ -14693,18 +14928,22 @@ int GeneratedCodeInfo::ByteSize() const { } void GeneratedCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const GeneratedCodeInfo* source = ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo) MergeFrom(*source); } } void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); annotation_.MergeFrom(from.annotation_); if (from._internal_metadata_.have_unknown_fields()) { @@ -14713,12 +14952,14 @@ void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) { } void GeneratedCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); } void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); @@ -14821,6 +15062,7 @@ void GeneratedCodeInfo_Annotation::clear_source_file() { return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* GeneratedCodeInfo_Annotation::release_source_file() { + // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file) clear_has_source_file(); return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 3fe07bf5..92a0a3a7 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -993,24 +993,42 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa // nested types ---------------------------------------------------- typedef FieldDescriptorProto_Type Type; - static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE; - static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT; - static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64; - static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64; - static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32; - static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64; - static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32; - static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL; - static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING; - static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP; - static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE; - static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES; - static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32; - static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM; - static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32; - static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64; - static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32; - static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64; + static const Type TYPE_DOUBLE = + FieldDescriptorProto_Type_TYPE_DOUBLE; + static const Type TYPE_FLOAT = + FieldDescriptorProto_Type_TYPE_FLOAT; + static const Type TYPE_INT64 = + FieldDescriptorProto_Type_TYPE_INT64; + static const Type TYPE_UINT64 = + FieldDescriptorProto_Type_TYPE_UINT64; + static const Type TYPE_INT32 = + FieldDescriptorProto_Type_TYPE_INT32; + static const Type TYPE_FIXED64 = + FieldDescriptorProto_Type_TYPE_FIXED64; + static const Type TYPE_FIXED32 = + FieldDescriptorProto_Type_TYPE_FIXED32; + static const Type TYPE_BOOL = + FieldDescriptorProto_Type_TYPE_BOOL; + static const Type TYPE_STRING = + FieldDescriptorProto_Type_TYPE_STRING; + static const Type TYPE_GROUP = + FieldDescriptorProto_Type_TYPE_GROUP; + static const Type TYPE_MESSAGE = + FieldDescriptorProto_Type_TYPE_MESSAGE; + static const Type TYPE_BYTES = + FieldDescriptorProto_Type_TYPE_BYTES; + static const Type TYPE_UINT32 = + FieldDescriptorProto_Type_TYPE_UINT32; + static const Type TYPE_ENUM = + FieldDescriptorProto_Type_TYPE_ENUM; + static const Type TYPE_SFIXED32 = + FieldDescriptorProto_Type_TYPE_SFIXED32; + static const Type TYPE_SFIXED64 = + FieldDescriptorProto_Type_TYPE_SFIXED64; + static const Type TYPE_SINT32 = + FieldDescriptorProto_Type_TYPE_SINT32; + static const Type TYPE_SINT64 = + FieldDescriptorProto_Type_TYPE_SINT64; static inline bool Type_IsValid(int value) { return FieldDescriptorProto_Type_IsValid(value); } @@ -1033,9 +1051,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa } typedef FieldDescriptorProto_Label Label; - static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL; - static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED; - static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED; + static const Label LABEL_OPTIONAL = + FieldDescriptorProto_Label_LABEL_OPTIONAL; + static const Label LABEL_REQUIRED = + FieldDescriptorProto_Label_LABEL_REQUIRED; + static const Label LABEL_REPEATED = + FieldDescriptorProto_Label_LABEL_REPEATED; static inline bool Label_IsValid(int value) { return FieldDescriptorProto_Label_IsValid(value); } @@ -1868,9 +1889,12 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FileOptions_OptimizeMode OptimizeMode; - static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED; - static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE; - static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME; + static const OptimizeMode SPEED = + FileOptions_OptimizeMode_SPEED; + static const OptimizeMode CODE_SIZE = + FileOptions_OptimizeMode_CODE_SIZE; + static const OptimizeMode LITE_RUNTIME = + FileOptions_OptimizeMode_LITE_RUNTIME; static inline bool OptimizeMode_IsValid(int value) { return FileOptions_OptimizeMode_IsValid(value); } @@ -2017,13 +2041,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { ::std::string* release_csharp_namespace(); void set_allocated_csharp_namespace(::std::string* csharp_namespace); - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - bool has_javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; - void clear_javanano_use_deprecated_package() PROTOBUF_DEPRECATED; - static const int kJavananoUseDeprecatedPackageFieldNumber = 38; - bool javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; - void set_javanano_use_deprecated_package(bool value) PROTOBUF_DEPRECATED; - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int uninterpreted_option_size() const; void clear_uninterpreted_option(); @@ -2067,8 +2084,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline void clear_has_objc_class_prefix(); inline void set_has_csharp_namespace(); inline void clear_has_csharp_namespace(); - inline void set_has_javanano_use_deprecated_package(); - inline void clear_has_javanano_use_deprecated_package(); ::google::protobuf::internal::ExtensionSet _extensions_; @@ -2083,14 +2098,13 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { bool cc_generic_services_; int optimize_for_; ::google::protobuf::internal::ArenaStringPtr go_package_; + ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_; + ::google::protobuf::internal::ArenaStringPtr csharp_namespace_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool java_generic_services_; bool py_generic_services_; bool deprecated_; bool cc_enable_arenas_; - bool javanano_use_deprecated_package_; - ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_; - ::google::protobuf::internal::ArenaStringPtr csharp_namespace_; - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2298,9 +2312,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FieldOptions_CType CType; - static const CType STRING = FieldOptions_CType_STRING; - static const CType CORD = FieldOptions_CType_CORD; - static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; + static const CType STRING = + FieldOptions_CType_STRING; + static const CType CORD = + FieldOptions_CType_CORD; + static const CType STRING_PIECE = + FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { return FieldOptions_CType_IsValid(value); } @@ -2323,9 +2340,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { } typedef FieldOptions_JSType JSType; - static const JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL; - static const JSType JS_STRING = FieldOptions_JSType_JS_STRING; - static const JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER; + static const JSType JS_NORMAL = + FieldOptions_JSType_JS_NORMAL; + static const JSType JS_STRING = + FieldOptions_JSType_JS_STRING; + static const JSType JS_NUMBER = + FieldOptions_JSType_JS_NUMBER; static inline bool JSType_IsValid(int value) { return FieldOptions_JSType_IsValid(value); } @@ -3696,6 +3716,7 @@ inline ::std::string* FileDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3749,6 +3770,7 @@ inline ::std::string* FileDescriptorProto::mutable_package() { return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package) clear_has_package(); return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3791,6 +3813,7 @@ inline void FileDescriptorProto::set_dependency(int index, const char* value, si // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency) } inline ::std::string* FileDescriptorProto::add_dependency() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency) return dependency_.Add(); } inline void FileDescriptorProto::add_dependency(const ::std::string& value) { @@ -4023,6 +4046,7 @@ inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options) clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; @@ -4066,6 +4090,7 @@ inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_c return source_code_info_; } inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info) clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; @@ -4122,6 +4147,7 @@ inline ::std::string* FileDescriptorProto::mutable_syntax() { return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_syntax() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax) clear_has_syntax(); return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4283,6 +4309,7 @@ inline ::std::string* DescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* DescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4503,6 +4530,7 @@ inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options) clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; @@ -4578,6 +4606,7 @@ inline void DescriptorProto::set_reserved_name(int index, const char* value, siz // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) } inline ::std::string* DescriptorProto::add_reserved_name() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name) return reserved_name_.Add(); } inline void DescriptorProto::add_reserved_name(const ::std::string& value) { @@ -4647,6 +4676,7 @@ inline ::std::string* FieldDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4774,6 +4804,7 @@ inline ::std::string* FieldDescriptorProto::mutable_type_name() { return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_type_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name) clear_has_type_name(); return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4827,6 +4858,7 @@ inline ::std::string* FieldDescriptorProto::mutable_extendee() { return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_extendee() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee) clear_has_extendee(); return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4880,6 +4912,7 @@ inline ::std::string* FieldDescriptorProto::mutable_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value) clear_has_default_value(); return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4957,6 +4990,7 @@ inline ::std::string* FieldDescriptorProto::mutable_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name) clear_has_json_name(); return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4997,6 +5031,7 @@ inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() return options_; } inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options) clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; @@ -5057,6 +5092,7 @@ inline ::std::string* OneofDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* OneofDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5114,6 +5150,7 @@ inline ::std::string* EnumDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5184,6 +5221,7 @@ inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; @@ -5244,6 +5282,7 @@ inline ::std::string* EnumValueDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumValueDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5308,6 +5347,7 @@ inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_o return options_; } inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; @@ -5368,6 +5408,7 @@ inline ::std::string* ServiceDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* ServiceDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5438,6 +5479,7 @@ inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_optio return options_; } inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options) clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; @@ -5498,6 +5540,7 @@ inline ::std::string* MethodDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5551,6 +5594,7 @@ inline ::std::string* MethodDescriptorProto::mutable_input_type() { return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_input_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type) clear_has_input_type(); return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5604,6 +5648,7 @@ inline ::std::string* MethodDescriptorProto::mutable_output_type() { return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_output_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type) clear_has_output_type(); return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5644,6 +5689,7 @@ inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options return options_; } inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options) clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; @@ -5752,6 +5798,7 @@ inline ::std::string* FileOptions::mutable_java_package() { return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_java_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package) clear_has_java_package(); return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5805,6 +5852,7 @@ inline ::std::string* FileOptions::mutable_java_outer_classname() { return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_java_outer_classname() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname) clear_has_java_outer_classname(); return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5955,6 +6003,7 @@ inline ::std::string* FileOptions::mutable_go_package() { return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_go_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package) clear_has_go_package(); return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6128,6 +6177,7 @@ inline ::std::string* FileOptions::mutable_objc_class_prefix() { return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_objc_class_prefix() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix) clear_has_objc_class_prefix(); return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6181,6 +6231,7 @@ inline ::std::string* FileOptions::mutable_csharp_namespace() { return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_csharp_namespace() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace) clear_has_csharp_namespace(); return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6194,30 +6245,6 @@ inline void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_na // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) } -// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; -inline bool FileOptions::has_javanano_use_deprecated_package() const { - return (_has_bits_[0] & 0x00004000u) != 0; -} -inline void FileOptions::set_has_javanano_use_deprecated_package() { - _has_bits_[0] |= 0x00004000u; -} -inline void FileOptions::clear_has_javanano_use_deprecated_package() { - _has_bits_[0] &= ~0x00004000u; -} -inline void FileOptions::clear_javanano_use_deprecated_package() { - javanano_use_deprecated_package_ = false; - clear_has_javanano_use_deprecated_package(); -} -inline bool FileOptions::javanano_use_deprecated_package() const { - // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package) - return javanano_use_deprecated_package_; -} -inline void FileOptions::set_javanano_use_deprecated_package(bool value) { - set_has_javanano_use_deprecated_package(); - javanano_use_deprecated_package_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.javanano_use_deprecated_package) -} - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -6858,6 +6885,7 @@ inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption_NamePart::release_name_part() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part) clear_has_name_part(); return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6969,6 +6997,7 @@ inline ::std::string* UninterpretedOption::mutable_identifier_value() { return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_identifier_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value) clear_has_identifier_value(); return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7094,6 +7123,7 @@ inline ::std::string* UninterpretedOption::mutable_string_value() { return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value) clear_has_string_value(); return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7147,6 +7177,7 @@ inline ::std::string* UninterpretedOption::mutable_aggregate_value() { return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_aggregate_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value) clear_has_aggregate_value(); return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7264,6 +7295,7 @@ inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() { return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceCodeInfo_Location::release_leading_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments) clear_has_leading_comments(); return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7317,6 +7349,7 @@ inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() { return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments) clear_has_trailing_comments(); return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7359,6 +7392,7 @@ inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, co // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) } inline ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) return leading_detached_comments_.Add(); } inline void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) { @@ -7492,6 +7526,7 @@ inline ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() { return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* GeneratedCodeInfo_Annotation::release_source_file() { + // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file) clear_has_source_file(); return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 3e664d59..08b15554 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -377,15 +377,13 @@ message FileOptions { // Namespace for generated classes; defaults to the package. optional string csharp_namespace = 37; - // Whether the nano proto compiler should generate in the deprecated non-nano - // suffixed package. - optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; + + reserved 38; } message MessageOptions { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index be8e0b72..f937b9ea 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -54,6 +54,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -5739,18 +5740,6 @@ TEST_F(ValidationErrorTest, ValidateProto3Enum) { "}"); } -TEST_F(ValidationErrorTest, ValidateProto3LiteRuntime) { - // Lite runtime is not supported in proto3. - BuildFileWithErrors( - "name: 'foo.proto' " - "syntax: 'proto3' " - "options { " - " optimize_for: LITE_RUNTIME " - "} ", - "foo.proto: foo.proto: OTHER: Lite runtime is not supported " - "in proto3.\n"); -} - TEST_F(ValidationErrorTest, ValidateProto3Group) { BuildFileWithErrors( "name: 'foo.proto' " diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index b325944e..e3639346 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\036google/protobuf/duration.proto\022\017google" ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r" - "\n\005nanos\030\002 \001(\005BP\n\023com.google.protobufB\rDu" - "rationProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf" - ".WellKnownTypesb\006proto3", 183); + "\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu" + "rationProtoP\001Z*github.com/golang/protobu" + "f/ptypes/duration\240\001\001\242\002\003GPB\252\002\036Google.Prot" + "obuf.WellKnownTypesb\006proto3", 227); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/duration.proto", &protobuf_RegisterTypes); Duration::default_instance_ = new Duration(); @@ -178,8 +179,17 @@ Duration* Duration::New(::google::protobuf::Arena* arena) const { } void Duration::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(Duration, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<Duration*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -195,7 +205,7 @@ void Duration::Clear() { bool Duration::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Duration) for (;;) { @@ -287,6 +297,7 @@ void Duration::SerializeWithCachedSizes( } int Duration::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration) int total_size = 0; // optional int64 seconds = 1; @@ -310,18 +321,22 @@ int Duration::ByteSize() const { } void Duration::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Duration) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Duration* source = ::google::protobuf::internal::DynamicCastToGenerated<const Duration>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Duration) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Duration) MergeFrom(*source); } } void Duration::MergeFrom(const Duration& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.seconds() != 0) { set_seconds(from.seconds()); @@ -332,12 +347,14 @@ void Duration::MergeFrom(const Duration& from) { } void Duration::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Duration) if (&from == this) return; Clear(); MergeFrom(from); } void Duration::CopyFrom(const Duration& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 78bcc74b..96c1796d 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/duration"; option java_package = "com.google.protobuf"; option java_outer_classname = "DurationProto"; option java_multiple_files = true; @@ -80,6 +81,7 @@ option objc_class_prefix = "GPB"; // end.nanos -= 1000000000; // } // +// message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 8d689ac8..9e83bd29 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -267,6 +267,16 @@ class DynamicMessage : public Message { Metadata GetMetadata() const; + // We actually allocate more memory than sizeof(*this) when this + // class's memory is allocated via the global operator new. Thus, we need to + // manually call the global operator delete. Calling the destructor is taken + // care of for us. This makes DynamicMessage compatible with -fsized-delete. + // It doesn't work for MSVC though. +#ifndef _MSC_VER + static void operator delete(void* ptr) { + ::operator delete(ptr); + } +#endif // !_MSC_VER private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); @@ -442,8 +452,10 @@ DynamicMessage::~DynamicMessage() { case FieldOptions::STRING: { const ::std::string* default_value = &(reinterpret_cast<const ArenaStringPtr*>( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i]))->Get(NULL)); + reinterpret_cast<uint8*>( + type_info_->default_oneof_instance) + + type_info_->offsets[i]) + ->Get(NULL)); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy( default_value, NULL); break; @@ -704,7 +716,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( // Oneof fields do not use any space. if (!type->field(i)->containing_oneof()) { int field_size = FieldSpaceUsed(type->field(i)); - size = AlignTo(size, min(kSafeAlignment, field_size)); + size = AlignTo(size, std::min(kSafeAlignment, field_size)); offsets[i] = size; size += field_size; } @@ -748,7 +760,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = type->oneof_decl(i)->field(j); int field_size = OneofFieldSpaceUsed(field); - oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size)); + oneof_size = AlignTo(oneof_size, std::min(kSafeAlignment, field_size)); offsets[field->index()] = oneof_size; oneof_size += field_size; } diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index f2eec782..dcf84263 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -80,9 +80,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\033google/protobuf/empty.proto\022\017google.pr" - "otobuf\"\007\n\005EmptyBP\n\023com.google.protobufB\n" - "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob" - "uf.WellKnownTypesb\006proto3", 145); + "otobuf\"\007\n\005EmptyBy\n\023com.google.protobufB\n" + "EmptyProtoP\001Z\'github.com/golang/protobuf" + "/ptypes/empty\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Proto" + "buf.WellKnownTypesb\006proto3", 186); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/empty.proto", &protobuf_RegisterTypes); Empty::default_instance_ = new Empty(); @@ -185,11 +186,12 @@ Empty* Empty::New(::google::protobuf::Arena* arena) const { } void Empty::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Empty) } bool Empty::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Empty) for (;;) { @@ -227,6 +229,7 @@ void Empty::SerializeWithCachedSizes( } int Empty::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty) int total_size = 0; GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); @@ -236,28 +239,34 @@ int Empty::ByteSize() const { } void Empty::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Empty) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Empty* source = ::google::protobuf::internal::DynamicCastToGenerated<const Empty>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Empty) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Empty) MergeFrom(*source); } } void Empty::MergeFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); } void Empty::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Empty) if (&from == this) return; Clear(); MergeFrom(from); } void Empty::CopyFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Empty) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto index b96daf28..37f4cd10 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/empty"; option java_package = "com.google.protobuf"; option java_outer_classname = "EmptyProto"; option java_multiple_files = true; diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index 01a6ce56..c49ebceb 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -175,12 +175,13 @@ FieldMask* FieldMask::New(::google::protobuf::Arena* arena) const { } void FieldMask::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask) paths_.Clear(); } bool FieldMask::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldMask) for (;;) { @@ -262,6 +263,7 @@ void FieldMask::SerializeWithCachedSizes( } int FieldMask::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask) int total_size = 0; // repeated string paths = 1; @@ -278,29 +280,35 @@ int FieldMask::ByteSize() const { } void FieldMask::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldMask) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldMask* source = ::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldMask) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldMask) MergeFrom(*source); } } void FieldMask::MergeFrom(const FieldMask& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); paths_.MergeFrom(from.paths_); } void FieldMask::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldMask) if (&from == this) return; Clear(); MergeFrom(from); } void FieldMask::CopyFrom(const FieldMask& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask) if (&from == this) return; Clear(); MergeFrom(from); @@ -361,6 +369,7 @@ void FieldMask::clear_paths() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths) } ::std::string* FieldMask::add_paths() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths) return paths_.Add(); } void FieldMask::add_paths(const ::std::string& value) { diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 7189fd79..f5e0b655 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -164,6 +164,7 @@ inline void FieldMask::set_paths(int index, const char* value, size_t size) { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths) } inline ::std::string* FieldMask::add_paths() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths) return paths_.Add(); } inline void FieldMask::add_paths(const ::std::string& value) { diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index 908c8a86..6af6dbe8 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -88,7 +88,7 @@ option java_generate_equals_and_hash = true; // operation applies to all fields (as if a FieldMask of all fields // had been specified). // -// Note that a field mask does not necessarily applies to the +// Note that a field mask does not necessarily apply to the // top-level response message. In case of a REST get operation, the // field mask applies directly to the response, but in case of a REST // list operation, the mask instead applies to each individual message @@ -162,6 +162,32 @@ option java_generate_equals_and_hash = true; // mask: "user.displayName,photo" // } // +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. message FieldMask { // The set of field mask paths. repeated string paths = 1; diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index eee024ee..2313181c 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -412,6 +412,15 @@ void GeneratedMessageReflection::SwapField( #undef SWAP_ARRAYS case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw<RepeatedPtrFieldBase>(message1, field)-> + Swap<GenericTypeHandler<string> >( + MutableRaw<RepeatedPtrFieldBase>(message2, field)); + break; + } + break; case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { MutableRaw<MapFieldBase>(message1, field)-> @@ -447,16 +456,50 @@ void GeneratedMessageReflection::SwapField( SWAP_VALUES(ENUM , int ); #undef SWAP_VALUES case FieldDescriptor::CPPTYPE_MESSAGE: - std::swap(*MutableRaw<Message*>(message1, field), - *MutableRaw<Message*>(message2, field)); + if (GetArena(message1) == GetArena(message2)) { + std::swap(*MutableRaw<Message*>(message1, field), + *MutableRaw<Message*>(message2, field)); + } else { + Message** sub_msg1 = MutableRaw<Message*>(message1, field); + Message** sub_msg2 = MutableRaw<Message*>(message2, field); + if (*sub_msg1 == NULL && *sub_msg2 == NULL) break; + if (*sub_msg1 && *sub_msg2) { + (*sub_msg1)->GetReflection()->Swap(*sub_msg1, *sub_msg2); + break; + } + if (*sub_msg1 == NULL) { + *sub_msg1 = (*sub_msg2)->New(message1->GetArena()); + (*sub_msg1)->CopyFrom(**sub_msg2); + ClearField(message2, field); + } else { + *sub_msg2 = (*sub_msg1)->New(message2->GetArena()); + (*sub_msg2)->CopyFrom(**sub_msg1); + ClearField(message1, field); + } + } break; case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: - MutableRaw<ArenaStringPtr>(message1, field)->Swap( - MutableRaw<ArenaStringPtr>(message2, field)); + { + Arena* arena1 = GetArena(message1); + Arena* arena2 = GetArena(message2); + ArenaStringPtr* string1 = + MutableRaw<ArenaStringPtr>(message1, field); + ArenaStringPtr* string2 = + MutableRaw<ArenaStringPtr>(message2, field); + if (arena1 == arena2) { + string1->Swap(string2); + } else { + const string* default_ptr = + &DefaultRaw<ArenaStringPtr>(field).Get(NULL); + const string temp = string1->Get(default_ptr); + string1->Set(default_ptr, string2->Get(default_ptr), arena1); + string2->Set(default_ptr, temp, arena2); + } + } break; } break; @@ -1752,7 +1795,8 @@ bool GeneratedMessageReflection::InsertOrLookupMapValue( "InsertOrLookupMapValue", "Field is not a map field."); val->SetType(field->message_type()->FindFieldByName("value")->cpp_type()); - return MutableRaw<MapFieldBase>(message, field)->InsertMapValue(key, val); + return MutableRaw<MapFieldBase>(message, field)->InsertOrLookupMapValue( + key, val); } bool GeneratedMessageReflection::DeleteMapValue( diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 9ef78710..15fc802c 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -582,7 +582,16 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { // which the offsets of the direct fields of a class are non-constant. // Fields inherited from superclasses *can* have non-constant offsets, // but that's not what this macro will be used for. -// +#if defined(__clang__) +// For Clang we use __builtin_offsetof() and suppress the warning, +// to avoid Control Flow Integrity and UBSan vptr sanitizers from +// crashing while trying to validate the invalid reinterpet_casts. +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(TYPE, FIELD) \ + _Pragma("clang diagnostic pop") +#else // Note that we calculate relative to the pointer value 16 here since if we // just use zero, GCC complains about dereferencing a NULL pointer. We // choose 16 rather than some other number just in case the compiler would @@ -592,6 +601,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { reinterpret_cast<const char*>( \ &reinterpret_cast<const TYPE*>(16)->FIELD) - \ reinterpret_cast<const char*>(16)) +#endif #define PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ONEOF, FIELD) \ static_cast<int>( \ diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 78c8d7ff..4475556a 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -42,8 +42,8 @@ #include <string> #include <google/protobuf/stubs/once.h> - #include <google/protobuf/stubs/common.h> + namespace google { namespace protobuf { @@ -63,6 +63,8 @@ namespace internal { #undef DEPRECATED_PROTOBUF_FIELD #define PROTOBUF_DEPRECATED +#define PROTOBUF_DEPRECATED_ATTR + // Constants for special floating point values. LIBPROTOBUF_EXPORT double Infinity(); diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index e3a34d0a..d8354c1f 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -105,7 +105,7 @@ void CodedInputStream::BackUpInputToCurrentPosition() { inline void CodedInputStream::RecomputeBufferLimits() { buffer_end_ += buffer_size_after_limit_; - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); if (closest_limit < total_bytes_read_) { // The limit position is in the current buffer. We must adjust // the buffer size accordingly. @@ -135,7 +135,7 @@ CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // We need to enforce all limits, not just the new one, so if the previous // limit was before the new requested limit, we continue to enforce the // previous limit. - current_limit_ = min(current_limit_, old_limit); + current_limit_ = std::min(current_limit_, old_limit); RecomputeBufferLimits(); return old_limit; @@ -188,7 +188,7 @@ void CodedInputStream::SetTotalBytesLimit( // Make sure the limit isn't already past, since this could confuse other // code. int current_position = CurrentPosition(); - total_bytes_limit_ = max(current_position, total_bytes_limit); + total_bytes_limit_ = std::max(current_position, total_bytes_limit); if (warning_threshold >= 0) { total_bytes_warning_threshold_ = warning_threshold; } else { @@ -233,7 +233,7 @@ bool CodedInputStream::Skip(int count) { buffer_end_ = buffer_; // Make sure this skip doesn't try to skip past the current limit. - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); int bytes_until_limit = closest_limit - total_bytes_read_; if (bytes_until_limit < count) { // We hit the limit. Skip up to it then fail. @@ -270,7 +270,7 @@ bool CodedInputStream::ReadStringFallback(string* buffer, int size) { buffer->clear(); } - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); if (closest_limit != INT_MAX) { int bytes_to_limit = closest_limit - CurrentPosition(); if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) { diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index e3771003..c81a33ac 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -1136,7 +1136,7 @@ inline void CodedOutputStream::WriteVarint32(uint32 value) { // this write won't cross the end, so we can skip the checks. uint8* target = buffer_; uint8* end = WriteVarint32ToArray(value, target); - int size = end - target; + int size = static_cast<int>(end - target); Advance(size); } else { WriteVarint32SlowPath(value); diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index d1782e39..a8108e45 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -46,7 +46,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/scoped_ptr.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> #include <google/protobuf/io/zero_copy_stream_impl.h> diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h index 82445000..15b02fe3 100644 --- a/src/google/protobuf/io/gzip_stream.h +++ b/src/google/protobuf/io/gzip_stream.h @@ -43,10 +43,9 @@ #ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ #define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ -#include <zlib.h> - #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/zero_copy_stream.h> +#include <zlib.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 7d886506..7532b098 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -42,13 +42,25 @@ namespace protobuf { namespace io { Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter) - : variable_delimiter_(variable_delimiter), - output_(output), - buffer_(NULL), - buffer_size_(0), - at_start_of_line_(true), - failed_(false) { -} + : variable_delimiter_(variable_delimiter), + output_(output), + buffer_(NULL), + buffer_size_(0), + offset_(0), + at_start_of_line_(true), + failed_(false), + annotation_collector_(NULL) {} + +Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter, + AnnotationCollector* annotation_collector) + : variable_delimiter_(variable_delimiter), + output_(output), + buffer_(NULL), + buffer_size_(0), + offset_(0), + at_start_of_line_(true), + failed_(false), + annotation_collector_(annotation_collector) {} Printer::~Printer() { // Only BackUp() if we have called Next() at least once and never failed. @@ -57,9 +69,47 @@ Printer::~Printer() { } } +bool Printer::GetSubstitutionRange(const char* varname, + pair<size_t, size_t>* range) { + map<string, pair<size_t, size_t> >::const_iterator iter = + substitutions_.find(varname); + if (iter == substitutions_.end()) { + GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname; + return false; + } + if (iter->second.first > iter->second.second) { + GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: " + << varname; + return false; + } + *range = iter->second; + return true; +} + +void Printer::Annotate(const char* begin_varname, const char* end_varname, + const string& file_path, const vector<int>& path) { + if (annotation_collector_ == NULL) { + // Can't generate signatures with this Printer. + return; + } + pair<size_t, size_t> begin, end; + if (!GetSubstitutionRange(begin_varname, &begin) || + !GetSubstitutionRange(end_varname, &end)) { + return; + } + if (begin.first > end.second) { + GOOGLE_LOG(DFATAL) << " Annotation has negative length from " << begin_varname + << " to " << end_varname; + } else { + annotation_collector_->AddAnnotation(begin.first, end.second, file_path, + path); + } +} + void Printer::Print(const map<string, string>& variables, const char* text) { int size = strlen(text); int pos = 0; // The number of bytes we've written so far. + substitutions_.clear(); for (int i = 0; i < size; i++) { if (text[i] == '\n') { @@ -97,7 +147,17 @@ void Printer::Print(const map<string, string>& variables, const char* text) { if (iter == variables.end()) { GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname; } else { + size_t begin = offset_; WriteRaw(iter->second.data(), iter->second.size()); + pair<map<string, pair<size_t, size_t> >::iterator, bool> inserted = + substitutions_.insert( + std::make_pair(varname, std::make_pair(begin, offset_))); + if (!inserted.second) { + // This variable was used multiple times. Make its span have + // negative length so we can detect it if it gets used in an + // annotation. + inserted.first->second = std::make_pair(1, 0); + } } } @@ -265,6 +325,7 @@ void Printer::WriteRaw(const char* data, int size) { // Data exceeds space in the buffer. Copy what we can and request a // new buffer. memcpy(buffer_, data, buffer_size_); + offset_ += buffer_size_; data += buffer_size_; size -= buffer_size_; void* void_buffer; @@ -277,6 +338,7 @@ void Printer::WriteRaw(const char* data, int size) { memcpy(buffer_, data, size); buffer_ += size; buffer_size_ -= size; + offset_ += size; } } // namespace io diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index f1490bbe..2ba84559 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -39,6 +39,7 @@ #include <string> #include <map> +#include <vector> #include <google/protobuf/stubs/common.h> namespace google { @@ -47,6 +48,47 @@ namespace io { class ZeroCopyOutputStream; // zero_copy_stream.h +// Records annotations about a Printer's output. +class LIBPROTOBUF_EXPORT AnnotationCollector { + public: + // Records that the bytes in file_path beginning with begin_offset and ending + // before end_offset are associated with the SourceCodeInfo-style path. + virtual void AddAnnotation(size_t begin_offset, size_t end_offset, + const string& file_path, + const vector<int>& path) = 0; + + virtual ~AnnotationCollector() {} +}; + +// Records annotations about a Printer's output to the given protocol buffer, +// assuming that the buffer has an ::Annotation message exposing path, +// source_file, begin and end fields. +template <typename AnnotationProto> +class AnnotationProtoCollector : public AnnotationCollector { + public: + // annotation_proto is the protocol buffer to which new Annotations should be + // added. It is not owned by the AnnotationProtoCollector. + explicit AnnotationProtoCollector(AnnotationProto* annotation_proto) + : annotation_proto_(annotation_proto) {} + + // Override for AnnotationCollector::AddAnnotation. + virtual void AddAnnotation(size_t begin_offset, size_t end_offset, + const string& file_path, const vector<int>& path) { + typename AnnotationProto::Annotation* annotation = + annotation_proto_->add_annotation(); + for (int i = 0; i < path.size(); ++i) { + annotation->add_path(path[i]); + } + annotation->set_source_file(file_path); + annotation->set_begin(begin_offset); + annotation->set_end(end_offset); + } + + private: + // The protocol buffer to which new annotations should be added. + AnnotationProto* const annotation_proto_; +}; + // This simple utility class assists in code generation. It basically // allows the caller to define a set of variables and then output some // text with variable substitutions. Example usage: @@ -61,13 +103,103 @@ class ZeroCopyOutputStream; // zero_copy_stream.h // Printer aggressively enforces correct usage, crashing (with assert failures) // in the case of undefined variables in debug builds. This helps greatly in // debugging code which uses it. +// +// If a Printer is constructed with an AnnotationCollector, it will provide it +// with annotations that connect the Printer's output to paths that can identify +// various descriptors. In the above example, if person_ is a descriptor that +// identifies Bob, we can associate the output string "My name is Bob." with +// a source path pointing to that descriptor with: +// +// printer.Annotate("name", person_); +// +// The AnnotationCollector will be sent an annotation linking the output range +// covering "Bob" to the logical path provided by person_. Tools may use +// this association to (for example) link "Bob" in the output back to the +// source file that defined the person_ descriptor identifying Bob. +// +// Annotate can only examine variables substituted during the last call to +// Print. It is invalid to refer to a variable that was used multiple times +// in a single Print call. +// +// In full generality, one may specify a range of output text using a beginning +// substitution variable and an ending variable. The resulting annotation will +// span from the first character of the substituted value for the beginning +// variable to the last character of the substituted value for the ending +// variable. For example, the Annotate call above is equivalent to this one: +// +// printer.Annotate("name", "name", person_); +// +// This is useful if multiple variables combine to form a single span of output +// that should be annotated with the same source path. For example: +// +// Printer printer(output, '$'); +// map<string, string> vars; +// vars["first"] = "Alice"; +// vars["last"] = "Smith"; +// printer.Print(vars, "My name is $first$ $last$."); +// printer.Annotate("first", "last", person_); +// +// This code would associate the span covering "Alice Smith" in the output with +// the person_ descriptor. +// +// Note that the beginning variable must come before (or overlap with, in the +// case of zero-sized substitution values) the ending variable. +// +// It is also sometimes useful to use variables with zero-sized values as +// markers. This avoids issues with multiple references to the same variable +// and also allows annotation ranges to span literal text from the Print +// templates: +// +// Printer printer(output, '$'); +// map<string, string> vars; +// vars["foo"] = "bar"; +// vars["function"] = "call"; +// vars["mark"] = ""; +// printer.Print(vars, "$function$($foo$,$foo$)$mark$"); +// printer.Annotate("function", "rmark", call_); +// +// This code associates the span covering "call(bar,bar)" in the output with the +// call_ descriptor. + class LIBPROTOBUF_EXPORT Printer { public: // Create a printer that writes text to the given output stream. Use the // given character as the delimiter for variables. Printer(ZeroCopyOutputStream* output, char variable_delimiter); + + // Create a printer that writes text to the given output stream. Use the + // given character as the delimiter for variables. If annotation_collector + // is not null, Printer will provide it with annotations about code written + // to the stream. annotation_collector is not owned by Printer. + Printer(ZeroCopyOutputStream* output, char variable_delimiter, + AnnotationCollector* annotation_collector); + ~Printer(); + // Link a subsitution variable emitted by the last call to Print to the object + // described by descriptor. + template <typename SomeDescriptor> + void Annotate(const char* varname, const SomeDescriptor* descriptor) { + Annotate(varname, varname, descriptor); + } + + // Link the output range defined by the substitution variables as emitted by + // the last call to Print to the object described by descriptor. The range + // begins at begin_varname's value and ends after the last character of the + // value substituted for end_varname. + template <typename SomeDescriptor> + void Annotate(const char* begin_varname, const char* end_varname, + const SomeDescriptor* descriptor) { + if (annotation_collector_ == NULL) { + // Annotations aren't turned on for this Printer, so don't pay the cost + // of building the location path. + return; + } + vector<int> path; + descriptor->GetLocationPath(&path); + Annotate(begin_varname, end_varname, descriptor->file()->name(), path); + } + // Print some text after applying variable substitutions. If a particular // variable in the text is not defined, this will crash. Variables to be // substituted are identified by their names surrounded by delimiter @@ -149,16 +281,48 @@ class LIBPROTOBUF_EXPORT Printer { bool failed() const { return failed_; } private: + // Link the output range defined by the substitution variables as emitted by + // the last call to Print to the object found at the SourceCodeInfo-style path + // in a file with path file_path. The range begins at the start of + // begin_varname's value and ends after the last character of the value + // substituted for end_varname. Note that begin_varname and end_varname + // may refer to the same variable. + void Annotate(const char* begin_varname, const char* end_varname, + const string& file_path, const vector<int>& path); + const char variable_delimiter_; ZeroCopyOutputStream* const output_; char* buffer_; int buffer_size_; + // The current position, in bytes, in the output stream. This is equivalent + // to the total number of bytes that have been written so far. This value is + // used to calculate annotation ranges in the substitutions_ map below. + size_t offset_; string indent_; bool at_start_of_line_; bool failed_; + // A map from variable name to [start, end) offsets in the output buffer. + // These refer to the offsets used for a variable after the last call to + // Print. If a variable was used more than once, the entry used in + // this map is set to a negative-length span. For singly-used variables, the + // start offset is the beginning of the substitution; the end offset is the + // last byte of the substitution plus one (such that (end - start) is the + // length of the substituted string). + map<string, pair<size_t, size_t> > substitutions_; + + // Returns true and sets range to the substitution range in the output for + // varname if varname was used once in the last call to Print. If varname + // was not used, or if it was used multiple times, returns false (and + // fails a debug assertion). + bool GetSubstitutionRange(const char* varname, pair<size_t, size_t>* range); + + // If non-null, annotation_collector_ is used to store annotations about + // generated code. + AnnotationCollector* const annotation_collector_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer); }; diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 258dd986..95f3afa2 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -36,6 +36,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> @@ -169,6 +170,196 @@ TEST(Printer, InlineVariableSubstitution) { buffer); } +// MockDescriptorFile defines only those members that Printer uses to write out +// annotations. +class MockDescriptorFile { + public: + explicit MockDescriptorFile(const string& file) : file_(file) {} + + // The mock filename for this file. + const string& name() const { return file_; } + + private: + string file_; +}; + +// MockDescriptor defines only those members that Printer uses to write out +// annotations. +class MockDescriptor { + public: + MockDescriptor(const string& file, const vector<int>& path) + : file_(file), path_(path) {} + + // The mock file in which this descriptor was defined. + const MockDescriptorFile* file() const { return &file_; } + + private: + // Allows access to GetLocationPath. + friend class ::google::protobuf::io::Printer; + + // Copies the pre-stored path to output. + void GetLocationPath(std::vector<int>* output) const { *output = path_; } + + MockDescriptorFile file_; + vector<int> path_; +}; + +TEST(Printer, AnnotateMap) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + map<string, string> vars; + vars["foo"] = "3"; + vars["bar"] = "5"; + printer.Print(vars, "012$foo$4$bar$\n"); + vector<int> path_1; + path_1.push_back(33); + vector<int> path_2; + path_2.push_back(11); + path_2.push_back(22); + MockDescriptor descriptor_1("path_1", path_1); + MockDescriptor descriptor_2("path_2", path_2); + printer.Annotate("foo", "foo", &descriptor_1); + printer.Annotate("bar", "bar", &descriptor_2); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(2, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1 + ? &info.annotation(0) + : &info.annotation(1); + const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1 + ? &info.annotation(1) + : &info.annotation(0); + ASSERT_EQ(1, foo->path_size()); + ASSERT_EQ(2, bar->path_size()); + EXPECT_EQ(33, foo->path(0)); + EXPECT_EQ(11, bar->path(0)); + EXPECT_EQ(22, bar->path(1)); + EXPECT_EQ("path_1", foo->source_file()); + EXPECT_EQ("path_2", bar->source_file()); + EXPECT_EQ(3, foo->begin()); + EXPECT_EQ(4, foo->end()); + EXPECT_EQ(5, bar->begin()); + EXPECT_EQ(6, bar->end()); +} + +TEST(Printer, AnnotateInline) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector<int> path_1; + path_1.push_back(33); + vector<int> path_2; + path_2.push_back(11); + path_2.push_back(22); + MockDescriptor descriptor_1("path_1", path_1); + MockDescriptor descriptor_2("path_2", path_2); + printer.Annotate("foo", "foo", &descriptor_1); + printer.Annotate("bar", "bar", &descriptor_2); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(2, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1 + ? &info.annotation(0) + : &info.annotation(1); + const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1 + ? &info.annotation(1) + : &info.annotation(0); + ASSERT_EQ(1, foo->path_size()); + ASSERT_EQ(2, bar->path_size()); + EXPECT_EQ(33, foo->path(0)); + EXPECT_EQ(11, bar->path(0)); + EXPECT_EQ(22, bar->path(1)); + EXPECT_EQ("path_1", foo->source_file()); + EXPECT_EQ("path_2", bar->source_file()); + EXPECT_EQ(3, foo->begin()); + EXPECT_EQ(4, foo->end()); + EXPECT_EQ(5, bar->begin()); + EXPECT_EQ(6, bar->end()); +} + +TEST(Printer, AnnotateRange) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("foo", "bar", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0); + ASSERT_EQ(1, foobar->path_size()); + EXPECT_EQ(33, foobar->path(0)); + EXPECT_EQ("path", foobar->source_file()); + EXPECT_EQ(3, foobar->begin()); + EXPECT_EQ(6, foobar->end()); +} + +TEST(Printer, AnnotateEmptyRange) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz", + "", "bam", ""); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("baz", "bam", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0); + ASSERT_EQ(1, bazbam->path_size()); + EXPECT_EQ(33, bazbam->path(0)); + EXPECT_EQ("path", bazbam->source_file()); + EXPECT_EQ(5, bazbam->begin()); + EXPECT_EQ(5, bazbam->end()); +} + +TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5"); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("bar", "bar", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("0123435\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* bar = &info.annotation(0); + ASSERT_EQ(1, bar->path_size()); + EXPECT_EQ(33, bar->path(0)); + EXPECT_EQ("path", bar->source_file()); + EXPECT_EQ(6, bar->begin()); + EXPECT_EQ(7, bar->end()); +} + TEST(Printer, Indenting) { char buffer[8192]; @@ -232,6 +423,52 @@ TEST(Printer, Death) { EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name"); EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent"); } + +TEST(Printer, AnnotateMultipleUsesDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$\n", "foo", "3"); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple"); + } +} + +TEST(Printer, AnnotateNegativeLengthDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative"); + } +} + +TEST(Printer, AnnotateUndefinedDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$\n", "foo", "3"); + vector<int> path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor), + "Undefined"); + } +} #endif // PROTOBUF_HAS_DEATH_TEST TEST(Printer, WriteFailurePartial) { diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 3d57707c..b3550dfb 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -881,9 +881,11 @@ bool Tokenizer::ParseInteger(const string& text, uint64 max_value, uint64 result = 0; for (; *ptr != '\0'; ptr++) { int digit = DigitValue(*ptr); - GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base) - << " Tokenizer::ParseInteger() passed text that could not have been" - " tokenized as an integer: " << CEscape(text); + if (digit < 0 || digit >= base) { + // The token provided by Tokenizer is invalid. i.e., 099 is an invalid + // token, but Tokenizer still think it's integer. + return false; + } if (digit > max_value || result > (max_value - digit) / base) { // Overflow. return false; diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 49885eda..64ee7d84 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -52,6 +52,12 @@ class ZeroCopyInputStream; // zero_copy_stream.h class ErrorCollector; class Tokenizer; +// By "column number", the proto compiler refers to a count of the number +// of bytes before a given byte, except that a tab character advances to +// the next multiple of 8 bytes. Note in particular that column numbers +// are zero-based, while many user interfaces use one-based column numbers. +typedef int ColumnNumber; + // Abstract interface for an object which collects the errors that occur // during parsing. A typical implementation might simply print the errors // to stdout. @@ -63,13 +69,14 @@ class LIBPROTOBUF_EXPORT ErrorCollector { // Indicates that there was an error in the input at the given line and // column numbers. The numbers are zero-based, so you may want to add // 1 to each before printing them. - virtual void AddError(int line, int column, const string& message) = 0; + virtual void AddError(int line, ColumnNumber column, + const string& message) = 0; // Indicates that there was a warning in the input at the given line and // column numbers. The numbers are zero-based, so you may want to add // 1 to each before printing them. - virtual void AddWarning(int /* line */, int /* column */, - const string& /* message */) { } + virtual void AddWarning(int line, ColumnNumber column, + const string& message) { } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); @@ -124,8 +131,8 @@ class LIBPROTOBUF_EXPORT Tokenizer { // "line" and "column" specify the position of the first character of // the token within the input stream. They are zero-based. int line; - int column; - int end_column; + ColumnNumber column; + ColumnNumber end_column; }; // Get the current token. This is updated when Next() is called. Before @@ -263,7 +270,7 @@ class LIBPROTOBUF_EXPORT Tokenizer { // Line and column number of current_char_ within the whole input stream. int line_; - int column_; + ColumnNumber column_; // String to which text should be appended as we advance through it. // Call RecordTo(&str) to start recording and StopRecording() to stop. @@ -280,6 +287,7 @@ class LIBPROTOBUF_EXPORT Tokenizer { // Since we count columns we need to interpret tabs somehow. We'll take // the standard 8-character definition for lack of any way to do better. + // This must match the documentation of ColumnNumber. static const int kTabWidth = 8; // ----------------------------------------------------------------- diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index 20d50a2c..ae0811f8 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -736,19 +736,13 @@ TEST_F(TokenizerTest, ParseInteger) { EXPECT_EQ(0, ParseInteger("0x")); uint64 i; -#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet + // Test invalid integers that will never be tokenized as integers. - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("1.2", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("08", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("0xg", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); -#endif // PROTOBUF_HAS_DEATH_TEST + EXPECT_FALSE(Tokenizer::ParseInteger("zxy", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("1.2", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("08", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("0xg", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("-1", kuint64max, &i)); // Test overflows. EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i)); diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 083beca4..e6ca88c2 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -69,7 +69,7 @@ ArrayInputStream::~ArrayInputStream() { bool ArrayInputStream::Next(const void** data, int* size) { if (position_ < size_) { - last_returned_size_ = min(block_size_, size_ - position_); + last_returned_size_ = std::min(block_size_, size_ - position_); *data = data_ + position_; *size = last_returned_size_; position_ += last_returned_size_; @@ -122,7 +122,7 @@ ArrayOutputStream::~ArrayOutputStream() { bool ArrayOutputStream::Next(void** data, int* size) { if (position_ < size_) { - last_returned_size_ = min(block_size_, size_ - position_); + last_returned_size_ = std::min(block_size_, size_ - position_); *data = data_ + position_; *size = last_returned_size_; position_ += last_returned_size_; @@ -157,7 +157,7 @@ StringOutputStream::~StringOutputStream() { } bool StringOutputStream::Next(void** data, int* size) { - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); int old_size = target_->size(); // Grow the string. @@ -177,9 +177,9 @@ bool StringOutputStream::Next(void** data, int* size) { // Double the size, also make sure that the new size is at least // kMinimumSize. STLStringResizeUninitialized( - target_, - max(old_size * 2, - kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. + target_, + std::max(old_size * 2, + kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. } *data = mutable_string_data(target_) + old_size; @@ -189,13 +189,13 @@ bool StringOutputStream::Next(void** data, int* size) { void StringOutputStream::BackUp(int count) { GOOGLE_CHECK_GE(count, 0); - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); GOOGLE_CHECK_LE(count, target_->size()); target_->resize(target_->size() - count); } int64 StringOutputStream::ByteCount() const { - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); return target_->size(); } @@ -235,8 +235,8 @@ int CopyingInputStream::Skip(int count) { char junk[4096]; int skipped = 0; while (skipped < count) { - int bytes = Read(junk, min(count - skipped, - implicit_cast<int>(sizeof(junk)))); + int bytes = + Read(junk, std::min(count - skipped, implicit_cast<int>(sizeof(junk)))); if (bytes <= 0) { // EOF or read error. return skipped; diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index 1c397dea..9d81ccfb 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -51,6 +51,7 @@ #include <string> #include <iosfwd> #include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/stl_util.h> @@ -174,7 +175,7 @@ class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream { int64 ByteCount() const; private: - const scoped_ptr<ResultCallback<string*> > callback_; + const google::protobuf::scoped_ptr<ResultCallback<string*> > callback_; bool string_is_set_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream); diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index 8c7358c1..a9db8872 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -63,8 +63,9 @@ #endif #include <sstream> -#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> #if HAVE_ZLIB #include <google/protobuf/io/gzip_stream.h> @@ -72,7 +73,6 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <google/protobuf/testing/file.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index d1948ab5..3ca3fbaf 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -686,6 +686,33 @@ int main(int argc, char* argv[]) { EXPECT_TRUE(map_message.IsInitialized()); } + { + // Check that adding more values to enum does not corrupt message + // when passed through an old client. + protobuf_unittest::V2MessageLite v2_message; + v2_message.set_int_field(800); + // Set enum field to the value not understood by the old client. + v2_message.set_enum_field(protobuf_unittest::V2_SECOND); + string v2_bytes = v2_message.SerializeAsString(); + + protobuf_unittest::V1MessageLite v1_message; + v1_message.ParseFromString(v2_bytes); + EXPECT_TRUE(v1_message.IsInitialized()); + EXPECT_EQ(v1_message.int_field(), v2_message.int_field()); + // V1 client does not understand V2_SECOND value, so it discards it and + // uses default value instead. + EXPECT_EQ(v1_message.enum_field(), protobuf_unittest::V1_FIRST); + + // However, when re-serialized, it should preserve enum value. + string v1_bytes = v1_message.SerializeAsString(); + + protobuf_unittest::V2MessageLite same_v2_message; + same_v2_message.ParseFromString(v1_bytes); + + EXPECT_EQ(v2_message.int_field(), same_v2_message.int_field()); + EXPECT_EQ(v2_message.enum_field(), same_v2_message.enum_field()); + } + std::cout << "PASS" << std::endl; return 0; } diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 37e19b0a..bb0b14f9 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -31,9 +31,11 @@ #ifndef GOOGLE_PROTOBUF_MAP_H__ #define GOOGLE_PROTOBUF_MAP_H__ -#include <iterator> #include <google/protobuf/stubs/hash.h> +#include <iterator> #include <limits> // To support Visual Studio 2008 +#include <set> +#include <utility> #include <google/protobuf/stubs/common.h> #include <google/protobuf/arena.h> @@ -41,17 +43,23 @@ #include <google/protobuf/map_type_handler.h> #include <google/protobuf/message.h> #include <google/protobuf/descriptor.h> +#if __cpp_exceptions && LANG_CXX11 +#include <random> +#endif namespace google { namespace protobuf { +// The Map and MapIterator types are provided by this header file. +// Please avoid using other types defined here, unless they are public +// types within Map or MapIterator, such as Map::value_type. template <typename Key, typename T> class Map; -template <typename Enum> struct is_proto_enum; - class MapIterator; +template <typename Enum> struct is_proto_enum; + namespace internal { template <typename Key, typename T, WireFormatLite::FieldType key_wire_type, @@ -73,15 +81,15 @@ class DynamicMapField; class GeneratedMessageReflection; } // namespace internal -#define TYPE_CHECK(EXPECTEDTYPE, METHOD) \ - if (type() != EXPECTEDTYPE) { \ - GOOGLE_LOG(FATAL) \ - << "Protocol Buffer map usage error:\n" \ - << METHOD << " type does not match\n" \ - << " Expected : " \ - << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n" \ - << " Actual : " \ - << FieldDescriptor::CppTypeName(type()); \ +#define TYPE_CHECK(EXPECTEDTYPE, METHOD) \ + if (type() != EXPECTEDTYPE) { \ + GOOGLE_LOG(FATAL) \ + << "Protocol Buffer map usage error:\n" \ + << METHOD << " type does not match\n" \ + << " Expected : " \ + << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n" \ + << " Actual : " \ + << FieldDescriptor::CppTypeName(type()); \ } // MapKey is an union type for representing any possible @@ -166,11 +174,47 @@ class LIBPROTOBUF_EXPORT MapKey { return *val_.string_value_; } + bool operator<(const MapKey& other) const { + if (type_ != other.type_) { + // We could define a total order that handles this case, but + // there currently no need. So, for now, fail. + GOOGLE_LOG(FATAL) << "Unsupported: type mismatch"; + } + switch (type()) { + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Unsupported"; + return false; + case FieldDescriptor::CPPTYPE_STRING: + return *val_.string_value_ < *other.val_.string_value_; + case FieldDescriptor::CPPTYPE_INT64: + return val_.int64_value_ < other.val_.int64_value_; + case FieldDescriptor::CPPTYPE_INT32: + return val_.int32_value_ < other.val_.int32_value_; + case FieldDescriptor::CPPTYPE_UINT64: + return val_.uint64_value_ < other.val_.uint64_value_; + case FieldDescriptor::CPPTYPE_UINT32: + return val_.uint32_value_ < other.val_.uint32_value_; + case FieldDescriptor::CPPTYPE_BOOL: + return val_.bool_value_ < other.val_.bool_value_; + } + return false; + } + bool operator==(const MapKey& other) const { if (type_ != other.type_) { - return false; + // To be consistent with operator<, we don't allow this either. + GOOGLE_LOG(FATAL) << "Unsupported: type mismatch"; } switch (type()) { + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Unsupported"; + break; case FieldDescriptor::CPPTYPE_STRING: return *val_.string_value_ == *other.val_.string_value_; case FieldDescriptor::CPPTYPE_INT64: @@ -183,11 +227,6 @@ class LIBPROTOBUF_EXPORT MapKey { return val_.uint32_value_ == other.val_.uint32_value_; case FieldDescriptor::CPPTYPE_BOOL: return val_.bool_value_ == other.val_.bool_value_; - case FieldDescriptor::CPPTYPE_DOUBLE: - case FieldDescriptor::CPPTYPE_FLOAT: - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; } GOOGLE_LOG(FATAL) << "Can't get here."; return false; @@ -196,6 +235,12 @@ class LIBPROTOBUF_EXPORT MapKey { void CopyFrom(const MapKey& other) { SetType(other.type()); switch (type_) { + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Unsupported"; + break; case FieldDescriptor::CPPTYPE_STRING: *val_.string_value_ = *other.val_.string_value_; break; @@ -214,12 +259,6 @@ class LIBPROTOBUF_EXPORT MapKey { case FieldDescriptor::CPPTYPE_BOOL: val_.bool_value_ = other.val_.bool_value_; break; - case FieldDescriptor::CPPTYPE_DOUBLE: - case FieldDescriptor::CPPTYPE_FLOAT: - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; - break; } } @@ -457,8 +496,17 @@ class MapPair { }; // google::protobuf::Map is an associative container type used to store protobuf map -// fields. Its interface is similar to std::unordered_map. Users should use this -// interface directly to visit or change map fields. +// fields. Each Map instance may or may not use a different hash function, a +// different iteration order, and so on. E.g., please don't examine +// implementation details to decide if the following would work: +// Map<int, int> m0, m1; +// m0[0] = m1[0] = m0[1] = m1[1] = 0; +// assert(m0.begin()->first == m1.begin()->first); // Bug! +// +// Map's interface is similar to std::unordered_map, except that Map is not +// designed to play well with exceptions. Mutations to a Map do not invalidate +// a Map's iterators, pointers to elements, or references to elements. Except +// for erase(iterator), any non-const method can reorder iterators. template <typename Key, typename T> class Map { public: @@ -473,40 +521,56 @@ class Map { typedef size_t size_type; typedef hash<Key> hasher; - typedef equal_to<Key> key_equal; - Map() + Map(bool old_style = true) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) {} - explicit Map(Arena* arena) + default_enum_value_(0), + old_style_(old_style) { + Init(); + } + explicit Map(Arena* arena, bool old_style = true) : arena_(arena), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) { - arena_->OwnDestructor(&elements_); + default_enum_value_(0), + old_style_(old_style) { + Init(); } - Map(const Map& other) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(other.default_enum_value_) { + default_enum_value_(other.default_enum_value_), + old_style_(other.old_style_) { + Init(); insert(other.begin(), other.end()); } template <class InputIt> - Map(const InputIt& first, const InputIt& last) + Map(const InputIt& first, const InputIt& last, bool old_style = true) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) { + default_enum_value_(0), + old_style_(old_style) { + Init(); insert(first, last); } - ~Map() { clear(); } + ~Map() { + clear(); + if (arena_ == NULL) { + if (old_style_) + delete deprecated_elements_; + else + delete elements_; + } + } private: + void Init() { + if (old_style_) + deprecated_elements_ = Arena::Create<DeprecatedInnerMap>( + arena_, 0, hasher(), equal_to<Key>(), + MapAllocator<std::pair<const Key, MapPair<Key, T>*> >(arena_)); + else + elements_ = + Arena::Create<InnerMap>(arena_, 0, hasher(), Allocator(arena_)); + } + // re-implement std::allocator to use arena allocator for memory allocation. // Used for google::protobuf::Map implementation. Users should not use this class // directly. @@ -545,14 +609,17 @@ class Map { } #if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ - !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) + !defined(GOOGLE_PROTOBUF_OS_NACL) && \ + !defined(GOOGLE_PROTOBUF_OS_ANDROID) && \ + !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) template<class NodeType, class... Args> void construct(NodeType* p, Args&&... args) { - // Clang 3.6 doesn't compile static casting to void* directly. (Issue #1266) - // According C++ standard 5.2.9/1: "The static_cast operator shall not cast - // away constness". So first the maybe const pointer is casted to const void* and - // after the const void* is const casted. - new (const_cast<void*>(static_cast<const void*>(p))) NodeType(std::forward<Args>(args)...); + // Clang 3.6 doesn't compile static casting to void* directly. (Issue + // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall + // not cast away constness". So first the maybe const pointer is casted to + // const void* and after the const void* is const casted. + new (const_cast<void*>(static_cast<const void*>(p))) + NodeType(std::forward<Args>(args)...); } template<class NodeType> @@ -593,86 +660,849 @@ class Map { friend class MapAllocator; }; - typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator; - typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> - InnerMap; + // InnerMap's key type is Key and its value type is value_type*. We use a + // custom class here and for Node, below, to ensure that k_ is at offset 0, + // allowing safe conversion from pointer to Node to pointer to Key, and vice + // versa when appropriate. + class KeyValuePair { + public: + KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {} + + const Key& key() const { return k_; } + Key& key() { return k_; } + value_type* const value() const { return v_; } + value_type*& value() { return v_; } + + private: + Key k_; + value_type* v_; + }; + + typedef MapAllocator<KeyValuePair> Allocator; + + // InnerMap is a generic hash-based map. It doesn't contain any + // protocol-buffer-specific logic. It is a chaining hash map with the + // additional feature that some buckets can be converted to use an ordered + // container. This ensures O(lg n) bounds on find, insert, and erase, while + // avoiding the overheads of ordered containers most of the time. + // + // The implementation doesn't need the full generality of unordered_map, + // and it doesn't have it. More bells and whistles can be added as needed. + // Some implementation details: + // 1. The hash function has type hasher and the equality function + // equal_to<Key>. We inherit from hasher to save space + // (empty-base-class optimization). + // 2. The number of buckets is a power of two. + // 3. Buckets are converted to trees in pairs: if we convert bucket b then + // buckets b and b^1 will share a tree. Invariant: buckets b and b^1 have + // the same non-NULL value iff they are sharing a tree. (An alternative + // implementation strategy would be to have a tag bit per bucket.) + // 4. As is typical for hash_map and such, the Keys and Values are always + // stored in linked list nodes. Pointers to elements are never invalidated + // until the element is deleted. + // 5. The trees' payload type is pointer to linked-list node. Tree-converting + // a bucket doesn't copy Key-Value pairs. + // 6. Once we've tree-converted a bucket, it is never converted back. However, + // the items a tree contains may wind up assigned to trees or lists upon a + // rehash. + // 7. The code requires no C++ features from C++11 or later. + // 8. Mutations to a map do not invalidate the map's iterators, pointers to + // elements, or references to elements. + // 9. Except for erase(iterator), any non-const method can reorder iterators. + class InnerMap : private hasher { + public: + typedef value_type* Value; + + InnerMap(size_type n, hasher h, Allocator alloc) + : hasher(h), + num_elements_(0), + seed_(Seed()), + table_(NULL), + alloc_(alloc) { + n = TableSize(n); + table_ = CreateEmptyTable(n); + num_buckets_ = index_of_first_non_null_ = n; + } + + ~InnerMap() { + if (table_ != NULL) { + clear(); + Dealloc<void*>(table_, num_buckets_); + } + } + + private: + enum { kMinTableSize = 8 }; + + // Linked-list nodes, as one would expect for a chaining hash table. + struct Node { + KeyValuePair kv; + Node* next; + }; + + // This is safe only if the given pointer is known to point to a Key that is + // part of a Node. + static Node* NodePtrFromKeyPtr(Key* k) { + return reinterpret_cast<Node*>(k); + } + + static Key* KeyPtrFromNodePtr(Node* node) { return &node->kv.key(); } + + // Trees. The payload type is pointer to Key, so that we can query the tree + // with Keys that are not in any particular data structure. When we insert, + // though, the pointer is always pointing to a Key that is inside a Node. + struct KeyCompare { + bool operator()(const Key* n0, const Key* n1) const { return *n0 < *n1; } + }; + typedef typename Allocator::template rebind<Key*>::other KeyPtrAllocator; + typedef std::set<Key*, KeyCompare, KeyPtrAllocator> Tree; + + // iterator and const_iterator are instantiations of iterator_base. + template <typename KeyValueType> + class iterator_base { + public: + typedef KeyValueType& reference; + typedef KeyValueType* pointer; + typedef typename Tree::iterator TreeIterator; + + // Invariants: + // node_ is always correct. This is handy because the most common + // operations are operator* and operator-> and they only use node_. + // When node_ is set to a non-NULL value, all the other non-const fields + // are updated to be correct also, but those fields can become stale + // if the underlying map is modified. When those fields are needed they + // are rechecked, and updated if necessary. + iterator_base() : node_(NULL) {} + + explicit iterator_base(const InnerMap* m) : m_(m) { + SearchFrom(m->index_of_first_non_null_); + } + + // Any iterator_base can convert to any other. This is overkill, and we + // rely on the enclosing class to use it wisely. The standard "iterator + // can convert to const_iterator" is OK but the reverse direction is not. + template <typename U> + explicit iterator_base(const iterator_base<U>& it) + : node_(it.node_), + m_(it.m_), + bucket_index_(it.bucket_index_), + tree_it_(it.tree_it_) {} + + iterator_base(Node* n, const InnerMap* m, size_type index) + : node_(n), + m_(m), + bucket_index_(index) {} + + iterator_base(TreeIterator tree_it, const InnerMap* m, size_type index) + : node_(NodePtrFromKeyPtr(*tree_it)), + m_(m), + bucket_index_(index), + tree_it_(tree_it) { + // Invariant: iterators that use tree_it_ have an even bucket_index_. + GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0); + } + + // Advance through buckets, looking for the first that isn't empty. + // If nothing non-empty is found then leave node_ == NULL. + void SearchFrom(size_type start_bucket) { + GOOGLE_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ || + m_->table_[m_->index_of_first_non_null_] != NULL); + node_ = NULL; + for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_; + bucket_index_++) { + if (m_->TableEntryIsNonEmptyList(bucket_index_)) { + node_ = static_cast<Node*>(m_->table_[bucket_index_]); + break; + } else if (m_->TableEntryIsTree(bucket_index_)) { + Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]); + GOOGLE_DCHECK(!tree->empty()); + tree_it_ = tree->begin(); + node_ = NodePtrFromKeyPtr(*tree_it_); + break; + } + } + } + + reference operator*() const { return node_->kv; } + pointer operator->() const { return &(operator*()); } + + friend bool operator==(const iterator_base& a, const iterator_base& b) { + return a.node_ == b.node_; + } + friend bool operator!=(const iterator_base& a, const iterator_base& b) { + return a.node_ != b.node_; + } + + iterator_base& operator++() { + if (node_->next == NULL) { + const bool is_list = revalidate_if_necessary(); + if (is_list) { + SearchFrom(bucket_index_ + 1); + } else { + GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0); + Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]); + if (++tree_it_ == tree->end()) { + SearchFrom(bucket_index_ + 2); + } else { + node_ = NodePtrFromKeyPtr(*tree_it_); + } + } + } else { + node_ = node_->next; + } + return *this; + } + + iterator_base operator++(int /* unused */) { + iterator_base tmp = *this; + ++*this; + return tmp; + } + + // Assumes node_ and m_ are correct and non-NULL, but other fields may be + // stale. Fix them as needed. Then return true iff node_ points to a + // Node in a list. + bool revalidate_if_necessary() { + GOOGLE_DCHECK(node_ != NULL && m_ != NULL); + // Force bucket_index_ to be in range. + bucket_index_ &= (m_->num_buckets_ - 1); + // Common case: the bucket we think is relevant points to node_. + if (m_->table_[bucket_index_] == static_cast<void*>(node_)) + return true; + // Less common: the bucket is a linked list with node_ somewhere in it, + // but not at the head. + if (m_->TableEntryIsNonEmptyList(bucket_index_)) { + Node* l = static_cast<Node*>(m_->table_[bucket_index_]); + while ((l = l->next) != NULL) { + if (l == node_) { + return true; + } + } + } + // Well, bucket_index_ still might be correct, but probably + // not. Revalidate just to be sure. This case is rare enough that we + // don't worry about potential optimizations, such as having a custom + // find-like method that compares Node* instead of const Key&. + iterator_base i(m_->find(*KeyPtrFromNodePtr(node_))); + bucket_index_ = i.bucket_index_; + tree_it_ = i.tree_it_; + return m_->TableEntryIsList(bucket_index_); + } + + Node* node_; + const InnerMap* m_; + size_type bucket_index_; + TreeIterator tree_it_; + }; + + public: + typedef iterator_base<KeyValuePair> iterator; + typedef iterator_base<const KeyValuePair> const_iterator; + + iterator begin() { return iterator(this); } + iterator end() { return iterator(); } + const_iterator begin() const { return const_iterator(this); } + const_iterator end() const { return const_iterator(); } + + void clear() { + for (size_type b = 0; b < num_buckets_; b++) { + if (TableEntryIsNonEmptyList(b)) { + Node* node = static_cast<Node*>(table_[b]); + table_[b] = NULL; + do { + Node* next = node->next; + DestroyNode(node); + node = next; + } while (node != NULL); + } else if (TableEntryIsTree(b)) { + Tree* tree = static_cast<Tree*>(table_[b]); + GOOGLE_DCHECK(table_[b] == table_[b + 1] && (b & 1) == 0); + table_[b] = table_[b + 1] = NULL; + typename Tree::iterator tree_it = tree->begin(); + do { + Node* node = NodePtrFromKeyPtr(*tree_it); + typename Tree::iterator next = tree_it; + ++next; + tree->erase(tree_it); + DestroyNode(node); + tree_it = next; + } while (tree_it != tree->end()); + DestroyTree(tree); + b++; + } + } + num_elements_ = 0; + index_of_first_non_null_ = num_buckets_; + } + + const hasher& hash_function() const { return *this; } + + static size_type max_size() { + return static_cast<size_type>(1) << (sizeof(void**) >= 8 ? 60 : 28); + } + size_type size() const { return num_elements_; } + bool empty() const { return size() == 0; } + + iterator find(const Key& k) { return iterator(FindHelper(k).first); } + const_iterator find(const Key& k) const { return FindHelper(k).first; } + + // In traditional C++ style, this performs "insert if not present." + std::pair<iterator, bool> insert(const KeyValuePair& kv) { + std::pair<const_iterator, size_type> p = FindHelper(kv.key()); + // Case 1: key was already present. + if (p.first.node_ != NULL) + return std::make_pair(iterator(p.first), false); + // Case 2: insert. + if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) { + p = FindHelper(kv.key()); + } + const size_type b = p.second; // bucket number + Node* node = Alloc<Node>(1); + alloc_.construct(&node->kv, kv); + iterator result = InsertUnique(b, node); + ++num_elements_; + return std::make_pair(result, true); + } + + // The same, but if an insertion is necessary then the value portion of the + // inserted key-value pair is left uninitialized. + std::pair<iterator, bool> insert(const Key& k) { + std::pair<const_iterator, size_type> p = FindHelper(k); + // Case 1: key was already present. + if (p.first.node_ != NULL) + return std::make_pair(iterator(p.first), false); + // Case 2: insert. + if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) { + p = FindHelper(k); + } + const size_type b = p.second; // bucket number + Node* node = Alloc<Node>(1); + typedef typename Allocator::template rebind<Key>::other KeyAllocator; + KeyAllocator(alloc_).construct(&node->kv.key(), k); + iterator result = InsertUnique(b, node); + ++num_elements_; + return std::make_pair(result, true); + } + + Value& operator[](const Key& k) { + KeyValuePair kv(k, Value()); + return insert(kv).first->value(); + } + + void erase(iterator it) { + GOOGLE_DCHECK_EQ(it.m_, this); + const bool is_list = it.revalidate_if_necessary(); + size_type b = it.bucket_index_; + Node* const item = it.node_; + if (is_list) { + GOOGLE_DCHECK(TableEntryIsNonEmptyList(b)); + Node* head = static_cast<Node*>(table_[b]); + head = EraseFromLinkedList(item, head); + table_[b] = static_cast<void*>(head); + } else { + GOOGLE_DCHECK(TableEntryIsTree(b)); + Tree* tree = static_cast<Tree*>(table_[b]); + tree->erase(it.tree_it_); + if (tree->empty()) { + // Force b to be the minimum of b and b ^ 1. This is important + // only because we want index_of_first_non_null_ to be correct. + b &= ~static_cast<size_type>(1); + DestroyTree(tree); + table_[b] = table_[b + 1] = NULL; + } + } + DestroyNode(item); + --num_elements_; + if (GOOGLE_PREDICT_FALSE(b == index_of_first_non_null_)) { + while (index_of_first_non_null_ < num_buckets_ && + table_[index_of_first_non_null_] == NULL) { + ++index_of_first_non_null_; + } + } + } + + private: + std::pair<const_iterator, size_type> FindHelper(const Key& k) const { + size_type b = BucketNumber(k); + if (TableEntryIsNonEmptyList(b)) { + Node* node = static_cast<Node*>(table_[b]); + do { + if (IsMatch(*KeyPtrFromNodePtr(node), k)) { + return std::make_pair(const_iterator(node, this, b), b); + } else { + node = node->next; + } + } while (node != NULL); + } else if (TableEntryIsTree(b)) { + GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]); + b &= ~static_cast<size_t>(1); + Tree* tree = static_cast<Tree*>(table_[b]); + Key* key = const_cast<Key*>(&k); + typename Tree::iterator tree_it = tree->find(key); + if (tree_it != tree->end()) { + return std::make_pair(const_iterator(tree_it, this, b), b); + } + } + return std::make_pair(end(), b); + } + + // Insert the given Node in bucket b. If that would make bucket b too big, + // and bucket b is not a tree, create a tree for buckets b and b^1 to share. + // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct + // bucket. num_elements_ is not modified. + iterator InsertUnique(size_type b, Node* node) { + GOOGLE_DCHECK(index_of_first_non_null_ == num_buckets_ || + table_[index_of_first_non_null_] != NULL); + // In practice, the code that led to this point may have already + // determined whether we are inserting into an empty list, a short list, + // or whatever. But it's probably cheap enough to recompute that here; + // it's likely that we're inserting into an empty or short list. + iterator result; + GOOGLE_DCHECK(find(*KeyPtrFromNodePtr(node)) == end()); + if (TableEntryIsEmpty(b)) { + result = InsertUniqueInList(b, node); + } else if (TableEntryIsNonEmptyList(b)) { + if (GOOGLE_PREDICT_FALSE(TableEntryIsTooLong(b))) { + TreeConvert(b); + result = InsertUniqueInTree(b, node); + GOOGLE_DCHECK_EQ(result.bucket_index_, b & ~static_cast<size_type>(1)); + } else { + // Insert into a pre-existing list. This case cannot modify + // index_of_first_non_null_, so we skip the code to update it. + return InsertUniqueInList(b, node); + } + } else { + // Insert into a pre-existing tree. This case cannot modify + // index_of_first_non_null_, so we skip the code to update it. + return InsertUniqueInTree(b, node); + } + index_of_first_non_null_ = + std::min(index_of_first_non_null_, result.bucket_index_); + return result; + } + + // Helper for InsertUnique. Handles the case where bucket b is a + // not-too-long linked list. + iterator InsertUniqueInList(size_type b, Node* node) { + node->next = static_cast<Node*>(table_[b]); + table_[b] = static_cast<void*>(node); + return iterator(node, this, b); + } + + // Helper for InsertUnique. Handles the case where bucket b points to a + // Tree. + iterator InsertUniqueInTree(size_type b, Node* node) { + GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]); + // Maintain the invariant that node->next is NULL for all Nodes in Trees. + node->next = NULL; + return iterator(static_cast<Tree*>(table_[b]) + ->insert(KeyPtrFromNodePtr(node)) + .first, + this, b & ~static_cast<size_t>(1)); + } + + // Returns whether it did resize. Currently this is only used when + // num_elements_ increases, though it could be used in other situations. + // It checks for load too low as well as load too high: because any number + // of erases can occur between inserts, the load could be as low as 0 here. + // Resizing to a lower size is not always helpful, but failing to do so can + // destroy the expected big-O bounds for some operations. By having the + // policy that sometimes we resize down as well as up, clients can easily + // keep O(size()) = O(number of buckets) if they want that. + bool ResizeIfLoadIsOutOfRange(size_type new_size) { + const size_type kMaxMapLoadTimes16 = 12; // controls RAM vs CPU tradeoff + const size_type hi_cutoff = num_buckets_ * kMaxMapLoadTimes16 / 16; + const size_type lo_cutoff = hi_cutoff / 4; + // We don't care how many elements are in trees. If a lot are, + // we may resize even though there are many empty buckets. In + // practice, this seems fine. + if (GOOGLE_PREDICT_FALSE(new_size >= hi_cutoff)) { + if (num_buckets_ <= max_size() / 2) { + Resize(num_buckets_ * 2); + return true; + } + } else if (GOOGLE_PREDICT_FALSE(new_size <= lo_cutoff && + num_buckets_ > kMinTableSize)) { + size_type lg2_of_size_reduction_factor = 1; + // It's possible we want to shrink a lot here... size() could even be 0. + // So, estimate how much to shrink by making sure we don't shrink so + // much that we would need to grow the table after a few inserts. + const size_type hypothetical_size = new_size * 5 / 4 + 1; + while ((hypothetical_size << lg2_of_size_reduction_factor) < + hi_cutoff) { + ++lg2_of_size_reduction_factor; + } + size_type new_num_buckets = std::max<size_type>( + kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor); + if (new_num_buckets != num_buckets_) { + Resize(new_num_buckets); + return true; + } + } + return false; + } + + // Resize to the given number of buckets. + void Resize(size_t new_num_buckets) { + GOOGLE_DCHECK_GE(new_num_buckets, kMinTableSize); + void** const old_table = table_; + const size_type old_table_size = num_buckets_; + num_buckets_ = new_num_buckets; + table_ = CreateEmptyTable(num_buckets_); + const size_type start = index_of_first_non_null_; + index_of_first_non_null_ = num_buckets_; + for (size_type i = start; i < old_table_size; i++) { + if (TableEntryIsNonEmptyList(old_table, i)) { + TransferList(old_table, i); + } else if (TableEntryIsTree(old_table, i)) { + TransferTree(old_table, i++); + } + } + Dealloc<void*>(old_table, old_table_size); + } + + void TransferList(void* const* table, size_type index) { + Node* node = static_cast<Node*>(table[index]); + do { + Node* next = node->next; + InsertUnique(BucketNumber(*KeyPtrFromNodePtr(node)), node); + node = next; + } while (node != NULL); + } + + void TransferTree(void* const* table, size_type index) { + Tree* tree = static_cast<Tree*>(table[index]); + typename Tree::iterator tree_it = tree->begin(); + do { + Node* node = NodePtrFromKeyPtr(*tree_it); + InsertUnique(BucketNumber(**tree_it), node); + } while (++tree_it != tree->end()); + DestroyTree(tree); + } + + Node* EraseFromLinkedList(Node* item, Node* head) { + if (head == item) { + return head->next; + } else { + head->next = EraseFromLinkedList(item, head->next); + return head; + } + } + + bool TableEntryIsEmpty(size_type b) const { + return TableEntryIsEmpty(table_, b); + } + bool TableEntryIsNonEmptyList(size_type b) const { + return TableEntryIsNonEmptyList(table_, b); + } + bool TableEntryIsTree(size_type b) const { + return TableEntryIsTree(table_, b); + } + bool TableEntryIsList(size_type b) const { + return TableEntryIsList(table_, b); + } + static bool TableEntryIsEmpty(void* const* table, size_type b) { + return table[b] == NULL; + } + static bool TableEntryIsNonEmptyList(void* const* table, size_type b) { + return table[b] != NULL && table[b] != table[b ^ 1]; + } + static bool TableEntryIsTree(void* const* table, size_type b) { + return !TableEntryIsEmpty(table, b) && + !TableEntryIsNonEmptyList(table, b); + } + static bool TableEntryIsList(void* const* table, size_type b) { + return !TableEntryIsTree(table, b); + } + + void TreeConvert(size_type b) { + GOOGLE_DCHECK(!TableEntryIsTree(b) && !TableEntryIsTree(b ^ 1)); + typename Allocator::template rebind<Tree>::other tree_allocator(alloc_); + Tree* tree = tree_allocator.allocate(1); + // We want to use the three-arg form of construct, if it exists, but we + // create a temporary and use the two-arg construct that's known to exist. + // It's clunky, but the compiler should be able to generate more-or-less + // the same code. + tree_allocator.construct(tree, + Tree(KeyCompare(), KeyPtrAllocator(alloc_))); + // Now the tree is ready to use. + size_type count = CopyListToTree(b, tree) + CopyListToTree(b ^ 1, tree); + GOOGLE_DCHECK_EQ(count, tree->size()); + table_[b] = table_[b ^ 1] = static_cast<void*>(tree); + } + + // Copy a linked list in the given bucket to a tree. + // Returns the number of things it copied. + size_type CopyListToTree(size_type b, Tree* tree) { + size_type count = 0; + Node* node = static_cast<Node*>(table_[b]); + while (node != NULL) { + tree->insert(KeyPtrFromNodePtr(node)); + ++count; + Node* next = node->next; + node->next = NULL; + node = next; + } + return count; + } + + // Return whether table_[b] is a linked list that seems awfully long. + // Requires table_[b] to point to a non-empty linked list. + bool TableEntryIsTooLong(size_type b) { + const int kMaxLength = 8; + size_type count = 0; + Node* node = static_cast<Node*>(table_[b]); + do { + ++count; + node = node->next; + } while (node != NULL); + // Invariant: no linked list ever is more than kMaxLength in length. + GOOGLE_DCHECK_LE(count, kMaxLength); + return count >= kMaxLength; + } + + size_type BucketNumber(const Key& k) const { + // We inherit from hasher, so one-arg operator() provides a hash function. + size_type h = (*const_cast<InnerMap*>(this))(k); + // To help prevent people from making assumptions about the hash function, + // we use the seed differently depending on NDEBUG. The default hash + // function, the seeding, etc., are all likely to change in the future. +#ifndef NDEBUG + return (h * (seed_ | 1)) & (num_buckets_ - 1); +#else + return (h + seed_) & (num_buckets_ - 1); +#endif + } + + bool IsMatch(const Key& k0, const Key& k1) const { + return std::equal_to<Key>()(k0, k1); + } + + // Return a power of two no less than max(kMinTableSize, n). + // Assumes either n < kMinTableSize or n is a power of two. + size_type TableSize(size_type n) { + return n < kMinTableSize ? kMinTableSize : n; + } + + // Use alloc_ to allocate an array of n objects of type U. + template <typename U> + U* Alloc(size_type n) { + typedef typename Allocator::template rebind<U>::other alloc_type; + return alloc_type(alloc_).allocate(n); + } + + // Use alloc_ to deallocate an array of n objects of type U. + template <typename U> + void Dealloc(U* t, size_type n) { + typedef typename Allocator::template rebind<U>::other alloc_type; + alloc_type(alloc_).deallocate(t, n); + } + + void DestroyNode(Node* node) { + alloc_.destroy(&node->kv); + Dealloc<Node>(node, 1); + } + + void DestroyTree(Tree* tree) { + typename Allocator::template rebind<Tree>::other tree_allocator(alloc_); + tree_allocator.destroy(tree); + tree_allocator.deallocate(tree, 1); + } + + void** CreateEmptyTable(size_type n) { + GOOGLE_DCHECK(n >= kMinTableSize); + GOOGLE_DCHECK_EQ(n & (n - 1), 0); + void** result = Alloc<void*>(n); + memset(result, 0, n * sizeof(result[0])); + return result; + } + + // Return a randomish value. + size_type Seed() const { + // random_device can throw, so avoid it unless we are compiling with + // exceptions enabled. +#if __cpp_exceptions && LANG_CXX11 + try { + std::random_device rd; + std::knuth_b knuth(rd()); + std::uniform_int_distribution<size_type> u; + return u(knuth); + } catch (...) { } +#endif + size_type s = static_cast<size_type>(reinterpret_cast<uintptr_t>(this)); +#if defined(__x86_64__) && defined(__GNUC__) + uint32 hi, lo; + asm("rdtsc" : "=a" (lo), "=d" (hi)); + s += ((static_cast<uint64>(hi) << 32) | lo); +#endif + return s; + } + + size_type num_elements_; + size_type num_buckets_; + size_type seed_; + size_type index_of_first_non_null_; + void** table_; // an array with num_buckets_ entries + Allocator alloc_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap); + }; // end of class InnerMap + + typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, + MapAllocator<std::pair<const Key, MapPair<Key, T>*> > > + DeprecatedInnerMap; public: // Iterators + class iterator_base { + public: + // We support "old style" and "new style" iterators for now. This is + // temporary. Also, for "iterator()" we have an unknown category. + // TODO(gpike): get rid of this. + enum IteratorStyle { kUnknown, kOld, kNew }; + explicit iterator_base(IteratorStyle style) : iterator_style_(style) {} + + bool OldStyle() const { + GOOGLE_DCHECK_NE(iterator_style_, kUnknown); + return iterator_style_ == kOld; + } + bool UnknownStyle() const { + return iterator_style_ == kUnknown; + } + bool SameStyle(const iterator_base& other) const { + return iterator_style_ == other.iterator_style_; + } + + private: + IteratorStyle iterator_style_; + }; + class const_iterator - : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t, + : private iterator_base, + public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t, const value_type*, const value_type&> { typedef typename InnerMap::const_iterator InnerIt; + typedef typename DeprecatedInnerMap::const_iterator DeprecatedInnerIt; public: - const_iterator() {} - explicit const_iterator(const InnerIt& it) : it_(it) {} + const_iterator() : iterator_base(iterator_base::kUnknown) {} + explicit const_iterator(const DeprecatedInnerIt& dit) + : iterator_base(iterator_base::kOld), dit_(dit) {} + explicit const_iterator(const InnerIt& it) + : iterator_base(iterator_base::kNew), it_(it) {} - const_reference operator*() const { return *it_->second; } - const_pointer operator->() const { return it_->second; } + const_iterator(const const_iterator& other) + : iterator_base(other), it_(other.it_), dit_(other.dit_) {} + + const_reference operator*() const { + return this->OldStyle() ? *dit_->second : *it_->value(); + } + const_pointer operator->() const { return &(operator*()); } const_iterator& operator++() { - ++it_; + if (this->OldStyle()) + ++dit_; + else + ++it_; return *this; } - const_iterator operator++(int) { return const_iterator(it_++); } + const_iterator operator++(int) { + return this->OldStyle() ? const_iterator(dit_++) : const_iterator(it_++); + } friend bool operator==(const const_iterator& a, const const_iterator& b) { - return a.it_ == b.it_; + if (!a.SameStyle(b)) return false; + if (a.UnknownStyle()) return true; + return a.OldStyle() ? (a.dit_ == b.dit_) : (a.it_ == b.it_); } friend bool operator!=(const const_iterator& a, const const_iterator& b) { - return a.it_ != b.it_; + return !(a == b); } private: InnerIt it_; + DeprecatedInnerIt dit_; }; - class iterator : public std::iterator<std::forward_iterator_tag, value_type> { + class iterator : private iterator_base, + public std::iterator<std::forward_iterator_tag, value_type> { typedef typename InnerMap::iterator InnerIt; + typedef typename DeprecatedInnerMap::iterator DeprecatedInnerIt; public: - iterator() {} - explicit iterator(const InnerIt& it) : it_(it) {} - - reference operator*() const { return *it_->second; } - pointer operator->() const { return it_->second; } + iterator() : iterator_base(iterator_base::kUnknown) {} + explicit iterator(const DeprecatedInnerIt& dit) + : iterator_base(iterator_base::kOld), dit_(dit) {} + explicit iterator(const InnerIt& it) + : iterator_base(iterator_base::kNew), it_(it) {} + + reference operator*() const { + return this->OldStyle() ? *dit_->second : *it_->value(); + } + pointer operator->() const { return &(operator*()); } iterator& operator++() { - ++it_; + if (this->OldStyle()) + ++dit_; + else + ++it_; return *this; } - iterator operator++(int) { return iterator(it_++); } + iterator operator++(int) { + return this->OldStyle() ? iterator(dit_++) : iterator(it_++); + } - // Implicitly convertible to const_iterator. - operator const_iterator() const { return const_iterator(it_); } + // Allow implicit conversion to const_iterator. + operator const_iterator() const { + return this->OldStyle() ? + const_iterator(typename DeprecatedInnerMap::const_iterator(dit_)) : + const_iterator(typename InnerMap::const_iterator(it_)); + } friend bool operator==(const iterator& a, const iterator& b) { - return a.it_ == b.it_; + if (!a.SameStyle(b)) return false; + if (a.UnknownStyle()) return true; + return a.OldStyle() ? a.dit_ == b.dit_ : a.it_ == b.it_; } friend bool operator!=(const iterator& a, const iterator& b) { - return a.it_ != b.it_; + return !(a == b); } private: friend class Map; + InnerIt it_; + DeprecatedInnerIt dit_; }; - iterator begin() { return iterator(elements_.begin()); } - iterator end() { return iterator(elements_.end()); } - const_iterator begin() const { return const_iterator(elements_.begin()); } - const_iterator end() const { return const_iterator(elements_.end()); } + iterator begin() { + return old_style_ ? iterator(deprecated_elements_->begin()) + : iterator(elements_->begin()); + } + iterator end() { + return old_style_ ? iterator(deprecated_elements_->end()) + : iterator(elements_->end()); + } + const_iterator begin() const { + return old_style_ ? const_iterator(deprecated_elements_->begin()) + : const_iterator(iterator(elements_->begin())); + } + const_iterator end() const { + return old_style_ ? const_iterator(deprecated_elements_->end()) + : const_iterator(iterator(elements_->end())); + } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } // Capacity - size_type size() const { return elements_.size(); } - bool empty() const { return elements_.empty(); } + size_type size() const { + return old_style_ ? deprecated_elements_->size() : elements_->size(); + } + bool empty() const { return size() == 0; } // Element access T& operator[](const key_type& key) { - value_type** value = &elements_[key]; + value_type** value = + old_style_ ? &(*deprecated_elements_)[key] : &(*elements_)[key]; if (*value == NULL) { *value = CreateValueTypeInternal(key); internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value, @@ -694,13 +1524,16 @@ class Map { // Lookup size_type count(const key_type& key) const { - return elements_.count(key); + if (find(key) != end()) assert(key == find(key)->first); + return find(key) == end() ? 0 : 1; } const_iterator find(const key_type& key) const { - return const_iterator(elements_.find(key)); + return old_style_ ? const_iterator(deprecated_elements_->find(key)) + : const_iterator(iterator(elements_->find(key))); } iterator find(const key_type& key) { - return iterator(elements_.find(key)); + return old_style_ ? iterator(deprecated_elements_->find(key)) + : iterator(elements_->find(key)); } std::pair<const_iterator, const_iterator> equal_range( const key_type& key) const { @@ -724,13 +1557,22 @@ class Map { // insert std::pair<iterator, bool> insert(const value_type& value) { - iterator it = find(value.first); - if (it != end()) { - return std::pair<iterator, bool>(it, false); + if (old_style_) { + iterator it = find(value.first); + if (it != end()) { + return std::pair<iterator, bool>(it, false); + } else { + return std::pair<iterator, bool>( + iterator(deprecated_elements_->insert(std::pair<Key, value_type*>( + value.first, CreateValueTypeInternal(value))).first), true); + } } else { - return std::pair<iterator, bool>( - iterator(elements_.insert(std::pair<Key, value_type*>( - value.first, CreateValueTypeInternal(value))).first), true); + std::pair<typename InnerMap::iterator, bool> p = + elements_->insert(value.first); + if (p.second) { + p.first->value() = CreateValueTypeInternal(value); + } + return std::pair<iterator, bool>(iterator(p.first), p.second); } } template <class InputIt> @@ -743,33 +1585,31 @@ class Map { } } - // Erase + // Erase and clear size_type erase(const key_type& key) { - typename InnerMap::iterator it = elements_.find(key); - if (it == elements_.end()) { + iterator it = find(key); + if (it == end()) { return 0; } else { - if (arena_ == NULL) delete it->second; - elements_.erase(it); + erase(it); return 1; } } - void erase(iterator pos) { - if (arena_ == NULL) delete pos.it_->second; - elements_.erase(pos.it_); + iterator erase(iterator pos) { + if (arena_ == NULL) delete pos.operator->(); + iterator i = pos++; + if (old_style_) + deprecated_elements_->erase(i.dit_); + else + elements_->erase(i.it_); + return pos; } void erase(iterator first, iterator last) { - for (iterator it = first; it != last;) { - if (arena_ == NULL) delete it.it_->second; - elements_.erase((it++).it_); + while (first != last) { + first = erase(first); } } - void clear() { - for (iterator it = begin(); it != end(); ++it) { - if (arena_ == NULL) delete it.it_->second; - } - elements_.clear(); - } + void clear() { erase(begin(), end()); } // Assign Map& operator=(const Map& other) { @@ -780,6 +1620,13 @@ class Map { return *this; } + // Access to hasher. Currently this returns a copy, but it may + // be modified to return a const reference in the future. + hasher hash_function() const { + return old_style_ ? deprecated_elements_->hash_function() + : elements_->hash_function(); + } + private: // Set default enum value only for proto2 map field whose value is enum type. void SetDefaultEnumValue(int default_enum_value) { @@ -814,9 +1661,15 @@ class Map { } Arena* arena_; - Allocator allocator_; - InnerMap elements_; int default_enum_value_; + // The following is a tagged union because we support two map styles + // for now. + // TODO(gpike): get rid of the old style. + const bool old_style_; + union { + InnerMap* elements_; + DeprecatedInnerMap* deprecated_elements_; + }; friend class ::google::protobuf::Arena; typedef void InternalArenaConstructable_; @@ -837,6 +1690,12 @@ struct hash<google::protobuf::MapKey> { size_t operator()(const google::protobuf::MapKey& map_key) const { switch (map_key.type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Unsupported"; + break; case google::protobuf::FieldDescriptor::CPPTYPE_STRING: return hash<string>()(map_key.GetStringValue()); case google::protobuf::FieldDescriptor::CPPTYPE_INT64: @@ -849,11 +1708,6 @@ struct hash<google::protobuf::MapKey> { return hash< ::google::protobuf::uint32>()(map_key.GetUInt32Value()); case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: return hash<bool>()(map_key.GetBoolValue()); - case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: - case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: - case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: - case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; } GOOGLE_LOG(FATAL) << "Can't get here."; return 0; @@ -861,26 +1715,7 @@ struct hash<google::protobuf::MapKey> { bool operator()(const google::protobuf::MapKey& map_key1, const google::protobuf::MapKey& map_key2) const { - switch (map_key1.type()) { -#define COMPARE_CPPTYPE(CPPTYPE, CPPTYPE_METHOD) \ - case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \ - return map_key1.Get##CPPTYPE_METHOD##Value() < \ - map_key2.Get##CPPTYPE_METHOD##Value(); - COMPARE_CPPTYPE(STRING, String) - COMPARE_CPPTYPE(INT64, Int64) - COMPARE_CPPTYPE(INT32, Int32) - COMPARE_CPPTYPE(UINT64, UInt64) - COMPARE_CPPTYPE(UINT32, UInt32) - COMPARE_CPPTYPE(BOOL, Bool) -#undef COMPARE_CPPTYPE - case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: - case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: - case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: - case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return true; + return map_key1 < map_key2; } }; GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index eddc95c4..49f91818 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -178,18 +178,19 @@ bool DynamicMapField::ContainsMapKey( return iter != map.end(); } -bool DynamicMapField::InsertMapValue( +bool DynamicMapField::InsertOrLookupMapValue( const MapKey& map_key, MapValueRef* val) { - bool result = false; - - MapValueRef& map_val = (*MutableMap())[map_key]; - // If map_val.data_ is not set, it is newly inserted by map_[map_key]. - if (map_val.data_ == NULL) { - result = true; + // Always use mutable map because users may change the map value by + // MapValueRef. + Map<MapKey, MapValueRef>* map = MutableMap(); + Map<MapKey, MapValueRef>::iterator iter = map->find(map_key); + if (iter == map->end()) { + // Insert + MapValueRef& map_val = (*map)[map_key]; const FieldDescriptor* val_des = default_entry_->GetDescriptor()->FindFieldByName("value"); map_val.SetType(val_des->cpp_type()); - // Allocate momery for the inserted MapValueRef, and initialize to + // Allocate memory for the inserted MapValueRef, and initialize to // default value. switch (val_des->cpp_type()) { #define HANDLE_TYPE(CPPTYPE, TYPE) \ @@ -216,9 +217,13 @@ bool DynamicMapField::InsertMapValue( break; } } + val->CopyFrom(map_val); + return true; } - val->CopyFrom(map_val); - return result; + // map_key is already in the map. Make sure (*map)[map_key] is not called. + // [] may reorder the map and iterators. + val->CopyFrom(iter->second); + return false; } bool DynamicMapField::DeleteMapValue(const MapKey& map_key) { diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 9130166b..4b46f3aa 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -87,7 +87,8 @@ class LIBPROTOBUF_EXPORT MapFieldBase { // Pure virtual map APIs for Map Reflection. virtual bool ContainsMapKey(const MapKey& map_key) const = 0; - virtual bool InsertMapValue(const MapKey& map_key, MapValueRef* val) = 0; + virtual bool InsertOrLookupMapValue( + const MapKey& map_key, MapValueRef* val) = 0; virtual bool DeleteMapValue(const MapKey& map_key) = 0; virtual bool EqualIterator(const MapIterator& a, const MapIterator& b) const = 0; @@ -251,7 +252,7 @@ class MapField : public TypeDefinedMapFieldBase<Key, T>, // Implement MapFieldBase bool ContainsMapKey(const MapKey& map_key) const; - bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val); bool DeleteMapValue(const MapKey& map_key); // Accessors @@ -302,7 +303,7 @@ class LIBPROTOBUF_EXPORT DynamicMapField: public TypeDefinedMapFieldBase<MapKey, // Implement MapFieldBase bool ContainsMapKey(const MapKey& map_key) const; - bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val); bool DeleteMapValue(const MapKey& map_key); const Map<MapKey, MapValueRef>& GetMap() const; diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index f116697c..01c9b89a 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -262,16 +262,22 @@ template <typename Key, typename T, WireFormatLite::FieldType kValueFieldType, int default_enum_value> bool MapField<Key, T, kKeyFieldType, kValueFieldType, - default_enum_value>::InsertMapValue(const MapKey& map_key, - MapValueRef* val) { + default_enum_value>::InsertOrLookupMapValue( + const MapKey& map_key, + MapValueRef* val) { + // Always use mutable map because users may change the map value by + // MapValueRef. Map<Key, T>* map = MutableMap(); - bool result = false; const Key& key = UnwrapMapKey<Key>(map_key); - if (map->end() == map->find(key)) { - result = true; + typename Map<Key, T>::iterator iter = map->find(key); + if (map->end() == iter) { + val->SetValue(&((*map)[key])); + return true; } - val->SetValue(&((*map)[key])); - return result; + // Key is already in the map. Make sure (*map)[key] is not called. + // [] may reorder the map and iterators. + val->SetValue(&(iter->second)); + return false; } template <typename Key, typename T, diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index 2ff1d6bb..223d42f3 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc @@ -78,7 +78,7 @@ class MapFieldBaseStub : public MapFieldBase { bool ContainsMapKey(const MapKey& map_key) const { return false; } - bool InsertMapValue(const MapKey& map_key, MapValueRef* val) { + bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) { return false; } bool DeleteMapValue(const MapKey& map_key) { diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 451b02e8..9d4d6c13 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -28,12 +28,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// A hack to include windows.h first, which ensures the GetMessage macro can +// be undefined when we include <google/protobuf/stubs/common.h> +#if defined(_WIN32) +#define _WINSOCKAPI_ // to avoid re-definition in WinSock2.h +#define NOMINMAX // to avoid defining min/max macros +#include <windows.h> +#endif // _WIN32 + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> #include <map> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <set> #include <sstream> +#include <vector> #include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/logging.h> @@ -62,6 +74,7 @@ #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/util/time_util.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> @@ -79,10 +92,11 @@ namespace internal { // Map API Test ===================================================== -class MapImplTest : public ::testing::Test { +// Parameterized tests on whether to use old style maps. +class MapImplTest : public testing::TestWithParam<bool> { protected: MapImplTest() - : map_ptr_(new Map<int32, int32>), + : map_ptr_(new Map<int32, int32>(GetParam())), map_(*map_ptr_), const_map_(*map_ptr_) { EXPECT_TRUE(map_.empty()); @@ -159,7 +173,7 @@ class MapImplTest : public ::testing::Test { const Map<int32, int32>& const_map_; }; -TEST_F(MapImplTest, OperatorBracket) { +TEST_P(MapImplTest, OperatorBracket) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -173,7 +187,7 @@ TEST_F(MapImplTest, OperatorBracket) { ExpectSingleElement(key, value2); } -TEST_F(MapImplTest, OperatorBracketNonExist) { +TEST_P(MapImplTest, OperatorBracketNonExist) { int32 key = 0; int32 default_value = 0; @@ -181,7 +195,7 @@ TEST_F(MapImplTest, OperatorBracketNonExist) { ExpectSingleElement(key, default_value); } -TEST_F(MapImplTest, MutableAt) { +TEST_P(MapImplTest, MutableAt) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -195,15 +209,15 @@ TEST_F(MapImplTest, MutableAt) { #ifdef PROTOBUF_HAS_DEATH_TEST -TEST_F(MapImplTest, MutableAtNonExistDeathTest) { +TEST_P(MapImplTest, MutableAtNonExistDeathTest) { EXPECT_DEATH(map_.at(0), ""); } -TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) { +TEST_P(MapImplTest, ImmutableAtNonExistDeathTest) { EXPECT_DEATH(const_map_.at(0), ""); } -TEST_F(MapImplTest, UsageErrors) { +TEST_P(MapImplTest, UsageErrors) { MapKey key; key.SetInt64Value(1); EXPECT_DEATH(key.GetUInt64Value(), @@ -220,23 +234,23 @@ TEST_F(MapImplTest, UsageErrors) { #endif // PROTOBUF_HAS_DEATH_TEST -TEST_F(MapImplTest, CountNonExist) { +TEST_P(MapImplTest, CountNonExist) { EXPECT_EQ(0, map_.count(0)); } -TEST_F(MapImplTest, MutableFindNonExist) { +TEST_P(MapImplTest, MutableFindNonExist) { EXPECT_TRUE(map_.end() == map_.find(0)); } -TEST_F(MapImplTest, ImmutableFindNonExist) { +TEST_P(MapImplTest, ImmutableFindNonExist) { EXPECT_TRUE(const_map_.end() == const_map_.find(0)); } -TEST_F(MapImplTest, ConstEnd) { +TEST_P(MapImplTest, ConstEnd) { EXPECT_TRUE(const_map_.end() == const_map_.cend()); } -TEST_F(MapImplTest, GetReferenceFromIterator) { +TEST_P(MapImplTest, GetReferenceFromIterator) { for (int i = 0; i < 10; i++) { map_[i] = i; } @@ -259,7 +273,7 @@ TEST_F(MapImplTest, GetReferenceFromIterator) { } } -TEST_F(MapImplTest, IteratorBasic) { +TEST_P(MapImplTest, IteratorBasic) { map_[0] = 0; // Default constructible (per forward iterator requirements). @@ -281,6 +295,292 @@ TEST_F(MapImplTest, IteratorBasic) { EXPECT_TRUE(it == cit); } +template <typename Iterator> +static int64 median(Iterator i0, Iterator i1) { + vector<int64> v(i0, i1); + std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end()); + return v[v.size() / 2]; +} + +static int64 Now() { + return google::protobuf::util::TimeUtil::TimestampToNanoseconds( + google::protobuf::util::TimeUtil::GetCurrentTime()); +} + +// Arbitrary odd integers for creating test data. +static int k0 = 812398771; +static int k1 = 1312938717; +static int k2 = 1321555333; + +// A naive begin() implementation will cause begin() to get slower and slower +// if one erases elements at the "front" of the hash map, and we'd like to +// avoid that, as std::unordered_map does. +TEST_P(MapImplTest, BeginIsFast) { + // Disable this test for both new and old implementations. + if (/*GetParam()*/true) return; + Map<int32, int32> map(false); // This test uses new-style maps only. + const int kTestSize = 250000; + // Create a random-looking map of size n. Use non-negative integer keys. + uint32 frog = 123983; + int last_key = 0; + int counter = 0; + while (map.size() < kTestSize) { + frog *= static_cast<uint32>(k0); + frog ^= frog >> 17; + frog += counter++; + last_key = + static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1; + GOOGLE_DCHECK_GE(last_key, 0); + map[last_key] = last_key ^ 1; + } + vector<int64> times; + // We're going to do map.erase(map.begin()) over and over again. But, + // just in case one iteration is fast compared to the granularity of + // our time keeping, we measure kChunkSize iterations per outer-loop iter. + const int kChunkSize = 1000; + GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0); + do { + const int64 start = Now(); + for (int i = 0; i < kChunkSize; i++) { + map.erase(map.begin()); + } + const int64 end = Now(); + if (end > start) { + times.push_back(end - start); + } + } while (!map.empty()); + if (times.size() < .99 * kTestSize / kChunkSize) { + GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time"; + return; + } + int64 x0 = median(times.begin(), times.begin() + 9); + int64 x1 = median(times.begin() + times.size() - 9, times.end()); + GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1; + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time. + // And we'll probably time out and never get here. So, this test is + // intentionally loose: we check that x0 and x1 are within a factor of 8. + EXPECT_GE(x1, x0 / 8); + EXPECT_GE(x0, x1 / 8); +} + +// Try to create kTestSize keys that will land in just a few buckets, and +// time the insertions, to get a rough estimate of whether an O(n^2) worst case +// was triggered. This test is a hacky, but probably better than nothing. +TEST_P(MapImplTest, HashFlood) { + const int kTestSize = 1024; // must be a power of 2 + std::set<int> s; + for (int i = 0; s.size() < kTestSize; i++) { + if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) { + s.insert(i); + } + } + // Create hash table with kTestSize entries that hash flood a table with + // 1024 (or 512 or 2048 or ...) entries. This assumes that map_ uses powers + // of 2 for table sizes, and that it's sufficient to "flood" with respect to + // the low bits of the output of map_.hash_function(). + vector<int64> times; + std::set<int>::iterator it = s.begin(); + int count = 0; + do { + const int64 start = Now(); + map_[*it] = 0; + const int64 end = Now(); + if (end > start) { + times.push_back(end - start); + } + ++count; + ++it; + } while (it != s.end()); + if (times.size() < .99 * count) return; + int64 x0 = median(times.begin(), times.begin() + 9); + int64 x1 = median(times.begin() + times.size() - 9, times.end()); + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time. + // But we want to allow O(n log n). A factor of 20 should be generous enough. + EXPECT_LE(x1, x0 * 20); +} + +template <typename T, typename U> +static void TestValidityForAllKeysExcept(int key_to_avoid, + const T& check_map, + const U& map) { + typedef typename U::value_type value_type; // a key-value pair + for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) { + const int key = it->first; + if (key == key_to_avoid) continue; + // All iterators relevant to this key, whether old (from check_map) or new, + // must point to the same memory. So, test pointer equality here. + const value_type* check_val = &*check_map.find(key)->second; + EXPECT_EQ(check_val, &*it); + EXPECT_EQ(check_val, &*map.find(key)); + } +} + +// EXPECT i0 and i1 to be the same. Advancing them should have the same effect, +// too. +template <typename Iter> +static void TestEqualIterators(Iter i0, Iter i1, Iter end) { + const int kMaxAdvance = 10; + for (int i = 0; i < kMaxAdvance; i++) { + EXPECT_EQ(i0 == end, i1 == end); + if (i0 == end) return; + EXPECT_EQ(&*i0, &*i1) << "iter " << i; + ++i0; + ++i1; + } +} + +template <typename IteratorType> +static void TestOldVersusNewIterator(int skip, Map<int, int>* m) { + const int initial_size = m->size(); + IteratorType it = m->begin(); + for (int i = 0; i < skip && it != m->end(); it++, i++) {} + if (it == m->end()) return; + const IteratorType old = it; + GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first; + const int target_size = + initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4; + for (int i = 0; m->size() <= target_size; i++) { + (*m)[i] = 0; + } + // Iterator 'old' should still work just fine despite the growth of *m. + const IteratorType after_growth = m->find(old->first); + TestEqualIterators<IteratorType>(old, after_growth, m->end()); + + // Now shrink the number of elements. Do this with a mix of erases and + // inserts to increase the chance that the hashtable will resize to a lower + // number of buckets. (But, in any case, the test is still useful.) + for (int i = 0; i < 2 * (target_size - initial_size); i++) { + if (i != old->first) { + m->erase(i); + } + if (((i ^ m->begin()->first) & 15) == 0) { + (*m)[i * 342] = i; + } + } + // Now, the table has grown and shrunk; test again. + TestEqualIterators<IteratorType>(old, m->find(old->first), m->end()); + TestEqualIterators<IteratorType>(old, after_growth, m->end()); +} + +// Create and test an n-element Map, with emphasis on iterator correctness. +static void StressTestIterators(int n, bool test_old_style_proto2_maps) { + GOOGLE_LOG(INFO) << "StressTestIterators " << n; + GOOGLE_CHECK_GT(n, 0); + // Create a random-looking map of size n. Use non-negative integer keys. + Map<int, int> m(test_old_style_proto2_maps); + uint32 frog = 123987 + n; + int last_key = 0; + int counter = 0; + while (m.size() < n) { + frog *= static_cast<uint32>(k0); + frog ^= frog >> 17; + frog += counter++; + last_key = + static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1; + GOOGLE_DCHECK_GE(last_key, 0); + m[last_key] = last_key ^ 1; + } + // Test it. + ASSERT_EQ(n, m.size()); + // Create maps of pointers and iterators. + // These should remain valid even if we modify m. + hash_map<int, Map<int, int>::value_type*> mp(n); + hash_map<int, Map<int, int>::iterator> mi(n); + for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) { + mp[it->first] = &*it; + mi[it->first] = it; + } + ASSERT_EQ(m.size(), mi.size()); + ASSERT_EQ(m.size(), mp.size()); + m.erase(last_key); + ASSERT_EQ(n - 1, m.size()); + TestValidityForAllKeysExcept(last_key, mp, m); + TestValidityForAllKeysExcept(last_key, mi, m); + + m[last_key] = 0; + ASSERT_EQ(n, m.size()); + // Test old iterator vs new iterator, with table modification in between. + TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m); + TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m); + // Finally, ensure erase(iterator) doesn't reorder anything, becuase that is + // what its documentation says. + m[last_key] = m[last_key ^ 999] = 0; + vector<Map<int, int>::iterator> v; + v.reserve(m.size()); + int position_of_last_key = 0; + for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) { + if (it->first == last_key) { + position_of_last_key = v.size(); + } + v.push_back(it); + } + ASSERT_EQ(m.size(), v.size()); + const Map<int, int>::iterator erase_result = m.erase(m.find(last_key)); + int index = 0; + for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) { + if (index == position_of_last_key) { + EXPECT_EQ(&*erase_result, &*v[++index]); + } + ASSERT_EQ(&*it, &*v[index]); + } +} + +TEST_P(MapImplTest, IteratorInvalidation) { + // As multiple underlying hash_map implementations do not follow the + // validation requirement, the test is disabled for old-style maps. + if (GetParam()) return; + // Create a set of pseudo-random sizes to test. +#ifndef NDEBUG + const int kMaxSizeToTest = 100 * 1000; +#else + const int kMaxSizeToTest = 1000 * 1000; +#endif + std::set<int> s; + int n = kMaxSizeToTest; + int frog = k1 + n; + while (n > 1 && s.size() < 25) { + s.insert(n); + n = static_cast<int>(n * 100 / (101.0 + (frog & 63))); + frog *= k2; + frog ^= frog >> 17; + } + // Ensure we test a few small sizes. + s.insert(1); + s.insert(2); + s.insert(3); + // Now, the real work. + for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) { + StressTestIterators(*i, GetParam()); + } +} + +// Test that erase() revalidates iterators. +TEST_P(MapImplTest, EraseRevalidates) { + // As multiple underlying hash_map implementations do not follow the + // validation requirement, the test is disabled for old-style maps. + if (GetParam()) return; + map_[3] = map_[13] = map_[20] = 0; + const int initial_size = map_.size(); + EXPECT_EQ(3, initial_size); + vector<Map<int, int>::iterator> v; + for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) { + v.push_back(it); + } + EXPECT_EQ(initial_size, v.size()); + for (int i = 0; map_.size() <= initial_size * 20; i++) { + map_[i] = 0; + } + const int larger_size = map_.size(); + // We've greatly increased the size of the map, so it is highly likely that + // the following will corrupt m if erase() doesn't properly revalidate + // iterators passed to it. Finishing this routine without crashing indicates + // success. + for (int i = 0; i < v.size(); i++) { + map_.erase(v[i]); + } + EXPECT_EQ(larger_size - v.size(), map_.size()); +} + template <typename T> bool IsConstHelper(T& /*t*/) { // NOLINT. We want to catch non-const refs here. return false; @@ -290,7 +590,7 @@ bool IsConstHelper(const T& /*t*/) { return true; } -TEST_F(MapImplTest, IteratorConstness) { +TEST_P(MapImplTest, IteratorConstness) { map_[0] = 0; EXPECT_TRUE(IsConstHelper(*map_.cbegin())); EXPECT_TRUE(IsConstHelper(*const_map_.begin())); @@ -303,14 +603,14 @@ bool IsForwardIteratorHelper(T /*t*/) { return false; } -TEST_F(MapImplTest, IteratorCategory) { +TEST_P(MapImplTest, IteratorCategory) { EXPECT_TRUE(IsForwardIteratorHelper( std::iterator_traits<Map<int, int>::iterator>::iterator_category())); EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits< Map<int, int>::const_iterator>::iterator_category())); } -TEST_F(MapImplTest, InsertSingle) { +TEST_P(MapImplTest, InsertSingle) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -335,7 +635,7 @@ TEST_F(MapImplTest, InsertSingle) { EXPECT_FALSE(result2.second); } -TEST_F(MapImplTest, InsertByIterator) { +TEST_P(MapImplTest, InsertByIterator) { int32 key1 = 0; int32 key2 = 1; int32 value1a = 100; @@ -358,7 +658,7 @@ TEST_F(MapImplTest, InsertByIterator) { ExpectElements(map1); } -TEST_F(MapImplTest, EraseSingleByKey) { +TEST_P(MapImplTest, EraseSingleByKey) { int32 key = 0; int32 value = 100; @@ -376,7 +676,7 @@ TEST_F(MapImplTest, EraseSingleByKey) { EXPECT_EQ(0, map_.erase(key)); } -TEST_F(MapImplTest, EraseMutipleByKey) { +TEST_P(MapImplTest, EraseMutipleByKey) { // erase in one specific order to trigger corner cases for (int i = 0; i < 5; i++) { map_[i] = i; @@ -403,7 +703,7 @@ TEST_F(MapImplTest, EraseMutipleByKey) { EXPECT_TRUE(map_.end() == map_.find(2)); } -TEST_F(MapImplTest, EraseSingleByIterator) { +TEST_P(MapImplTest, EraseSingleByIterator) { int32 key = 0; int32 value = 100; @@ -418,7 +718,7 @@ TEST_F(MapImplTest, EraseSingleByIterator) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, ValidIteratorAfterErase) { +TEST_P(MapImplTest, ValidIteratorAfterErase) { for (int i = 0; i < 10; i++) { map_[i] = i; } @@ -438,7 +738,7 @@ TEST_F(MapImplTest, ValidIteratorAfterErase) { EXPECT_EQ(5, map_.size()); } -TEST_F(MapImplTest, EraseByIterator) { +TEST_P(MapImplTest, EraseByIterator) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -459,7 +759,7 @@ TEST_F(MapImplTest, EraseByIterator) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, Clear) { +TEST_P(MapImplTest, Clear) { int32 key = 0; int32 value = 100; @@ -474,7 +774,7 @@ TEST_F(MapImplTest, Clear) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, CopyConstructor) { +static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -484,16 +784,25 @@ TEST_F(MapImplTest, CopyConstructor) { map[key1] = value1; map[key2] = value2; - map_.insert(map.begin(), map.end()); + m->insert(map.begin(), map.end()); - Map<int32, int32> other(map_); + Map<int32, int32> other(*m); EXPECT_EQ(2, other.size()); EXPECT_EQ(value1, other.at(key1)); EXPECT_EQ(value2, other.at(key2)); } -TEST_F(MapImplTest, IterConstructor) { +TEST_P(MapImplTest, CopyConstructorWithArena) { + Arena a; + CopyConstructorHelper(&a, &map_); +} + +TEST_P(MapImplTest, CopyConstructorWithoutArena) { + CopyConstructorHelper(NULL, &map_); +} + +TEST_P(MapImplTest, IterConstructor) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -503,14 +812,15 @@ TEST_F(MapImplTest, IterConstructor) { map[key1] = value1; map[key2] = value2; - Map<int32, int32> new_map(map.begin(), map.end()); + Map<int32, int32> new_map(map.begin(), map.end(), + GetParam()); EXPECT_EQ(2, new_map.size()); EXPECT_EQ(value1, new_map.at(key1)); EXPECT_EQ(value2, new_map.at(key2)); } -TEST_F(MapImplTest, Assigner) { +TEST_P(MapImplTest, Assigner) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -522,7 +832,7 @@ TEST_F(MapImplTest, Assigner) { map_.insert(map.begin(), map.end()); - Map<int32, int32> other; + Map<int32, int32> other(GetParam()); int32 key_other = 123; int32 value_other = 321; other[key_other] = value_other; @@ -540,9 +850,16 @@ TEST_F(MapImplTest, Assigner) { EXPECT_EQ(2, other.size()); EXPECT_EQ(value1, other.at(key1)); EXPECT_EQ(value2, other.at(key2)); + + // Try assignment to a map with a different choice of "style." + Map<int32, int32> m(!GetParam()); + m = other; + EXPECT_EQ(2, m.size()); + EXPECT_EQ(value1, m.at(key1)); + EXPECT_EQ(value2, m.at(key2)); } -TEST_F(MapImplTest, Rehash) { +TEST_P(MapImplTest, Rehash) { const int test_size = 50; std::map<int32, int32> reference_map; for (int i = 0; i < test_size; i++) { @@ -559,7 +876,7 @@ TEST_F(MapImplTest, Rehash) { EXPECT_TRUE(map_.empty()); } -TEST_F(MapImplTest, EqualRange) { +TEST_P(MapImplTest, EqualRange) { int key = 100, key_missing = 101; map_[key] = 100; @@ -583,14 +900,14 @@ TEST_F(MapImplTest, EqualRange) { EXPECT_TRUE(const_map_.end() == const_range.second); } -TEST_F(MapImplTest, ConvertToStdMap) { +TEST_P(MapImplTest, ConvertToStdMap) { map_[100] = 101; std::map<int32, int32> std_map(map_.begin(), map_.end()); EXPECT_EQ(1, std_map.size()); EXPECT_EQ(101, std_map[100]); } -TEST_F(MapImplTest, ConvertToStdVectorOfPairs) { +TEST_P(MapImplTest, ConvertToStdVectorOfPairs) { map_[100] = 101; std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end()); EXPECT_EQ(1, std_vec.size()); @@ -598,6 +915,8 @@ TEST_F(MapImplTest, ConvertToStdVectorOfPairs) { EXPECT_EQ(101, std_vec[0].second); } +INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool()); + // Map Field Reflection Test ======================================== static int Func(int i, int j) { diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 032748bd..d62ca79c 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -69,7 +69,7 @@ void Message::MergeFrom(const Message& from) { GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to merge from a message with a different type. " "to: " << descriptor->full_name() << ", " - "from:" << from.GetDescriptor()->full_name(); + "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Merge(from, this); } @@ -82,7 +82,7 @@ void Message::CopyFrom(const Message& from) { GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to copy from a message with a different type. " "to: " << descriptor->full_name() << ", " - "from:" << from.GetDescriptor()->full_name(); + "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Copy(from, this); } diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 5bd8bcfb..9d7b64f7 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -62,13 +62,15 @@ namespace { // provide a useful error message. void ByteSizeConsistencyError(int byte_size_before_serialization, int byte_size_after_serialization, - int bytes_produced_by_serialization) { + int bytes_produced_by_serialization, + const MessageLite& message) { GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) - << "Protocol message was modified concurrently during serialization."; + << message.GetTypeName() + << " was modified concurrently during serialization."; GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) << "Byte size calculation and serialization were inconsistent. This " "may indicate a bug in protocol buffers or it may be caused by " - "concurrent modification of the message."; + "concurrent modification of " << message.GetTypeName() << "."; GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; } @@ -248,7 +250,7 @@ bool MessageLite::SerializePartialToCodedStream( if (buffer != NULL) { uint8* end = SerializeWithCachedSizesToArray(buffer); if (end - buffer != size) { - ByteSizeConsistencyError(size, ByteSize(), end - buffer); + ByteSizeConsistencyError(size, ByteSize(), end - buffer, *this); } return true; } else { @@ -261,7 +263,7 @@ bool MessageLite::SerializePartialToCodedStream( if (final_byte_count - original_byte_count != size) { ByteSizeConsistencyError(size, ByteSize(), - final_byte_count - original_byte_count); + final_byte_count - original_byte_count, *this); } return true; @@ -299,7 +301,7 @@ bool MessageLite::AppendPartialToString(string* output) const { reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size); uint8* end = SerializeWithCachedSizesToArray(start); if (end - start != byte_size) { - ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this); } return true; } @@ -325,7 +327,7 @@ bool MessageLite::SerializePartialToArray(void* data, int size) const { uint8* start = reinterpret_cast<uint8*>(data); uint8* end = SerializeWithCachedSizesToArray(start); if (end - start != byte_size) { - ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this); } return true; } @@ -359,6 +361,11 @@ void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, MessageLite* to) { to->CheckTypeAndMergeFrom(from); } +template<> +void GenericTypeHandler<string>::Merge(const string& from, + string* to) { + *to = from; +} } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index 2d4780fe..d668a1a6 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -55,6 +55,7 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h index 219645d3..fdee150b 100644 --- a/src/google/protobuf/metadata.h +++ b/src/google/protobuf/metadata.h @@ -56,7 +56,7 @@ namespace internal { // The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to // indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container // pointer. -class InternalMetadataWithArena { +class LIBPROTOBUF_EXPORT InternalMetadataWithArena { public: InternalMetadataWithArena() : ptr_(NULL) {} explicit InternalMetadataWithArena(Arena* arena) diff --git a/src/google/protobuf/proto3_arena_lite_unittest.cc b/src/google/protobuf/proto3_arena_lite_unittest.cc new file mode 100644 index 00000000..0f18c027 --- /dev/null +++ b/src/google/protobuf/proto3_arena_lite_unittest.cc @@ -0,0 +1,164 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string> +#include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif +#include <vector> + +#include <google/protobuf/test_util.h> +#include <google/protobuf/unittest.pb.h> +#include <google/protobuf/unittest_proto3_arena_lite.pb.h> +#include <google/protobuf/arena.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +using proto3_arena_lite_unittest::TestAllTypes; + +namespace protobuf { +namespace { +// We selectively set/check a few representative fields rather than all fields +// as this test is only expected to cover the basics of arena support. +void SetAllFields(TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->set_optional_nested_enum( + proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto3_arena_lite_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_nested_enum( + proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto3_arena_lite_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void ExpectAllFieldsSet(const TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +// In this file we only test some basic functionalities of arena support in +// proto3 and expect the arena support to be fully tested in proto2 unittests +// because proto3 shares most code with proto2. + +TEST(Proto3ArenaLiteTest, Parsing) { + TestAllTypes original; + SetAllFields(&original); + + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(*arena_message); +} + +TEST(Proto3ArenaLiteTest, Swap) { + Arena arena1; + Arena arena2; + + // Test Swap(). + TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); +} + +TEST(Proto3ArenaLiteTest, SetAllocatedMessage) { + Arena arena; + TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena); + TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; + nested->set_bb(118); + arena_message->set_allocated_optional_nested_message(nested); + EXPECT_EQ(118, arena_message->optional_nested_message().bb()); +} + +TEST(Proto3ArenaLiteTest, ReleaseMessage) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); + arena_message->mutable_optional_nested_message()->set_bb(118); + google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested( + arena_message->release_optional_nested_message()); + EXPECT_EQ(118, nested->bb()); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/proto3_lite_unittest.cc b/src/google/protobuf/proto3_lite_unittest.cc new file mode 100644 index 00000000..2e2beea9 --- /dev/null +++ b/src/google/protobuf/proto3_lite_unittest.cc @@ -0,0 +1,145 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string> +#include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif +#include <vector> + +#include <google/protobuf/test_util.h> +#include <google/protobuf/unittest.pb.h> +#include <google/protobuf/unittest_proto3_lite.pb.h> +#include <google/protobuf/arena.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +using proto3_lite_unittest::TestAllTypes; + +namespace protobuf { +namespace { +// We selectively set/check a few representative fields rather than all fields +// as this test is only expected to cover the basics of lite support. +void SetAllFields(TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->set_optional_nested_enum( + proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto3_lite_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_nested_enum( + proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto3_lite_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void ExpectAllFieldsSet(const TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto3_lite_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +// In this file we only test some basic functionalities of in proto3 and expect +// the rest is fully tested in proto2 unittests because proto3 shares most code +// with proto2. + +TEST(Proto3LiteTest, Parsing) { + TestAllTypes original; + SetAllFields(&original); + + TestAllTypes msg; + msg.ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(msg); +} + +TEST(Proto3LiteTest, Swap) { + // Test Swap(). + TestAllTypes msg1; + TestAllTypes msg2; + msg1.set_optional_string("123"); + msg2.set_optional_string("3456"); + msg1.Swap(&msg2); + EXPECT_EQ("3456", msg1.optional_string()); + EXPECT_EQ("123", msg2.optional_string()); + EXPECT_EQ(msg1.ByteSize(), msg2.ByteSize() + 1); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 949e0a23..77004f59 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -52,8 +52,8 @@ void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { } Rep* old_rep = rep_; Arena* arena = GetArenaNoVirtual(); - new_size = max(kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); + new_size = std::max(kMinRepeatedFieldAllocationSize, + std::max(total_size_ * 2, new_size)); GOOGLE_CHECK_LE(new_size, (std::numeric_limits<size_t>::max() - kRepHeaderSize) / sizeof(old_rep->elements[0])) diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 5447fa42..1961bc48 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -244,7 +244,7 @@ class RepeatedField { int total_size_; struct Rep { Arena* arena; - Element elements[1]; + Element elements[1]; }; // We can not use sizeof(Rep) - sizeof(Element) due to the trailing padding on // the struct. We can not use sizeof(Arena*) as well because there might be @@ -272,6 +272,22 @@ class RepeatedField { inline Arena* GetArenaNoVirtual() const { return (rep_ == NULL) ? NULL : rep_->arena; } + + // Internal helper to delete all elements and deallocate the storage. + // If Element has a trivial destructor (for example, if it's a fundamental + // type, like int32), the loop will be removed by the optimizer. + void InternalDeallocate(Rep* rep, int size) { + if (rep != NULL) { + Element* e = &rep->elements[0]; + Element* limit = &rep->elements[size]; + for (; e < limit; e++) { + e->Element::~Element(); + } + if (rep->arena == NULL) { + delete[] reinterpret_cast<char*>(rep); + } + } + } }; template<typename Element> @@ -610,6 +626,13 @@ inline void* GenericTypeHandler<MessageLite>::GetMaybeArenaPointer( template <> void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, MessageLite* to); +template<> +inline void GenericTypeHandler<string>::Clear(string* value) { + value->clear(); +} +template<> +void GenericTypeHandler<string>::Merge(const string& from, + string* to); // Declarations of the specialization as we cannot define them here, as the // header that defines ProtocolMessage depends on types defined in this header. @@ -836,6 +859,15 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Add an already-allocated object, skipping arena-ownership checks. The user // must guarantee that the given object is in the same arena as this // RepeatedPtrField. + // It is also useful in legacy code that uses temporary ownership to avoid + // copies. Example: + // RepeatedPtrField<T> temp_field; + // temp_field.AddAllocated(new T); + // ... // Do something with temp_field + // temp_field.ExtractSubrange(0, temp_field.size(), NULL); + // If you put temp_field on the arena this fails, because the ownership + // transfers to the arena at the "AddAllocated" call and is not released + // anymore causing a double delete. UnsafeArenaAddAllocated prevents this. void UnsafeArenaAddAllocated(Element* value); // Remove the last element and return it. Works only when operating on an @@ -992,19 +1024,8 @@ RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end) template <typename Element> RepeatedField<Element>::~RepeatedField() { // See explanation in Reserve(): we need to invoke destructors here for the - // case that Element has a non-trivial destructor. If Element has a trivial - // destructor (for example, if it's a primitive type, like int32), this entire - // loop will be removed by the optimizer. - if (rep_ != NULL) { - Element* e = &rep_->elements[0]; - Element* limit = &rep_->elements[total_size_]; - for (; e < limit; e++) { - e->Element::~Element(); - } - if (rep_->arena == NULL) { - delete[] reinterpret_cast<char*>(rep_); - } - } + // case that Element has a non-trivial destructor. + InternalDeallocate(rep_, total_size_); } template <typename Element> @@ -1240,8 +1261,8 @@ void RepeatedField<Element>::Reserve(int new_size) { if (total_size_ >= new_size) return; Rep* old_rep = rep_; Arena* arena = GetArenaNoVirtual(); - new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); + new_size = std::max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, + std::max(total_size_ * 2, new_size)); GOOGLE_CHECK_LE(static_cast<size_t>(new_size), (std::numeric_limits<size_t>::max() - kRepHeaderSize) / sizeof(Element)) @@ -1274,18 +1295,10 @@ void RepeatedField<Element>::Reserve(int new_size) { if (current_size_ > 0) { MoveArray(rep_->elements, old_rep->elements, current_size_); } - if (old_rep) { - // Likewise, we need to invoke destructors on the old array. If Element has - // no destructor, this loop will disappear. - e = &old_rep->elements[0]; - limit = &old_rep->elements[old_total_size]; - for (; e < limit; e++) { - e->Element::~Element(); - } - if (arena == NULL) { - delete[] reinterpret_cast<char*>(old_rep); - } - } + + // Likewise, we need to invoke destructors on the old array. + InternalDeallocate(old_rep, old_total_size); + } template <typename Element> @@ -2380,6 +2393,37 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator private: RepeatedPtrField<T>* field_; }; + +// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one +// uses the UnsafeArenaAddAllocated instead. +template<typename T> +class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator + : public std::iterator<std::output_iterator_tag, T> { + public: + explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( + ::google::protobuf::RepeatedPtrField<T>* const mutable_field) + : field_(mutable_field) { + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=( + T const* const ptr_to_value) { + field_->UnsafeArenaAddAllocated(const_cast<T*>(ptr_to_value)); + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++( + int /* unused */) { + return *this; + } + + private: + ::google::protobuf::RepeatedPtrField<T>* field_; +}; + } // namespace internal // Provides a back insert iterator for RepeatedField instances, @@ -2414,6 +2458,25 @@ AllocatedRepeatedPtrFieldBackInserter( mutable_field); } +// Similar to AllocatedRepeatedPtrFieldBackInserter, using +// UnsafeArenaAddAllocated instead of AddAllocated. +// This is slightly faster if that matters. It is also useful in legacy code +// that uses temporary ownership to avoid copies. Example: +// RepeatedPtrField<T> temp_field; +// temp_field.AddAllocated(new T); +// ... // Do something with temp_field +// temp_field.ExtractSubrange(0, temp_field.size(), NULL); +// If you put temp_field on the arena this fails, because the ownership +// transfers to the arena at the "AddAllocated" call and is not released anymore +// causing a double delete. Using UnsafeArenaAddAllocated prevents this. +template<typename T> +internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T> +UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + ::google::protobuf::RepeatedPtrField<T>* const mutable_field) { + return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>( + mutable_field); +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index b45664b0..39b24b33 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -1522,6 +1522,44 @@ TEST_F(RepeatedFieldInsertionIteratorsTest, EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); } +TEST_F(RepeatedFieldInsertionIteratorsTest, + UnsafeArenaAllocatedRepeatedPtrFieldWithStringIntData) { + vector<Nested*> data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + Nested* new_data = new Nested; + new_data->set_bb(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_nested_message(); + new_data->set_bb(i); + } + TestAllTypes testproto; + std::copy(data.begin(), data.end(), + UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_nested_message())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, + UnsafeArenaAllocatedRepeatedPtrFieldWithString) { + vector<string*> data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + string* new_data = new string; + *new_data = "name-" + SimpleItoa(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_string(); + *new_data = "name-" + SimpleItoa(i); + } + TestAllTypes testproto; + std::copy(data.begin(), data.end(), + UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_string())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + } // namespace } // namespace protobuf diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index f2eb7ae7..c67cd102 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -177,12 +177,13 @@ SourceContext* SourceContext::New(::google::protobuf::Arena* arena) const { } void SourceContext::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceContext) file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool SourceContext::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceContext) for (;;) { @@ -262,6 +263,7 @@ void SourceContext::SerializeWithCachedSizes( } int SourceContext::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext) int total_size = 0; // optional string file_name = 1; @@ -278,18 +280,22 @@ int SourceContext::ByteSize() const { } void SourceContext::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceContext) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceContext* source = ::google::protobuf::internal::DynamicCastToGenerated<const SourceContext>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceContext) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceContext) MergeFrom(*source); } } void SourceContext::MergeFrom(const SourceContext& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.file_name().size() > 0) { @@ -298,12 +304,14 @@ void SourceContext::MergeFrom(const SourceContext& from) { } void SourceContext::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceContext) if (&from == this) return; Clear(); MergeFrom(from); } void SourceContext::CopyFrom(const SourceContext& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceContext) if (&from == this) return; Clear(); MergeFrom(from); @@ -365,6 +373,7 @@ void SourceContext::clear_file_name() { return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceContext::release_file_name() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name) return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 02e11460..ccfd365b 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -160,6 +160,7 @@ inline ::std::string* SourceContext::mutable_file_name() { return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceContext::release_file_name() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name) return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index e020597a..11ccabbf 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -166,9 +166,11 @@ void protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto() { "\000\0220\n\nlist_value\030\006 \001(\0132\032.google.protobuf." "ListValueH\000B\006\n\004kind\"3\n\tListValue\022&\n\006valu" "es\030\001 \003(\0132\026.google.protobuf.Value*\033\n\tNull" - "Value\022\016\n\nNULL_VALUE\020\000BN\n\023com.google.prot" - "obufB\013StructProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Pr" - "otobuf.WellKnownTypesb\006proto3", 589); + "Value\022\016\n\nNULL_VALUE\020\000B\201\001\n\023com.google.pro" + "tobufB\013StructProtoP\001Z1github.com/golang/" + "protobuf/ptypes/struct;structpb\240\001\001\242\002\003GPB" + "\252\002\036Google.Protobuf.WellKnownTypesb\006proto" + "3", 641); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/struct.proto", &protobuf_RegisterTypes); Struct::default_instance_ = new Struct(); @@ -280,12 +282,13 @@ Struct* Struct::New(::google::protobuf::Arena* arena) const { } void Struct::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Struct) fields_.Clear(); } bool Struct::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Struct) for (;;) { @@ -383,6 +386,7 @@ void Struct::SerializeWithCachedSizes( } int Struct::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct) int total_size = 0; // map<string, .google.protobuf.Value> fields = 1; @@ -405,29 +409,35 @@ int Struct::ByteSize() const { } void Struct::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Struct) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Struct* source = ::google::protobuf::internal::DynamicCastToGenerated<const Struct>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Struct) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Struct) MergeFrom(*source); } } void Struct::MergeFrom(const Struct& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); fields_.MergeFrom(from.fields_); } void Struct::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Struct) if (&from == this) return; Clear(); MergeFrom(from); } void Struct::CopyFrom(const Struct& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Struct) if (&from == this) return; Clear(); MergeFrom(from); @@ -560,6 +570,7 @@ Value* Value::New(::google::protobuf::Arena* arena) const { } void Value::clear_kind() { +// @@protoc_insertion_point(one_of_clear_start:google.protobuf.Value) switch(kind_case()) { case kNullValue: { // No need to clear @@ -594,12 +605,13 @@ void Value::clear_kind() { void Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Value) clear_kind(); } bool Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Value) for (;;) { @@ -811,6 +823,7 @@ void Value::SerializeWithCachedSizes( } int Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value) int total_size = 0; switch (kind_case()) { @@ -862,18 +875,22 @@ int Value::ByteSize() const { } void Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Value* source = ::google::protobuf::internal::DynamicCastToGenerated<const Value>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Value) MergeFrom(*source); } } void Value::MergeFrom(const Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); switch (from.kind_case()) { case kNullValue: { @@ -907,12 +924,14 @@ void Value::MergeFrom(const Value& from) { } void Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Value) if (&from == this) return; Clear(); MergeFrom(from); } void Value::CopyFrom(const Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1063,6 +1082,7 @@ void Value::clear_string_value() { return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Value::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value) if (has_string_value()) { clear_has_kind(); return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -1141,6 +1161,7 @@ void Value::clear_struct_value() { return kind_.struct_value_; } ::google::protobuf::Struct* Value::release_struct_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value) if (has_struct_value()) { clear_has_kind(); ::google::protobuf::Struct* temp = kind_.struct_value_; @@ -1188,6 +1209,7 @@ void Value::clear_list_value() { return kind_.list_value_; } ::google::protobuf::ListValue* Value::release_list_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value) if (has_list_value()) { clear_has_kind(); ::google::protobuf::ListValue* temp = kind_.list_value_; @@ -1282,12 +1304,13 @@ ListValue* ListValue::New(::google::protobuf::Arena* arena) const { } void ListValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ListValue) values_.Clear(); } bool ListValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ListValue) for (;;) { @@ -1359,6 +1382,7 @@ void ListValue::SerializeWithCachedSizes( } int ListValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue) int total_size = 0; // repeated .google.protobuf.Value values = 1; @@ -1376,29 +1400,35 @@ int ListValue::ByteSize() const { } void ListValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ListValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ListValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const ListValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ListValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ListValue) MergeFrom(*source); } } void ListValue::MergeFrom(const ListValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); values_.MergeFrom(from.values_); } void ListValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ListValue) if (&from == this) return; Clear(); MergeFrom(from); } void ListValue::CopyFrom(const ListValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ListValue) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 0527c812..6a4764a7 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -550,6 +550,7 @@ inline ::std::string* Value::mutable_string_value() { return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Value::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value) if (has_string_value()) { clear_has_kind(); return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -628,6 +629,7 @@ inline ::google::protobuf::Struct* Value::mutable_struct_value() { return kind_.struct_value_; } inline ::google::protobuf::Struct* Value::release_struct_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value) if (has_struct_value()) { clear_has_kind(); ::google::protobuf::Struct* temp = kind_.struct_value_; @@ -675,6 +677,7 @@ inline ::google::protobuf::ListValue* Value::mutable_list_value() { return kind_.list_value_; } inline ::google::protobuf::ListValue* Value::release_list_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value) if (has_list_value()) { clear_has_kind(); ::google::protobuf::ListValue* temp = kind_.list_value_; diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto index 8562e2c1..beeba811 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/struct;structpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "StructProto"; option java_multiple_files = true; @@ -49,7 +50,7 @@ option objc_class_prefix = "GPB"; // // The JSON representation for `Struct` is JSON object. message Struct { - // Map of dynamically typed values. + // Unordered map of dynamically typed values. map<string, Value> fields = 1; } diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index 58334322..bbd8ee65 100755 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -214,6 +214,8 @@ class hash_map : public std::map<Key, Data, HashFcn, Alloc> { hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(b, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template <typename Key, @@ -222,6 +224,8 @@ template <typename Key, class hash_set : public std::set<Key, HashFcn> { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) @@ -257,6 +261,8 @@ class hash_map hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template <typename Key, typename HashFcn = hash<Key>, @@ -266,6 +272,8 @@ class hash_set Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #else @@ -315,6 +323,8 @@ class hash_map hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template <typename Key, typename HashFcn = hash<Key>, @@ -324,6 +334,8 @@ class hash_set Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #endif // !GOOGLE_PROTOBUF_MISSING_HASH diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc index d80c64f2..3a36b4b1 100644 --- a/src/google/protobuf/stubs/int128.cc +++ b/src/google/protobuf/stubs/int128.cc @@ -31,7 +31,7 @@ #include <google/protobuf/stubs/int128.h> #include <iomanip> -#include <iostream> // NOLINT(readability/streams) +#include <ostream> // NOLINT(readability/streams) #include <sstream> namespace google { diff --git a/src/google/protobuf/stubs/logging.h b/src/google/protobuf/stubs/logging.h index 3108db8c..f69605d9 100644 --- a/src/google/protobuf/stubs/logging.h +++ b/src/google/protobuf/stubs/logging.h @@ -174,7 +174,7 @@ T* CheckNotNull(const char* /* file */, int /* line */, #ifdef NDEBUG -#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false) +#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false) #define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION) #define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E)) diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h index 3a1ef8a8..27956a8e 100644 --- a/src/google/protobuf/stubs/mathutil.h +++ b/src/google/protobuf/stubs/mathutil.h @@ -83,7 +83,7 @@ class MathUtil { if (value == T(0) || ::google::protobuf::internal::IsNan<T>(value)) { return value; } - return value > T(0) ? value : -value; + return value > T(0) ? 1 : -1; } template<typename T> diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h index ad848701..29f869ad 100644 --- a/src/google/protobuf/stubs/statusor.h +++ b/src/google/protobuf/stubs/statusor.h @@ -224,7 +224,7 @@ inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { template<typename T> template<typename U> inline StatusOr<T>::StatusOr(const StatusOr<U>& other) - : status_(other.status_), value_(other.status_.ok() ? other.value_ : NULL) { + : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { } template<typename T> diff --git a/src/google/protobuf/stubs/stringpiece.h b/src/google/protobuf/stubs/stringpiece.h index ec3ffd5b..91671659 100644 --- a/src/google/protobuf/stubs/stringpiece.h +++ b/src/google/protobuf/stubs/stringpiece.h @@ -435,6 +435,44 @@ inline bool operator>=(StringPiece x, StringPiece y) { // allow StringPiece to be logged extern std::ostream& operator<<(std::ostream& o, StringPiece piece); +namespace internal { +// StringPiece is not a POD and can not be used in an union (pre C++11). We +// need a POD version of it. +struct StringPiecePod { + // Create from a StringPiece. + static StringPiecePod CreateFromStringPiece(StringPiece str) { + StringPiecePod pod; + pod.data_ = str.data(); + pod.size_ = str.size(); + return pod; + } + + // Cast to StringPiece. + operator StringPiece() const { return StringPiece(data_, size_); } + + bool operator==(const char* value) const { + return StringPiece(data_, size_) == StringPiece(value); + } + + char operator[](stringpiece_ssize_type i) const { + assert(0 <= i); + assert(i < size_); + return data_[i]; + } + + const char* data() const { return data_; } + + stringpiece_ssize_type size() const { + return size_; + } + + std::string ToString() const { return std::string(data_, size_); } + private: + const char* data_; + stringpiece_ssize_type size_; +}; + +} // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc index 3272d8e3..83fdfe45 100644 --- a/src/google/protobuf/stubs/stringprintf.cc +++ b/src/google/protobuf/stubs/stringprintf.cc @@ -37,7 +37,6 @@ #include <stdio.h> // MSVC requires this for _vsnprintf #include <vector> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/testing/googletest.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 27d47575..8bdd6110 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -648,6 +648,9 @@ struct LIBPROTOBUF_EXPORT AlphaNum { AlphaNum(StringPiece str) : piece_data_(str.data()), piece_size_(str.size()) {} + AlphaNum(internal::StringPiecePod str) + : piece_data_(str.data()), piece_size_(str.size()) {} + size_t size() const { return piece_size_; } const char *data() const { return piece_data_; } @@ -847,6 +850,11 @@ LIBPROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc, LIBPROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc, string* dest, bool do_padding); +inline bool IsValidCodePoint(uint32 code_point) { + return code_point < 0xD800 || + (code_point >= 0xE000 && code_point <= 0x10FFFF); +} + static const int UTFmax = 4; // ---------------------------------------------------------------------- // EncodeAsUTF8Char() diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index b0a5ce63..c0dfd53f 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -91,7 +91,10 @@ inline bool GetAnyFieldDescriptors(const Message& message, string Message::DebugString() const { string debug_string; - TextFormat::PrintToString(*this, &debug_string); + TextFormat::Printer printer; + printer.SetExpandAny(true); + + printer.PrintToString(*this, &debug_string); return debug_string; } @@ -101,6 +104,7 @@ string Message::ShortDebugString() const { TextFormat::Printer printer; printer.SetSingleLineMode(true); + printer.SetExpandAny(true); printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. @@ -117,6 +121,7 @@ string Message::Utf8DebugString() const { TextFormat::Printer printer; printer.SetUseUtf8StringEscaping(true); + printer.SetExpandAny(true); printer.PrintToString(*this, &debug_string); @@ -1153,10 +1158,10 @@ class TextFormat::Printer::TextGenerator { } // Print text to the output stream. - void Print(const char* text, int size) { - int pos = 0; // The number of bytes we've written so far. + void Print(const char* text, size_t size) { + size_t pos = 0; // The number of bytes we've written so far. - for (int i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { if (text[i] == '\n') { // Saw newline. If there is more text, we may need to insert an indent // here. So, write what we have so far, including the '\n'. @@ -1181,7 +1186,7 @@ class TextFormat::Printer::TextGenerator { private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator); - void Write(const char* data, int size) { + void Write(const char* data, size_t size) { if (failed_) return; if (size == 0) return; @@ -1780,14 +1785,12 @@ void TextFormat::Printer::PrintFieldValue( ? reflection->GetRepeatedStringReference( message, field, index, &scratch) : reflection->GetStringReference(message, field, &scratch); - int64 size = value.size(); - if (truncate_string_field_longer_than_ > 0) { - size = std::min(truncate_string_field_longer_than_, - static_cast<int64>(value.size())); - } - string truncated_value(value.substr(0, size) + "...<truncated>..."); const string* value_to_print = &value; - if (size < value.size()) { + string truncated_value; + if (truncate_string_field_longer_than_ > 0 && + truncate_string_field_longer_than_ < value.size()) { + truncated_value = value.substr(0, truncate_string_field_longer_than_) + + "...<truncated>..."; value_to_print = &truncated_value; } if (field->type() == FieldDescriptor::TYPE_STRING) { diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 8d61be19..58aa3f8d 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -44,6 +44,8 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> @@ -52,10 +54,10 @@ #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/mathlimits.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> +#include <google/protobuf/stubs/mathlimits.h> namespace google { diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index c1c4402c..7cdf5093 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\037google/protobuf/timestamp.proto\022\017googl" "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003" - "\022\r\n\005nanos\030\002 \001(\005BT\n\023com.google.protobufB\016" - "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr" - "otobuf.WellKnownTypesb\006proto3", 189); + "\022\r\n\005nanos\030\002 \001(\005B\201\001\n\023com.google.protobufB" + "\016TimestampProtoP\001Z+github.com/golang/pro" + "tobuf/ptypes/timestamp\240\001\001\370\001\001\242\002\003GPB\252\002\036Goo" + "gle.Protobuf.WellKnownTypesb\006proto3", 235); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/timestamp.proto", &protobuf_RegisterTypes); Timestamp::default_instance_ = new Timestamp(); @@ -192,8 +193,17 @@ Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const { } void Timestamp::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Timestamp) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(Timestamp, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<Timestamp*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -209,7 +219,7 @@ void Timestamp::Clear() { bool Timestamp::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Timestamp) for (;;) { @@ -301,6 +311,7 @@ void Timestamp::SerializeWithCachedSizes( } int Timestamp::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp) int total_size = 0; // optional int64 seconds = 1; @@ -324,18 +335,22 @@ int Timestamp::ByteSize() const { } void Timestamp::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Timestamp) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Timestamp* source = ::google::protobuf::internal::DynamicCastToGenerated<const Timestamp>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Timestamp) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Timestamp) MergeFrom(*source); } } void Timestamp::MergeFrom(const Timestamp& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.seconds() != 0) { set_seconds(from.seconds()); @@ -346,12 +361,14 @@ void Timestamp::MergeFrom(const Timestamp& from) { } void Timestamp::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Timestamp) if (&from == this) return; Clear(); MergeFrom(from); } void Timestamp::CopyFrom(const Timestamp& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Timestamp) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index b51fc3fa..7992a858 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -34,6 +34,7 @@ package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; option java_package = "com.google.protobuf"; option java_outer_classname = "TimestampProto"; option java_multiple_files = true; diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 7b47b3bd..759cab27 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -359,6 +359,7 @@ Type* Type::New(::google::protobuf::Arena* arena) const { } void Type::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Type) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; @@ -370,7 +371,7 @@ void Type::Clear() { bool Type::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Type) for (;;) { @@ -603,6 +604,7 @@ void Type::SerializeWithCachedSizes( } int Type::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type) int total_size = 0; // optional string name = 1; @@ -655,18 +657,22 @@ int Type::ByteSize() const { } void Type::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Type) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Type* source = ::google::protobuf::internal::DynamicCastToGenerated<const Type>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Type) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Type) MergeFrom(*source); } } void Type::MergeFrom(const Type& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); fields_.MergeFrom(from.fields_); oneofs_.MergeFrom(from.oneofs_); @@ -684,12 +690,14 @@ void Type::MergeFrom(const Type& from) { } void Type::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Type) if (&from == this) return; Clear(); MergeFrom(from); } void Type::CopyFrom(const Type& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Type) if (&from == this) return; Clear(); MergeFrom(from); @@ -756,6 +764,7 @@ void Type::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Type::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -828,6 +837,7 @@ void Type::clear_oneofs() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs) } ::std::string* Type::add_oneofs() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs) return oneofs_.Add(); } void Type::add_oneofs(const ::std::string& value) { @@ -904,6 +914,7 @@ const ::google::protobuf::SourceContext& Type::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Type::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1104,8 +1115,17 @@ Field* Field::New(::google::protobuf::Arena* arena) const { } void Field::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Field) +#if defined(__clang__) +#define ZR_HELPER_(f) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(Field, f) \ + _Pragma("clang diagnostic pop") +#else #define ZR_HELPER_(f) reinterpret_cast<char*>(\ &reinterpret_cast<Field*>(16)->f) +#endif #define ZR_(first, last) do {\ ::memset(&first, 0,\ @@ -1128,7 +1148,7 @@ void Field::Clear() { bool Field::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Field) for (;;) { @@ -1483,6 +1503,7 @@ void Field::SerializeWithCachedSizes( } int Field::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field) int total_size = 0; // optional .google.protobuf.Field.Kind kind = 1; @@ -1559,18 +1580,22 @@ int Field::ByteSize() const { } void Field::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Field) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Field* source = ::google::protobuf::internal::DynamicCastToGenerated<const Field>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Field) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Field) MergeFrom(*source); } } void Field::MergeFrom(const Field& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.kind() != 0) { @@ -1607,12 +1632,14 @@ void Field::MergeFrom(const Field& from) { } void Field::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Field) if (&from == this) return; Clear(); MergeFrom(from); } void Field::CopyFrom(const Field& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Field) if (&from == this) return; Clear(); MergeFrom(from); @@ -1725,6 +1752,7 @@ void Field::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1768,6 +1796,7 @@ void Field::clear_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1869,6 +1898,7 @@ void Field::clear_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name) return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1912,6 +1942,7 @@ void Field::clear_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value) return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2003,6 +2034,7 @@ Enum* Enum::New(::google::protobuf::Arena* arena) const { } void Enum::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Enum) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; @@ -2013,7 +2045,7 @@ void Enum::Clear() { bool Enum::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Enum) for (;;) { @@ -2206,6 +2238,7 @@ void Enum::SerializeWithCachedSizes( } int Enum::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum) int total_size = 0; // optional string name = 1; @@ -2251,18 +2284,22 @@ int Enum::ByteSize() const { } void Enum::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Enum) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Enum* source = ::google::protobuf::internal::DynamicCastToGenerated<const Enum>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Enum) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Enum) MergeFrom(*source); } } void Enum::MergeFrom(const Enum& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); enumvalue_.MergeFrom(from.enumvalue_); options_.MergeFrom(from.options_); @@ -2279,12 +2316,14 @@ void Enum::MergeFrom(const Enum& from) { } void Enum::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Enum) if (&from == this) return; Clear(); MergeFrom(from); } void Enum::CopyFrom(const Enum& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Enum) if (&from == this) return; Clear(); MergeFrom(from); @@ -2350,6 +2389,7 @@ void Enum::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Enum::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2444,6 +2484,7 @@ const ::google::protobuf::SourceContext& Enum::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Enum::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -2547,6 +2588,7 @@ EnumValue* EnumValue::New(::google::protobuf::Arena* arena) const { } void EnumValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValue) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); number_ = 0; options_.Clear(); @@ -2554,7 +2596,7 @@ void EnumValue::Clear() { bool EnumValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValue) for (;;) { @@ -2689,6 +2731,7 @@ void EnumValue::SerializeWithCachedSizes( } int EnumValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue) int total_size = 0; // optional string name = 1; @@ -2720,18 +2763,22 @@ int EnumValue::ByteSize() const { } void EnumValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const EnumValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValue) MergeFrom(*source); } } void EnumValue::MergeFrom(const EnumValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.name().size() > 0) { @@ -2744,12 +2791,14 @@ void EnumValue::MergeFrom(const EnumValue& from) { } void EnumValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValue) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValue::CopyFrom(const EnumValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2813,6 +2862,7 @@ void EnumValue::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumValue::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2944,6 +2994,7 @@ Option* Option::New(::google::protobuf::Arena* arena) const { } void Option::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Option) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; @@ -2951,7 +3002,7 @@ void Option::Clear() { bool Option::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Option) for (;;) { @@ -3057,6 +3108,7 @@ void Option::SerializeWithCachedSizes( } int Option::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option) int total_size = 0; // optional string name = 1; @@ -3080,18 +3132,22 @@ int Option::ByteSize() const { } void Option::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Option) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Option* source = ::google::protobuf::internal::DynamicCastToGenerated<const Option>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Option) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Option) MergeFrom(*source); } } void Option::MergeFrom(const Option& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.name().size() > 0) { @@ -3103,12 +3159,14 @@ void Option::MergeFrom(const Option& from) { } void Option::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Option) if (&from == this) return; Clear(); MergeFrom(from); } void Option::CopyFrom(const Option& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Option) if (&from == this) return; Clear(); MergeFrom(from); @@ -3171,6 +3229,7 @@ void Option::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Option::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3205,6 +3264,7 @@ const ::google::protobuf::Any& Option::value() const { return value_; } ::google::protobuf::Any* Option::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.value) ::google::protobuf::Any* temp = value_; value_ = NULL; diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index 76fe8a65..4255fa8c 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -328,25 +328,44 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef Field_Kind Kind; - static const Kind TYPE_UNKNOWN = Field_Kind_TYPE_UNKNOWN; - static const Kind TYPE_DOUBLE = Field_Kind_TYPE_DOUBLE; - static const Kind TYPE_FLOAT = Field_Kind_TYPE_FLOAT; - static const Kind TYPE_INT64 = Field_Kind_TYPE_INT64; - static const Kind TYPE_UINT64 = Field_Kind_TYPE_UINT64; - static const Kind TYPE_INT32 = Field_Kind_TYPE_INT32; - static const Kind TYPE_FIXED64 = Field_Kind_TYPE_FIXED64; - static const Kind TYPE_FIXED32 = Field_Kind_TYPE_FIXED32; - static const Kind TYPE_BOOL = Field_Kind_TYPE_BOOL; - static const Kind TYPE_STRING = Field_Kind_TYPE_STRING; - static const Kind TYPE_GROUP = Field_Kind_TYPE_GROUP; - static const Kind TYPE_MESSAGE = Field_Kind_TYPE_MESSAGE; - static const Kind TYPE_BYTES = Field_Kind_TYPE_BYTES; - static const Kind TYPE_UINT32 = Field_Kind_TYPE_UINT32; - static const Kind TYPE_ENUM = Field_Kind_TYPE_ENUM; - static const Kind TYPE_SFIXED32 = Field_Kind_TYPE_SFIXED32; - static const Kind TYPE_SFIXED64 = Field_Kind_TYPE_SFIXED64; - static const Kind TYPE_SINT32 = Field_Kind_TYPE_SINT32; - static const Kind TYPE_SINT64 = Field_Kind_TYPE_SINT64; + static const Kind TYPE_UNKNOWN = + Field_Kind_TYPE_UNKNOWN; + static const Kind TYPE_DOUBLE = + Field_Kind_TYPE_DOUBLE; + static const Kind TYPE_FLOAT = + Field_Kind_TYPE_FLOAT; + static const Kind TYPE_INT64 = + Field_Kind_TYPE_INT64; + static const Kind TYPE_UINT64 = + Field_Kind_TYPE_UINT64; + static const Kind TYPE_INT32 = + Field_Kind_TYPE_INT32; + static const Kind TYPE_FIXED64 = + Field_Kind_TYPE_FIXED64; + static const Kind TYPE_FIXED32 = + Field_Kind_TYPE_FIXED32; + static const Kind TYPE_BOOL = + Field_Kind_TYPE_BOOL; + static const Kind TYPE_STRING = + Field_Kind_TYPE_STRING; + static const Kind TYPE_GROUP = + Field_Kind_TYPE_GROUP; + static const Kind TYPE_MESSAGE = + Field_Kind_TYPE_MESSAGE; + static const Kind TYPE_BYTES = + Field_Kind_TYPE_BYTES; + static const Kind TYPE_UINT32 = + Field_Kind_TYPE_UINT32; + static const Kind TYPE_ENUM = + Field_Kind_TYPE_ENUM; + static const Kind TYPE_SFIXED32 = + Field_Kind_TYPE_SFIXED32; + static const Kind TYPE_SFIXED64 = + Field_Kind_TYPE_SFIXED64; + static const Kind TYPE_SINT32 = + Field_Kind_TYPE_SINT32; + static const Kind TYPE_SINT64 = + Field_Kind_TYPE_SINT64; static inline bool Kind_IsValid(int value) { return Field_Kind_IsValid(value); } @@ -369,10 +388,14 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { } typedef Field_Cardinality Cardinality; - static const Cardinality CARDINALITY_UNKNOWN = Field_Cardinality_CARDINALITY_UNKNOWN; - static const Cardinality CARDINALITY_OPTIONAL = Field_Cardinality_CARDINALITY_OPTIONAL; - static const Cardinality CARDINALITY_REQUIRED = Field_Cardinality_CARDINALITY_REQUIRED; - static const Cardinality CARDINALITY_REPEATED = Field_Cardinality_CARDINALITY_REPEATED; + static const Cardinality CARDINALITY_UNKNOWN = + Field_Cardinality_CARDINALITY_UNKNOWN; + static const Cardinality CARDINALITY_OPTIONAL = + Field_Cardinality_CARDINALITY_OPTIONAL; + static const Cardinality CARDINALITY_REQUIRED = + Field_Cardinality_CARDINALITY_REQUIRED; + static const Cardinality CARDINALITY_REPEATED = + Field_Cardinality_CARDINALITY_REPEATED; static inline bool Cardinality_IsValid(int value) { return Field_Cardinality_IsValid(value); } @@ -865,6 +888,7 @@ inline ::std::string* Type::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Type::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -937,6 +961,7 @@ inline void Type::set_oneofs(int index, const char* value, size_t size) { // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs) } inline ::std::string* Type::add_oneofs() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs) return oneofs_.Add(); } inline void Type::add_oneofs(const ::std::string& value) { @@ -1013,6 +1038,7 @@ inline ::google::protobuf::SourceContext* Type::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Type::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1119,6 +1145,7 @@ inline ::std::string* Field::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1162,6 +1189,7 @@ inline ::std::string* Field::mutable_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1263,6 +1291,7 @@ inline ::std::string* Field::mutable_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name) return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1306,6 +1335,7 @@ inline ::std::string* Field::mutable_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value) return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1353,6 +1383,7 @@ inline ::std::string* Enum::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Enum::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1447,6 +1478,7 @@ inline ::google::protobuf::SourceContext* Enum::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Enum::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1511,6 +1543,7 @@ inline ::std::string* EnumValue::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumValue::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1602,6 +1635,7 @@ inline ::std::string* Option::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Option::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1636,6 +1670,7 @@ inline ::google::protobuf::Any* Option::mutable_value() { return value_; } inline ::google::protobuf::Any* Option::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.value) ::google::protobuf::Any* temp = value_; value_ = NULL; diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 85fe6153..da56ae0a 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -696,6 +696,7 @@ message TestRequiredOneof { } } + // Test messages for packed fields message TestPackedTypes { diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto index 662c0e46..878ec7c1 100644 --- a/src/google/protobuf/unittest_lite.proto +++ b/src/google/protobuf/unittest_lite.proto @@ -43,8 +43,10 @@ option java_package = "com.google.protobuf"; // Same as TestAllTypes but with the lite runtime. message TestAllTypesLite { + message NestedMessage { optional int32 bb = 1; + optional int64 cc = 2; } enum NestedEnum { @@ -159,6 +161,7 @@ message TestAllTypesLite { NestedMessage oneof_nested_message = 112; string oneof_string = 113; bytes oneof_bytes = 114; + NestedMessage oneof_lazy_nested_message = 115 [lazy = true]; } } @@ -383,3 +386,22 @@ message TestEmptyMessageLite{ message TestEmptyMessageWithExtensionsLite { extensions 1 to max; } + +enum V1EnumLite { + V1_FIRST = 1; +} + +enum V2EnumLite { + V2_FIRST = 1; + V2_SECOND = 2; +} + +message V1MessageLite { + required int32 int_field = 1; + optional V1EnumLite enum_field = 2 [ default = V1_FIRST ]; +} + +message V2MessageLite { + required int32 int_field = 1; + optional V2EnumLite enum_field = 2 [ default = V2_FIRST ]; +} diff --git a/src/google/protobuf/unittest_proto3_arena_lite.proto b/src/google/protobuf/unittest_proto3_arena_lite.proto new file mode 100644 index 00000000..5a60b90f --- /dev/null +++ b/src/google/protobuf/unittest_proto3_arena_lite.proto @@ -0,0 +1,207 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option cc_enable_arenas = true; +option optimize_for = LITE_RUNTIME; + +import "google/protobuf/unittest_import.proto"; + +package proto3_arena_lite_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recusively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage { +} + diff --git a/src/google/protobuf/unittest_proto3_lite.proto b/src/google/protobuf/unittest_proto3_lite.proto new file mode 100644 index 00000000..874ade6c --- /dev/null +++ b/src/google/protobuf/unittest_proto3_lite.proto @@ -0,0 +1,206 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +import "google/protobuf/unittest_import.proto"; + +package proto3_lite_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recusively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage { +} + diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc index 9f613265..60b8b8a5 100644 --- a/src/google/protobuf/util/field_comparator.cc +++ b/src/google/protobuf/util/field_comparator.cc @@ -92,7 +92,27 @@ FieldComparator::ComparisonResult DefaultFieldComparator::Compare( case FieldDescriptor::CPPTYPE_INT64: COMPARE_FIELD(Int64); case FieldDescriptor::CPPTYPE_STRING: - COMPARE_FIELD(String); + if (field->is_repeated()) { + // Allocate scratch strings to store the result if a conversion is + // needed. + string scratch1; + string scratch2; + return ResultFromBoolean( + CompareString(*field, reflection_1->GetRepeatedStringReference( + message_1, field, index_1, &scratch1), + reflection_2->GetRepeatedStringReference( + message_2, field, index_2, &scratch2))); + } else { + // Allocate scratch strings to store the result if a conversion is + // needed. + string scratch1; + string scratch2; + return ResultFromBoolean(CompareString( + *field, + reflection_1->GetStringReference(message_1, field, &scratch1), + reflection_2->GetStringReference(message_2, field, &scratch2))); + } + break; case FieldDescriptor::CPPTYPE_UINT32: COMPARE_FIELD(UInt32); case FieldDescriptor::CPPTYPE_UINT64: diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h index 8b83c69f..1b4d65b0 100644 --- a/src/google/protobuf/util/field_comparator.h +++ b/src/google/protobuf/util/field_comparator.h @@ -91,9 +91,9 @@ class LIBPROTOBUF_EXPORT FieldComparator { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator); }; -// Basic implementation of FieldComparator. Supports four modes of floating +// Basic implementation of FieldComparator. Supports three modes of floating // point value comparison: exact, approximate using MathUtil::AlmostEqual -// method, and arbitrarilly precise using MathUtil::WithinFractionOrMargin. +// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin. class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator { public: enum FloatComparison { diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc index 23f7d51d..6fd631d8 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -42,7 +42,6 @@ // and the opensource version gtest.h header includes cmath transitively // somehow. #include <gtest/gtest.h> - namespace google { namespace protobuf { namespace util { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc index c59f43aa..547c9fb5 100644 --- a/src/google/protobuf/util/field_mask_util.cc +++ b/src/google/protobuf/util/field_mask_util.cc @@ -52,6 +52,82 @@ void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { } } +bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) { + output->clear(); + bool after_underscore = false; + for (int i = 0; i < input.size(); ++i) { + if (input[i] >= 'A' && input[i] <= 'Z') { + // The field name must not contain uppercase letters. + return false; + } + if (after_underscore) { + if (input[i] >= 'a' && input[i] <= 'z') { + output->push_back(input[i] + 'A' - 'a'); + after_underscore = false; + } else { + // The character after a "_" must be a lowercase letter. + return false; + } + } else if (input[i] == '_') { + after_underscore = true; + } else { + output->push_back(input[i]); + } + } + if (after_underscore) { + // Trailing "_". + return false; + } + return true; +} + +bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) { + output->clear(); + for (int i = 0; i < input.size(); ++i) { + if (input[i] == '_') { + // The field name must not contain "_"s. + return false; + } + if (input[i] >= 'A' && input[i] <= 'Z') { + output->push_back('_'); + output->push_back(input[i] + 'a' - 'A'); + } else { + output->push_back(input[i]); + } + } + return true; +} + +bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) { + out->clear(); + for (int i = 0; i < mask.paths_size(); ++i) { + const string& path = mask.paths(i); + string camelcase_path; + if (!SnakeCaseToCamelCase(path, &camelcase_path)) { + return false; + } + if (i > 0) { + out->push_back(','); + } + out->append(camelcase_path); + } + return true; +} + +bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { + out->Clear(); + vector<string> paths = Split(str, ","); + for (int i = 0; i < paths.size(); ++i) { + if (paths[i].empty()) continue; + string snakecase_path; + if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) { + return false; + } + out->add_paths(snakecase_path); + } + return true; +} + bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, StringPiece path) { vector<string> parts = Split(path, "."); diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h index 92f69893..644161b9 100644 --- a/src/google/protobuf/util/field_mask_util.h +++ b/src/google/protobuf/util/field_mask_util.h @@ -45,11 +45,18 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { typedef google::protobuf::FieldMask FieldMask; public: - // Converts FieldMask to/from string, formatted according to proto3 JSON - // spec for FieldMask (e.g., "foo,bar,baz.quz"). + // Converts FieldMask to/from string, formatted by separating each path + // with a comma (e.g., "foo_bar,baz.quz"). static string ToString(const FieldMask& mask); static void FromString(StringPiece str, FieldMask* out); + // Converts FieldMask to/from string, formatted according to proto3 JSON + // spec for FieldMask (e.g., "fooBar,baz.quz"). If the field name is not + // style conforming (i.e., not snake_case when converted to string, or not + // camelCase when converted from string), the conversion will fail. + static bool ToJsonString(const FieldMask& mask, string* out); + static bool FromJsonString(StringPiece str, FieldMask* out); + // Checks whether the given path is valid for type T. template <typename T> static bool IsValidPath(StringPiece path) { @@ -105,6 +112,35 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { const MergeOptions& options, Message* destination); private: + friend class SnakeCaseCamelCaseTest; + // Converts a field name from snake_case to camelCase: + // 1. Every character after "_" will be converted to uppercase. + // 2. All "_"s are removed. + // The conversion will fail if: + // 1. The field name contains uppercase letters. + // 2. Any character after a "_" is not a lowercase letter. + // If the conversion succeeds, it's guaranteed that the resulted + // camelCase name will yield the original snake_case name when + // converted using CamelCaseToSnakeCase(). + // + // Note that the input can contain characters not allowed in C identifiers. + // For example, "foo_bar,baz_quz" will be converted to "fooBar,bazQuz" + // successfully. + static bool SnakeCaseToCamelCase(StringPiece input, string* output); + // Converts a field name from camelCase to snake_case: + // 1. Every uppercase letter is converted to lowercase with a additional + // preceding "-". + // The conversion will fail if: + // 1. The field name contains "_"s. + // If the conversion succeeds, it's guaranteed that the resulted + // snake_case name will yield the original camelCase name when + // converted using SnakeCaseToCamelCase(). + // + // Note that the input can contain characters not allowed in C identifiers. + // For example, "fooBar,bazQuz" will be converted to "foo_bar,baz_quz" + // successfully. + static bool CamelCaseToSnakeCase(StringPiece input, string* output); + static bool InternalIsValidPath(const Descriptor* descriptor, StringPiece path); diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc index a9523250..9b7fb62a 100644 --- a/src/google/protobuf/util/field_mask_util_test.cc +++ b/src/google/protobuf/util/field_mask_util_test.cc @@ -30,6 +30,10 @@ #include <google/protobuf/util/field_mask_util.h> +#include <algorithm> + +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/common.h> #include <google/protobuf/field_mask.pb.h> #include <google/protobuf/unittest.pb.h> #include <google/protobuf/test_util.h> @@ -38,8 +42,77 @@ namespace google { namespace protobuf { namespace util { + +class SnakeCaseCamelCaseTest : public ::testing::Test { + protected: + string SnakeCaseToCamelCase(const string& input) { + string output; + if (FieldMaskUtil::SnakeCaseToCamelCase(input, &output)) { + return output; + } else { + return "#FAIL#"; + } + } + + string CamelCaseToSnakeCase(const string& input) { + string output; + if (FieldMaskUtil::CamelCaseToSnakeCase(input, &output)) { + return output; + } else { + return "#FAIL#"; + } + } +}; + namespace { +TEST_F(SnakeCaseCamelCaseTest, SnakeToCamel) { + EXPECT_EQ("fooBar", SnakeCaseToCamelCase("foo_bar")); + EXPECT_EQ("FooBar", SnakeCaseToCamelCase("_foo_bar")); + EXPECT_EQ("foo3Bar", SnakeCaseToCamelCase("foo3_bar")); + // No uppercase letter is allowed. + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("Foo")); + // Any character after a "_" must be a lowercase letter. + // 1. "_" cannot be followed by another "_". + // 2. "_" cannot be followed by a digit. + // 3. "_" cannot appear as the last character. + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo__bar")); + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_3bar")); + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_bar_")); +} + +TEST_F(SnakeCaseCamelCaseTest, CamelToSnake) { + EXPECT_EQ("foo_bar", CamelCaseToSnakeCase("fooBar")); + EXPECT_EQ("_foo_bar", CamelCaseToSnakeCase("FooBar")); + EXPECT_EQ("foo3_bar", CamelCaseToSnakeCase("foo3Bar")); + // "_"s are not allowed. + EXPECT_EQ("#FAIL#", CamelCaseToSnakeCase("foo_bar")); +} + +TEST_F(SnakeCaseCamelCaseTest, RoundTripTest) { + // Enumerates all possible snake_case names and test that converting it to + // camelCase and then to snake_case again will yield the original name. + string name = "___abc123"; + std::sort(name.begin(), name.end()); + do { + string camelName = SnakeCaseToCamelCase(name); + if (camelName != "#FAIL#") { + EXPECT_EQ(name, CamelCaseToSnakeCase(camelName)); + } + } while (std::next_permutation(name.begin(), name.end())); + + // Enumerates all possible camelCase names and test that converting it to + // snake_case and then to camelCase again will yield the original name. + name = "abcABC123"; + std::sort(name.begin(), name.end()); + do { + string camelName = CamelCaseToSnakeCase(name); + if (camelName != "#FAIL#") { + EXPECT_EQ(name, SnakeCaseToCamelCase(camelName)); + } + } while (std::next_permutation(name.begin(), name.end())); +} + using protobuf_unittest::TestAllTypes; using protobuf_unittest::NestedTestAllTypes; using google::protobuf::FieldMask; @@ -47,20 +120,43 @@ using google::protobuf::FieldMask; TEST(FieldMaskUtilTest, StringFormat) { FieldMask mask; EXPECT_EQ("", FieldMaskUtil::ToString(mask)); - mask.add_paths("foo"); - EXPECT_EQ("foo", FieldMaskUtil::ToString(mask)); - mask.add_paths("bar"); - EXPECT_EQ("foo,bar", FieldMaskUtil::ToString(mask)); + mask.add_paths("foo_bar"); + EXPECT_EQ("foo_bar", FieldMaskUtil::ToString(mask)); + mask.add_paths("baz_quz"); + EXPECT_EQ("foo_bar,baz_quz", FieldMaskUtil::ToString(mask)); FieldMaskUtil::FromString("", &mask); EXPECT_EQ(0, mask.paths_size()); - FieldMaskUtil::FromString("foo", &mask); + FieldMaskUtil::FromString("fooBar", &mask); + EXPECT_EQ(1, mask.paths_size()); + EXPECT_EQ("fooBar", mask.paths(0)); + FieldMaskUtil::FromString("fooBar,bazQuz", &mask); + EXPECT_EQ(2, mask.paths_size()); + EXPECT_EQ("fooBar", mask.paths(0)); + EXPECT_EQ("bazQuz", mask.paths(1)); +} + +TEST(FieldMaskUtilTest, JsonStringFormat) { + FieldMask mask; + string value; + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("", value); + mask.add_paths("foo_bar"); + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("fooBar", value); + mask.add_paths("bar_quz"); + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("fooBar,barQuz", value); + + FieldMaskUtil::FromJsonString("", &mask); + EXPECT_EQ(0, mask.paths_size()); + FieldMaskUtil::FromJsonString("fooBar", &mask); EXPECT_EQ(1, mask.paths_size()); - EXPECT_EQ("foo", mask.paths(0)); - FieldMaskUtil::FromString("foo,bar", &mask); + EXPECT_EQ("foo_bar", mask.paths(0)); + FieldMaskUtil::FromJsonString("fooBar,bazQuz", &mask); EXPECT_EQ(2, mask.paths_size()); - EXPECT_EQ("foo", mask.paths(0)); - EXPECT_EQ("bar", mask.paths(1)); + EXPECT_EQ("foo_bar", mask.paths(0)); + EXPECT_EQ("baz_quz", mask.paths(1)); } TEST(FieldMaskUtilTest, TestIsVaildPath) { diff --git a/src/google/protobuf/util/internal/constants.h b/src/google/protobuf/util/internal/constants.h index 0cb8f6e1..e556888c 100644 --- a/src/google/protobuf/util/internal/constants.h +++ b/src/google/protobuf/util/internal/constants.h @@ -43,13 +43,23 @@ namespace converter { const char kTypeServiceBaseUrl[] = "type.googleapis.com"; // Format string for RFC3339 timestamp formatting. -const char kRfc3339TimeFormat[] = "%Y-%m-%dT%H:%M:%S"; +const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S"; -// Minimum seconds allowed in a google.protobuf.TimeStamp or Duration value. -const int64 kMinSeconds = -315576000000; +// Same as above, but the year value is not zero-padded i.e. this accepts +// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z". +const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S"; -// Maximum seconds allowed in a google.protobuf.TimeStamp or Duration value. -const int64 kMaxSeconds = 315576000000; +// Minimun seconds allowed in a google.protobuf.Timestamp value. +const int64 kTimestampMinSeconds = -62135596800; + +// Maximum seconds allowed in a google.protobuf.Timestamp value. +const int64 kTimestampMaxSeconds = 253402300799; + +// Minimum seconds allowed in a google.protobuf.Duration value. +const int64 kDurationMinSeconds = -315576000000; + +// Maximum seconds allowed in a google.protobuf.Duration value. +const int64 kDurationMaxSeconds = 315576000000; // Nano seconds in a second. const int32 kNanosPerSecond = 1000000000; diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index b557429f..72c0aca6 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -47,6 +47,7 @@ using google::protobuf::EnumDescriptor; using google::protobuf::EnumValueDescriptor; ; ; +; using util::error::Code; using util::Status; using util::StatusOr; @@ -248,11 +249,8 @@ StatusOr<string> DataPiece::ToBytes() const { if (type_ == TYPE_BYTES) return str_.ToString(); if (type_ == TYPE_STRING) { string decoded; - if (!WebSafeBase64Unescape(str_, &decoded)) { - if (!Base64Unescape(str_, &decoded)) { - return InvalidArgument( - ValueAsStringOrDefault("Invalid data in input.")); - } + if (!DecodeBase64(str_, &decoded)) { + return InvalidArgument(ValueAsStringOrDefault("Invalid data in input.")); } return decoded; } else { @@ -313,11 +311,49 @@ StatusOr<To> DataPiece::GenericConvert() const { template <typename To> StatusOr<To> DataPiece::StringToNumber(bool (*func)(StringPiece, To*)) const { + if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) { + return InvalidArgument(StrCat("\"", str_, "\"")); + } To result; if (func(str_, &result)) return result; return InvalidArgument(StrCat("\"", str_.ToString(), "\"")); } +bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { + // Try web-safe decode first, if it fails, try the non-web-safe decode. + if (WebSafeBase64Unescape(src, dest)) { + if (use_strict_base64_decoding_) { + // In strict mode, check if the escaped version gives us the same value as + // unescaped. + string encoded; + // WebSafeBase64Escape does no padding by default. + WebSafeBase64Escape(*dest, &encoded); + // Remove trailing padding '=' characters before comparison. + StringPiece src_no_padding(src, 0, src.ends_with("=") + ? src.find_last_not_of('=') + 1 + : src.length()); + return encoded == src_no_padding; + } + return true; + } + + if (Base64Unescape(src, dest)) { + if (use_strict_base64_decoding_) { + string encoded; + Base64Escape( + reinterpret_cast<const unsigned char*>(dest->data()), dest->length(), + &encoded, false); + StringPiece src_no_padding(src, 0, src.ends_with("=") + ? src.find_last_not_of('=') + 1 + : src.length()); + return encoded == src_no_padding; + } + return true; + } + + return false; +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h index f22bfe70..8b2e35d3 100644 --- a/src/google/protobuf/util/internal/datapiece.h +++ b/src/google/protobuf/util/internal/datapiece.h @@ -83,12 +83,15 @@ class LIBPROTOBUF_EXPORT DataPiece { explicit DataPiece(const double value) : type_(TYPE_DOUBLE), double_(value) {} explicit DataPiece(const float value) : type_(TYPE_FLOAT), float_(value) {} explicit DataPiece(const bool value) : type_(TYPE_BOOL), bool_(value) {} - explicit DataPiece(StringPiece value) + DataPiece(StringPiece value, bool use_strict_base64_decoding) : type_(TYPE_STRING), - str_(StringPiecePod::CreateFromStringPiece(value)) {} + str_(StringPiecePod::CreateFromStringPiece(value)), + use_strict_base64_decoding_(use_strict_base64_decoding) {} // Constructor for bytes. The second parameter is not used. - explicit DataPiece(StringPiece value, bool dummy) - : type_(TYPE_BYTES), str_(StringPiecePod::CreateFromStringPiece(value)) {} + DataPiece(StringPiece value, bool dummy, bool use_strict_base64_decoding) + : type_(TYPE_BYTES), + str_(StringPiecePod::CreateFromStringPiece(value)), + use_strict_base64_decoding_(use_strict_base64_decoding) {} DataPiece(const DataPiece& r) : type_(r.type_), str_(r.str_) {} DataPiece& operator=(const DataPiece& x) { type_ = x.type_; @@ -165,32 +168,13 @@ class LIBPROTOBUF_EXPORT DataPiece { template <typename To> util::StatusOr<To> StringToNumber(bool (*func)(StringPiece, To*)) const; + // Decodes a base64 string. Returns true on success. + bool DecodeBase64(StringPiece src, string* dest) const; + // Data type for this piece of data. Type type_; - // StringPiece is not a POD and can not be used in an union (pre C++11). We - // need a POD version of it. - struct StringPiecePod { - const char* data; - int size; - - // Create from a StringPiece. - static StringPiecePod CreateFromStringPiece(StringPiece str) { - StringPiecePod pod; - pod.data = str.data(); - pod.size = str.size(); - return pod; - } - - // Cast to StringPiece. - operator StringPiece() const { return StringPiece(data, size); } - - bool operator==(const char* value) const { - return StringPiece(data, size) == StringPiece(value); - } - - string ToString() const { return string(data, size); } - }; + typedef ::google::protobuf::internal::StringPiecePod StringPiecePod; // Stored piece of data. union { @@ -203,6 +187,9 @@ class LIBPROTOBUF_EXPORT DataPiece { bool bool_; StringPiecePod str_; }; + + // Uses a stricter version of base64 decoding for byte fields. + bool use_strict_base64_decoding_; }; } // namespace converter diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index a63e560d..21d7a2e4 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -51,7 +51,7 @@ template <typename T> T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const, T default_value) { if (value.empty()) return default_value; - StatusOr<T> result = (DataPiece(value).*converter_fn)(); + StatusOr<T> result = (DataPiece(value, true).*converter_fn)(); return result.ok() ? result.ValueOrDie() : default_value; } } // namespace @@ -64,6 +64,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( type_(type), current_(NULL), root_(NULL), + field_scrub_callback_(NULL), ow_(ow) {} DefaultValueObjectWriter::~DefaultValueObjectWriter() { @@ -153,7 +154,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( // Since StringPiece is essentially a pointer, takes a copy of "value" to // avoid ownership issues. string_values_.push_back(new string(value.ToString())); - RenderDataPiece(name, DataPiece(*string_values_.back())); + RenderDataPiece(name, DataPiece(*string_values_.back(), true)); } return this; } @@ -163,7 +164,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( if (current_ == NULL) { ow_->RenderBytes(name, value); } else { - RenderDataPiece(name, DataPiece(value)); + RenderDataPiece(name, DataPiece(value, false, true)); } return this; } @@ -178,16 +179,25 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( return this; } +void DefaultValueObjectWriter::RegisterFieldScrubCallBack( + FieldScrubCallBackPtr field_scrub_callback) { + field_scrub_callback_.reset(field_scrub_callback.release()); +} + DefaultValueObjectWriter::Node::Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, - bool is_placeholder) + bool is_placeholder, + const vector<string>& path, + FieldScrubCallBack* field_scrub_callback) : name_(name), type_(type), kind_(kind), is_any_(false), data_(data), - is_placeholder_(is_placeholder) {} + is_placeholder_(is_placeholder), + path_(path), + field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( StringPiece name) { @@ -291,6 +301,19 @@ void DefaultValueObjectWriter::Node::PopulateChildren( for (int i = 0; i < type_->fields_size(); ++i) { const google::protobuf::Field& field = type_->fields(i); + + // This code is checking if the field to be added to the tree should be + // scrubbed or not by calling the field_scrub_callback_ callback function. + vector<string> path; + if (!path_.empty()) { + path.insert(path.begin(), path_.begin(), path_.end()); + } + path.push_back(field.name()); + if (field_scrub_callback_ != NULL && + field_scrub_callback_->Run(path, &field)) { + continue; + } + hash_map<string, int>::iterator found = orig_children_map.find(field.name()); // If the child field has already been set, we just add it to the new list @@ -343,7 +366,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( field.json_name(), field_type, kind, kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) : DataPiece::NullData(), - true)); + true, path, field_scrub_callback_)); new_children.push_back(child.release()); } // Adds all leftover nodes in children_ to the beginning of new_child. @@ -368,7 +391,8 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { DataPiece DefaultValueObjectWriter::FindEnumDefault( const google::protobuf::Field& field, const TypeInfo* typeinfo) { - if (!field.default_value().empty()) return DataPiece(field.default_value()); + if (!field.default_value().empty()) + return DataPiece(field.default_value(), true); const google::protobuf::Enum* enum_type = typeinfo->GetEnumByTypeUrl(field.type_url()); @@ -379,7 +403,7 @@ DataPiece DefaultValueObjectWriter::FindEnumDefault( } // We treat the first value as the default if none is specified. return enum_type->enumvalue_size() > 0 - ? DataPiece(enum_type->enumvalue(0).name()) + ? DataPiece(enum_type->enumvalue(0).name(), true) : DataPiece::NullData(); } @@ -416,10 +440,10 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false)); } case google::protobuf::Field_Kind_TYPE_STRING: { - return DataPiece(field.default_value()); + return DataPiece(field.default_value(), true); } case google::protobuf::Field_Kind_TYPE_BYTES: { - return DataPiece(field.default_value(), false); + return DataPiece(field.default_value(), false, true); } case google::protobuf::Field_Kind_TYPE_UINT32: case google::protobuf::Field_Kind_TYPE_FIXED32: { @@ -436,8 +460,9 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( StringPiece name) { if (current_ == NULL) { + vector<string> path; root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), - false)); + false, path, field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; @@ -451,7 +476,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP) ? current_->type() : NULL), - OBJECT, DataPiece::NullData(), false)); + OBJECT, DataPiece::NullData(), false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -480,8 +507,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( StringPiece name) { if (current_ == NULL) { - root_.reset( - new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false)); + vector<string> path; + root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), + false, path, field_scrub_callback_.get())); current_ = root_.get(); return this; } @@ -489,7 +517,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( Node* child = current_->FindChild(name); if (child == NULL || child->kind() != LIST) { google::protobuf::scoped_ptr<Node> node( - new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false)); + new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -545,7 +575,9 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, if (child == NULL || child->kind() != PRIMITIVE) { // No children are found, creates a new child. google::protobuf::scoped_ptr<Node> node( - new Node(name.ToString(), NULL, PRIMITIVE, data, false)); + new Node(name.ToString(), NULL, PRIMITIVE, data, false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } else { diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 695b9dd8..1d85bed8 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -38,6 +38,7 @@ #include <stack> #include <vector> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/util/internal/type_info.h> #include <google/protobuf/util/internal/datapiece.h> @@ -59,6 +60,25 @@ namespace converter { // with their default values (0 for numbers, "" for strings, etc). class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { public: + // A Callback function to check whether a field needs to be scrubbed. + // + // Returns true if the field should not be present in the output. Returns + // false otherwise. + // + // The 'path' parameter is a vector of path to the field from root. For + // example: if a nested field "a.b.c" (b is the parent message field of c and + // a is the parent message field of b), then the vector should contain { "a", + // "b", "c" }. + // + // The Field* should point to the google::protobuf::Field of "c". + typedef ResultCallback2<bool /*return*/, + const std::vector<string>& /*path of the field*/, + const google::protobuf::Field* /*field*/> + FieldScrubCallBack; + + // A unique pointer to a DefaultValueObjectWriter::FieldScrubCallBack. + typedef google::protobuf::scoped_ptr<FieldScrubCallBack> FieldScrubCallBackPtr; + DefaultValueObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, ObjectWriter* ow); @@ -98,6 +118,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { virtual DefaultValueObjectWriter* RenderNull(StringPiece name); + // Register the callback for scrubbing of fields. Owership of + // field_scrub_callback pointer is also transferred to this class + void RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback); + private: enum NodeKind { PRIMITIVE = 0, @@ -111,7 +135,8 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { class LIBPROTOBUF_EXPORT Node { public: Node(const string& name, const google::protobuf::Type* type, NodeKind kind, - const DataPiece& data, bool is_placeholder); + const DataPiece& data, bool is_placeholder, const vector<string>& path, + FieldScrubCallBack* field_scrub_callback); virtual ~Node() { for (int i = 0; i < children_.size(); ++i) { delete children_[i]; @@ -137,17 +162,19 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Accessors const string& name() const { return name_; } - const google::protobuf::Type* type() { return type_; } + const vector<string>& path() const { return path_; } + + const google::protobuf::Type* type() const { return type_; } void set_type(const google::protobuf::Type* type) { type_ = type; } - NodeKind kind() { return kind_; } + NodeKind kind() const { return kind_; } - int number_of_children() { return children_.size(); } + int number_of_children() const { return children_.size(); } void set_data(const DataPiece& data) { data_ = data; } - bool is_any() { return is_any_; } + bool is_any() const { return is_any_; } void set_is_any(bool is_any) { is_any_ = is_any; } @@ -181,6 +208,15 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // the parent node's StartObject()/StartList() method is called with this // node's name. bool is_placeholder_; + + // Path of the field of this node + std::vector<string> path_; + + // Pointer to function for determining whether a field needs to be scrubbed + // or not. This callback is owned by the creator of this node. + FieldScrubCallBack* field_scrub_callback_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node); }; // Populates children of "node" if it is an "any" Node and its real type has @@ -221,6 +257,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // The stack to hold the path of Nodes from current_ to root_; std::stack<Node*> stack_; + // Unique Pointer to function for determining whether a field needs to be + // scrubbed or not. + FieldScrubCallBackPtr field_scrub_callback_; + ObjectWriter* ow_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultValueObjectWriter); diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index 94d2ab7a..b84210c1 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -46,6 +46,7 @@ namespace util { namespace converter { using strings::ArrayByteSource; +; JsonObjectWriter::~JsonObjectWriter() { if (!element_->is_root()) { @@ -81,13 +82,11 @@ JsonObjectWriter* JsonObjectWriter::EndList() { return this; } -JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, - bool value) { +JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, bool value) { return RenderSimple(name, value ? "true" : "false"); } -JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, - int32 value) { +JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, int32 value) { return RenderSimple(name, SimpleItoa(value)); } @@ -96,8 +95,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name, return RenderSimple(name, SimpleItoa(value)); } -JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, - int64 value) { +JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, int64 value) { WritePrefix(name); WriteChar('"'); stream_->WriteString(SimpleItoa(value)); @@ -124,8 +122,7 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, return RenderString(name, DoubleAsString(value)); } -JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, - float value) { +JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) { if (MathLimits<float>::IsFinite(value)) { return RenderSimple(name, SimpleFtoa(value)); } @@ -148,7 +145,12 @@ JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name, StringPiece value) { WritePrefix(name); string base64; - Base64Escape(value, &base64); + + if (use_websafe_base64_for_bytes_) + WebSafeBase64Escape(value.ToString(), &base64); + else + Base64Escape(value, &base64); + WriteChar('"'); // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes // directly to the stream, rather than first putting them diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h index 761a0a10..cb7e2fb3 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.h +++ b/src/google/protobuf/util/internal/json_objectwriter.h @@ -90,9 +90,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { JsonObjectWriter(StringPiece indent_string, google::protobuf::io::CodedOutputStream* out) : element_(new Element(NULL)), - stream_(out), sink_(out), - indent_string_(indent_string.ToString()) { - } + stream_(out), + sink_(out), + indent_string_(indent_string.ToString()), + use_websafe_base64_for_bytes_(false) {} virtual ~JsonObjectWriter(); // ObjectWriter methods. @@ -111,6 +112,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value); virtual JsonObjectWriter* RenderNull(StringPiece name); + void set_use_websafe_base64_for_bytes(bool value) { + use_websafe_base64_for_bytes_ = value; + } + protected: class LIBPROTOBUF_EXPORT Element : public BaseElement { public: @@ -195,6 +200,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { ByteSinkWrapper sink_; const string indent_string_; + // Whether to use regular or websafe base64 encoding for byte fields. Defaults + // to regular base64 encoding. + bool use_websafe_base64_for_bytes_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter); }; diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index 9d820162..b87b06ac 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -58,7 +58,7 @@ class JsonObjectWriterTest : public ::testing::Test { string output_; StringOutputStream* const str_stream_; CodedOutputStream* const out_stream_; - ObjectWriter* ow_; + JsonObjectWriter* ow_; }; TEST_F(JsonObjectWriterTest, EmptyRootObject) { @@ -283,6 +283,30 @@ TEST_F(JsonObjectWriterTest, Stringification) { output_.substr(0, out_stream_->ByteCount())); } +TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) { + ow_ = new JsonObjectWriter("", out_stream_); + ow_->StartObject("") + ->RenderBytes("bytes", "\x03\xef\xc0") + ->EndObject(); + + // Test that we get regular (non websafe) base64 encoding on byte fields by + // default. + EXPECT_EQ("{\"bytes\":\"A+/A\"}", + output_.substr(0, out_stream_->ByteCount())); +} + +TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) { + ow_ = new JsonObjectWriter("", out_stream_); + ow_->set_use_websafe_base64_for_bytes(true); + ow_->StartObject("") + ->RenderBytes("bytes", "\x03\xef\xc0") + ->EndObject(); + + // Test that we get websafe base64 encoding when explicitly asked. + EXPECT_EQ("{\"bytes\":\"A-_A\"}", + output_.substr(0, out_stream_->ByteCount())); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index df916751..39be7b03 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -42,8 +42,9 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/util/internal/object_writer.h> +#include <google/protobuf/util/internal/json_escaping.h> +#include <google/protobuf/stubs/strutil.h> namespace google { namespace protobuf { @@ -59,7 +60,7 @@ using util::error::INVALID_ARGUMENT; namespace converter { -// Number of digits in a unicode escape sequence (/uXXXX) +// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X) static const int kUnicodeEscapedLength = 6; // Length of the true, false, and null literals. @@ -419,9 +420,45 @@ util::Status JsonStreamParser::ParseUnicodeEscape() { } code = (code << 4) + hex_digit_to_int(p_.data()[i]); } + if (code >= JsonEscaping::kMinHighSurrogate && + code <= JsonEscaping::kMaxHighSurrogate) { + if (p_.length() < 2 * kUnicodeEscapedLength) { + if (!finishing_) { + return util::Status::CANCELLED; + } + if (!coerce_to_utf8_) { + return ReportFailure("Missing low surrogate."); + } + } else if (p_.data()[kUnicodeEscapedLength] == '\\' && + p_.data()[kUnicodeEscapedLength + 1] == 'u') { + uint32 low_code = 0; + for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength; + ++i) { + if (!isxdigit(p_.data()[i])) { + return ReportFailure("Invalid escape sequence."); + } + low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]); + } + if (low_code >= JsonEscaping::kMinLowSurrogate && + low_code <= JsonEscaping::kMaxLowSurrogate) { + // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint. + code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) + + JsonEscaping::kMinSupplementaryCodePoint; + // Advance past the first code unit escape. + p_.remove_prefix(kUnicodeEscapedLength); + } else if (!coerce_to_utf8_) { + return ReportFailure("Invalid low surrogate."); + } + } else if (!coerce_to_utf8_) { + return ReportFailure("Missing low surrogate."); + } + } + if (!coerce_to_utf8_ && !IsValidCodePoint(code)) { + return ReportFailure("Invalid unicode code point."); + } char buf[UTFmax]; int len = EncodeAsUTF8Char(code, buf); - // Advance past the unicode escape. + // Advance past the [final] code unit escape. p_.remove_prefix(kUnicodeEscapedLength); parsed_storage_.append(buf, len); return util::Status::OK; @@ -473,7 +510,7 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { floating = true; continue; } - if (c == '+' || c == '-') continue; + if (c == '+' || c == '-' || c == 'x') continue; // Not a valid number character, break out. break; } @@ -499,6 +536,10 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { // Positive non-floating point number, parse as a uint64. if (!negative) { + // Octal/Hex numbers are not valid JSON values. + if (number.length() >= 2 && number[0] == '0') { + return ReportFailure("Octal/hex numbers are not valid JSON values."); + } if (!safe_strtou64(number, &result->uint_val)) { return ReportFailure("Unable to parse number."); } @@ -507,6 +548,10 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { return util::Status::OK; } + // Octal/Hex numbers are not valid JSON values. + if (number.length() >= 3 && number[1] == '0') { + return ReportFailure("Octal/hex numbers are not valid JSON values."); + } // Negative non-floating point number, parse as an int64. if (!safe_strto64(number, &result->int_val)) { return ReportFailure("Unable to parse number."); @@ -677,8 +722,9 @@ util::Status JsonStreamParser::ReportFailure(StringPiece message) { static const int kContextLength = 20; const char* p_start = p_.data(); const char* json_start = json_.data(); - const char* begin = max(p_start - kContextLength, json_start); - const char* end = min(p_start + kContextLength, json_start + json_.size()); + const char* begin = std::max(p_start - kContextLength, json_start); + const char* end = + std::min(p_start + kContextLength, json_start + json_.size()); StringPiece segment(begin, end - begin); string location(p_start - begin, ' '); location.push_back('^'); @@ -706,8 +752,8 @@ void JsonStreamParser::SkipWhitespace() { void JsonStreamParser::Advance() { // Advance by moving one UTF8 character while making sure we don't go beyond // the length of StringPiece. - p_.remove_prefix( - min<int>(p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length()))); + p_.remove_prefix(std::min<int>( + p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length()))); } util::Status JsonStreamParser::ParseKey() { diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc index 3414826e..059ea6d8 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -124,8 +124,9 @@ class JsonStreamParserTest : public ::testing::Test { EXPECT_OK(result); } - void DoErrorTest(StringPiece json, int split, StringPiece error_prefix) { - util::Status result = RunTest(json, split); + void DoErrorTest(StringPiece json, int split, StringPiece error_prefix, + bool coerce_utf8 = false) { + util::Status result = RunTest(json, split, coerce_utf8); EXPECT_EQ(util::error::INVALID_ARGUMENT, result.error_code()); StringPiece error_message(result.error_message()); EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size())); @@ -230,6 +231,32 @@ TEST_F(JsonStreamParserTest, SimpleUnsignedInt) { } } +TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) { + StringPiece str = "01234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "-01234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } +} + +TEST_F(JsonStreamParserTest, HexNumberIsInvalid) { + StringPiece str = "0x1234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "-0x1234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "12x34"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Unable to parse number."); + } +} + // - single and double quoted strings TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) { StringPiece str = "\"\""; @@ -351,19 +378,62 @@ TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points."); } -#ifndef _MSC_VER // - unicode handling in strings TEST_F(JsonStreamParserTest, UnicodeEscaping) { StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; for (int i = 0; i <= str.length(); ++i) { - // TODO(xiaofeng): Figure out what default encoding to use for JSON strings. - // In protobuf we use UTF-8 for strings, but for JSON we probably should - // allow different encodings? - ow_.StartList("")->RenderString("", "\u0639\u0631\u0628\u0649")->EndList(); + ow_.StartList("") + ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89") + ->EndList(); + DoTest(str, i); + } +} + +// - unicode UTF-16 surrogate pair handling in strings +TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) { + StringPiece str = + "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]"; + for (int i = 0; i <= str.length(); ++i) { + ow_.StartList("") + ->RenderString("", + "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0" + "\x9F\x90\x9D\xF0\x9F\x8D\xAF") + ->EndList(); DoTest(str, i); } } -#endif + + +TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) { + // A low surrogate alone. + StringPiece str = "[\"\\ude36\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid unicode code point."); + } +} + +TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) { + // A high surrogate alone. + StringPiece str = "[\"\\ud83d\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Missing low surrogate."); + } + // A high surrogate with some trailing characters. + str = "[\"\\ud83d|ude36\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Missing low surrogate."); + } + // A high surrogate with half a low surrogate. + str = "[\"\\ud83d\\ude--\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } + // Two high surrogates. + str = "[\"\\ud83d\\ud83d\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid low surrogate."); + } +} // - ascii escaping (\b, \f, \n, \r, \t, \v) TEST_F(JsonStreamParserTest, AsciiEscaping) { @@ -629,6 +699,22 @@ TEST_F(JsonStreamParserTest, DoubleTooBig) { } */ +// invalid bare backslash. +TEST_F(JsonStreamParserTest, UnfinishedEscape) { + StringPiece str = "\"\\"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Closing quote expected in string."); + } +} + +// invalid bare backslash u. +TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) { + StringPiece str = "\"\\u"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Illegal hex string."); + } +} + // invalid unicode sequence. TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { StringPiece str = "\"\\u12"; @@ -637,6 +723,15 @@ TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { } } +// invalid unicode sequence (valid in modern EcmaScript but not in JSON). +TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) { + StringPiece str = "\"\\u{1f36f}\""; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } +} + + TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { StringPiece str = "\"\\u12$4hello"; for (int i = 0; i <= str.length(); ++i) { @@ -644,6 +739,14 @@ TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { } } +// invalid unicode sequence in low half surrogate: g is not a hex digit. +TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) { + StringPiece str = "\"\\ud800\\udcfg\""; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } +} + // Extra commas with an object or array. TEST_F(JsonStreamParserTest, ExtraCommaInObject) { StringPiece str = "{'k1': true,,'k2': false}"; diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h index e695f45e..9f07363d 100644 --- a/src/google/protobuf/util/internal/object_writer.h +++ b/src/google/protobuf/util/internal/object_writer.h @@ -105,10 +105,27 @@ class LIBPROTOBUF_EXPORT ObjectWriter { static void RenderDataPieceTo(const DataPiece& data, StringPiece name, ObjectWriter* ow); + // Indicates whether this ObjectWriter has completed writing the root message, + // usually this means writing of one complete object. Subclasses must override + // this behavior appropriately. + virtual bool done() { return false; } + + void set_use_strict_base64_decoding(bool value) { + use_strict_base64_decoding_ = value; + } + + bool use_strict_base64_decoding() const { + return use_strict_base64_decoding_; + } + protected: - ObjectWriter() {} + ObjectWriter() : use_strict_base64_decoding_(true) {} private: + // If set to true, we use the stricter version of base64 decoding for byte + // fields by making sure decoded version encodes back to the original string. + bool use_strict_base64_decoding_; + // Do not add any data members to this class. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter); }; diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc index 47e0009e..36b79410 100644 --- a/src/google/protobuf/util/internal/proto_writer.cc +++ b/src/google/protobuf/util/internal/proto_writer.cc @@ -447,9 +447,7 @@ ProtoWriter* ProtoWriter::StartObject(StringPiece name) { return this; } - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, false)); - return this; + return StartObjectField(*field, *type); } ProtoWriter* ProtoWriter::EndObject() { @@ -488,8 +486,7 @@ ProtoWriter* ProtoWriter::StartList(StringPiece name) { return this; } - element_.reset(new ProtoElement(element_.release(), field, *type, true)); - return this; + return StartListField(*field, *type); } ProtoWriter* ProtoWriter::EndList() { @@ -518,84 +515,128 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, return this; } + return RenderPrimitiveField(*field, *type, data); +} + +bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name) { + if (element_ == NULL) return true; + + if (field.oneof_index() > 0) { + if (element_->IsOneofIndexTaken(field.oneof_index())) { + InvalidValue( + "oneof", + StrCat("oneof field '", + element_->type().oneofs(field.oneof_index() - 1), + "' is already set. Cannot set '", unnormalized_name, "'")); + return false; + } + element_->TakeOneofIndex(field.oneof_index()); + } + return true; +} + +bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { + return field.cardinality() == + google::protobuf::Field_Cardinality_CARDINALITY_REPEATED; +} + +ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field, + const google::protobuf::Type& type) { + WriteTag(field); + element_.reset(new ProtoElement(element_.release(), &field, type, false)); + return this; +} + +ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field, + const google::protobuf::Type& type) { + element_.reset(new ProtoElement(element_.release(), &field, type, true)); + return this; +} + +ProtoWriter* ProtoWriter::RenderPrimitiveField( + const google::protobuf::Field& field, const google::protobuf::Type& type, + const DataPiece& data) { + Status status; + // Pushing a ProtoElement and then pop it off at the end for 2 purposes: // error location reporting and required field accounting. - element_.reset(new ProtoElement(element_.release(), field, *type, false)); + element_.reset(new ProtoElement(element_.release(), &field, type, false)); - if (field->kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || - field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { - InvalidValue(field->type_url().empty() - ? google::protobuf::Field_Kind_Name(field->kind()) - : field->type_url(), + if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || + field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { + InvalidValue(field.type_url().empty() + ? google::protobuf::Field_Kind_Name(field.kind()) + : field.type_url(), data.ValueAsStringOrDefault("")); element_.reset(element()->pop()); return this; } - switch (field->kind()) { + switch (field.kind()) { case google::protobuf::Field_Kind_TYPE_INT32: { - status = WriteInt32(field->number(), data, stream_.get()); + status = WriteInt32(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_SFIXED32: { - status = WriteSFixed32(field->number(), data, stream_.get()); + status = WriteSFixed32(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_SINT32: { - status = WriteSInt32(field->number(), data, stream_.get()); + status = WriteSInt32(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_FIXED32: { - status = WriteFixed32(field->number(), data, stream_.get()); + status = WriteFixed32(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_UINT32: { - status = WriteUInt32(field->number(), data, stream_.get()); + status = WriteUInt32(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_INT64: { - status = WriteInt64(field->number(), data, stream_.get()); + status = WriteInt64(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_SFIXED64: { - status = WriteSFixed64(field->number(), data, stream_.get()); + status = WriteSFixed64(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_SINT64: { - status = WriteSInt64(field->number(), data, stream_.get()); + status = WriteSInt64(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_FIXED64: { - status = WriteFixed64(field->number(), data, stream_.get()); + status = WriteFixed64(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_UINT64: { - status = WriteUInt64(field->number(), data, stream_.get()); + status = WriteUInt64(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_DOUBLE: { - status = WriteDouble(field->number(), data, stream_.get()); + status = WriteDouble(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_FLOAT: { - status = WriteFloat(field->number(), data, stream_.get()); + status = WriteFloat(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_BOOL: { - status = WriteBool(field->number(), data, stream_.get()); + status = WriteBool(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_BYTES: { - status = WriteBytes(field->number(), data, stream_.get()); + status = WriteBytes(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_STRING: { - status = WriteString(field->number(), data, stream_.get()); + status = WriteString(field.number(), data, stream_.get()); break; } case google::protobuf::Field_Kind_TYPE_ENUM: { - status = WriteEnum(field->number(), data, - typeinfo_->GetEnumByTypeUrl(field->type_url()), + status = WriteEnum(field.number(), data, + typeinfo_->GetEnumByTypeUrl(field.type_url()), stream_.get()); break; } @@ -604,7 +645,7 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, } if (!status.ok()) { - InvalidValue(google::protobuf::Field_Kind_Name(field->kind()), + InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), status.error_message()); } @@ -612,29 +653,6 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, return this; } -bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, - StringPiece unnormalized_name) { - if (element_ == NULL) return true; - - if (field.oneof_index() > 0) { - if (element_->IsOneofIndexTaken(field.oneof_index())) { - InvalidValue( - "oneof", - StrCat("oneof field '", - element_->type().oneofs(field.oneof_index() - 1), - "' is already set. Cannot set '", unnormalized_name, "'")); - return false; - } - element_->TakeOneofIndex(field.oneof_index()); - } - return true; -} - -bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { - return field.cardinality() == - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED; -} - const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, bool is_list) { if (invalid_depth_ > 0) { diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h index e631e56f..957565e7 100644 --- a/src/google/protobuf/util/internal/proto_writer.h +++ b/src/google/protobuf/util/internal/proto_writer.h @@ -106,10 +106,12 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) { - return RenderDataPiece(name, DataPiece(value)); + return RenderDataPiece(name, + DataPiece(value, use_strict_base64_decoding())); } virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { - return RenderDataPiece(name, DataPiece(value, false)); + return RenderDataPiece( + name, DataPiece(value, false, use_strict_base64_decoding())); } virtual ProtoWriter* RenderNull(StringPiece name) { return RenderDataPiece(name, DataPiece::NullData()); @@ -126,7 +128,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { } // When true, we finished writing to output a complete message. - bool done() const { return done_; } + bool done() { return done_; } // Returns the proto stream object. google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); } @@ -266,6 +268,19 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // Returns true if the field is repeated. bool IsRepeated(const google::protobuf::Field& field); + // Starts an object given the field and the enclosing type. + ProtoWriter* StartObjectField(const google::protobuf::Field& field, + const google::protobuf::Type& type); + + // Starts a list given the field and the enclosing type. + ProtoWriter* StartListField(const google::protobuf::Field& field, + const google::protobuf::Type& type); + + // Renders a primitve field given the field and the enclosing type. + ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field, + const google::protobuf::Type& type, + const DataPiece& value); + private: // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 034d616f..1f3781a4 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -70,6 +70,9 @@ using util::Status; using util::StatusOr; namespace { + +static int kDefaultMaxRecursionDepth = 64; + // Finds a field with the given number. NULL if none found. const google::protobuf::Field* FindFieldByNumber( const google::protobuf::Type& type, int number); @@ -83,6 +86,29 @@ const google::protobuf::EnumValue* FindEnumValueByNumber( // Utility function to format nanos. const string FormatNanos(uint32 nanos); + +StatusOr<string> MapKeyDefaultValueAsString( + const google::protobuf::Field& field) { + switch (field.kind()) { + case google::protobuf::Field_Kind_TYPE_BOOL: + return string("false"); + case google::protobuf::Field_Kind_TYPE_INT32: + case google::protobuf::Field_Kind_TYPE_INT64: + case google::protobuf::Field_Kind_TYPE_UINT32: + case google::protobuf::Field_Kind_TYPE_UINT64: + case google::protobuf::Field_Kind_TYPE_SINT32: + case google::protobuf::Field_Kind_TYPE_SINT64: + case google::protobuf::Field_Kind_TYPE_SFIXED32: + case google::protobuf::Field_Kind_TYPE_SFIXED64: + case google::protobuf::Field_Kind_TYPE_FIXED32: + case google::protobuf::Field_Kind_TYPE_FIXED64: + return string("0"); + case google::protobuf::Field_Kind_TYPE_STRING: + return string(); + default: + return Status(util::error::INTERNAL, "Invalid map key type."); + } +} } // namespace @@ -92,14 +118,23 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( : stream_(stream), typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), - type_(type) { + type_(type), + use_lower_camel_for_enums_(false), + recursion_depth_(0), + max_recursion_depth_(kDefaultMaxRecursionDepth) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } ProtoStreamObjectSource::ProtoStreamObjectSource( google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, const google::protobuf::Type& type) - : stream_(stream), typeinfo_(typeinfo), own_typeinfo_(false), type_(type) { + : stream_(stream), + typeinfo_(typeinfo), + own_typeinfo_(false), + type_(type), + use_lower_camel_for_enums_(false), + recursion_depth_(0), + max_recursion_depth_(kDefaultMaxRecursionDepth) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } @@ -238,9 +273,21 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap( map_key = ReadFieldValueAsString(*field); } else if (field->number() == 2) { if (map_key.empty()) { - return Status(util::error::INTERNAL, "Map key must be non-empty"); + // An absent map key is treated as the default. + const google::protobuf::Field* key_field = + FindFieldByNumber(*field_type, 1); + if (key_field == NULL) { + // The Type info for this map entry is incorrect. It should always + // have a field named "key" and with field number 1. + return Status(util::error::INTERNAL, "Invalid map entry."); + } + ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); } RETURN_IF_ERROR(RenderField(field, map_key, ow)); + } else { + // The Type info for this map entry is incorrect. It should contain + // exactly two fields with field number 1 and 2. + return Status(util::error::INTERNAL, "Invalid map entry."); } } stream_->PopLimit(old_limit); @@ -266,7 +313,7 @@ Status ProtoStreamObjectSource::RenderTimestamp( pair<int64, int32> p = os->ReadSecondsAndNanos(type); int64 seconds = p.first; int32 nanos = p.second; - if (seconds > kMaxSeconds || seconds < kMinSeconds) { + if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { return Status( util::error::INTERNAL, StrCat("Timestamp seconds exceeds limit for field: ", field_name)); @@ -290,7 +337,7 @@ Status ProtoStreamObjectSource::RenderDuration( pair<int64, int32> p = os->ReadSecondsAndNanos(type); int64 seconds = p.first; int32 nanos = p.second; - if (seconds > kMaxSeconds || seconds < kMinSeconds) { + if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { return Status( util::error::INTERNAL, StrCat("Duration seconds exceeds limit for field: ", field_name)); @@ -701,7 +748,9 @@ Status ProtoStreamObjectSource::RenderField( if (use_type_renderer) { RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow)); } else { + RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name)); RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); + --recursion_depth_; } if (!stream_->ConsumedEntireMessage()) { return Status(util::error::INVALID_ARGUMENT, @@ -807,7 +856,10 @@ Status ProtoStreamObjectSource::RenderNonMessageField( const google::protobuf::EnumValue* enum_value = FindEnumValueByNumber(*en, buffer32); if (enum_value != NULL) { - ow->RenderString(field_name, enum_value->name()); + if (use_lower_camel_for_enums_) + ow->RenderString(field_name, ToCamelCase(enum_value->name())); + else + ow->RenderString(field_name, enum_value->name()); } } else { GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); @@ -994,6 +1046,17 @@ std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( return std::pair<int64, int32>(signed_seconds, signed_nanos); } +Status ProtoStreamObjectSource::IncrementRecursionDepth( + StringPiece type_name, StringPiece field_name) const { + if (++recursion_depth_ > max_recursion_depth_) { + return Status( + util::error::INVALID_ARGUMENT, + StrCat("Message too deep. Max recursion depth reached for type '", + type_name, "', field '", field_name, "'")); + } + return Status::OK; +} + namespace { // TODO(skarvaje): Speed this up by not doing a linear scan. const google::protobuf::Field* FindFieldByNumber( diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 78defa1d..d7d4347b 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -82,6 +82,41 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { virtual util::Status NamedWriteTo(StringPiece name, ObjectWriter* ow) const; + // Sets whether or not to use lowerCamelCase casing for enum values. If set to + // false, enum values are output without any case conversions. + // + // For example, if we have an enum: + // enum Type { + // ACTION_AND_ADVENTURE = 1; + // } + // Type type = 20; + // + // And this option is set to true. Then the rendered "type" field will have + // the string "actionAndAdventure". + // { + // ... + // "type": "actionAndAdventure", + // ... + // } + // + // If set to false, the rendered "type" field will have the string + // "ACTION_AND_ADVENTURE". + // { + // ... + // "type": "ACTION_AND_ADVENTURE", + // ... + // } + void set_use_lower_camel_for_enums(bool value) { + use_lower_camel_for_enums_ = value; + } + + // Sets the max recursion depth of proto message to be deserialized. Proto + // messages over this depth will fail to be deserialized. + // Default value is 64. + void set_max_recursion_depth(int max_depth) { + max_recursion_depth_ = max_depth; + } + protected: // Writes a proto2 Message to the ObjectWriter. When the given end_tag is // found this method will complete, allowing it to be used for parsing both @@ -223,6 +258,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { std::pair<int64, int32> ReadSecondsAndNanos( const google::protobuf::Type& type) const; + // Helper function to check recursion depth and increment it. It will return + // Status::OK if the current depth is allowed. Otherwise an error is returned. + // type_name and field_name are used for error reporting. + util::Status IncrementRecursionDepth(StringPiece type_name, + StringPiece field_name) const; + // Input stream to read from. Ownership rests with the caller. google::protobuf::io::CodedInputStream* stream_; @@ -237,6 +278,15 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { const google::protobuf::Type& type_; + // Whether to render enums using lowerCamelCase. Defaults to false. + bool use_lower_camel_for_enums_; + + // Tracks current recursion depth. + mutable int recursion_depth_; + + // Maximum allowed recursion depth. + int max_recursion_depth_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource); }; diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 561f6763..3f6fdf97 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -50,6 +50,7 @@ #include <google/protobuf/util/internal/testdata/anys.pb.h> #include <google/protobuf/util/internal/testdata/maps.pb.h> #include <google/protobuf/util/internal/testdata/struct.pb.h> +#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h> #include <gtest/gtest.h> @@ -69,12 +70,15 @@ using google::protobuf::testing::Author; using google::protobuf::testing::BadAuthor; using google::protobuf::testing::BadNestedBook; using google::protobuf::testing::Book; +using google::protobuf::testing::Cyclic; using google::protobuf::testing::Book_Label; using google::protobuf::testing::NestedBook; using google::protobuf::testing::PackedPrimitive; using google::protobuf::testing::Primitive; using google::protobuf::testing::more_author; using google::protobuf::testing::maps::MapOut; +using google::protobuf::testing::maps::MapOutWireFormat; +using google::protobuf::testing::timestampduration::TimestampDuration; using google::protobuf::testing::anys::AnyOut; using google::protobuf::testing::anys::AnyM; using google::protobuf::testing::FieldMaskTest; @@ -92,7 +96,11 @@ string GetTypeUrl(const Descriptor* descriptor) { class ProtostreamObjectSourceTest : public ::testing::TestWithParam<testing::TypeInfoSource> { protected: - ProtostreamObjectSourceTest() : helper_(GetParam()), mock_(), ow_(&mock_) { + ProtostreamObjectSourceTest() + : helper_(GetParam()), + mock_(), + ow_(&mock_), + use_lower_camel_for_enums_(false) { helper_.ResetTypeInfo(Book::descriptor()); } @@ -112,6 +120,8 @@ class ProtostreamObjectSourceTest google::protobuf::scoped_ptr<ProtoStreamObjectSource> os( helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); + if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); + os->set_max_recursion_depth(64); return os->WriteTo(&mock_); } @@ -256,10 +266,13 @@ class ProtostreamObjectSourceTest return primitive; } + void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; } + testing::TypeInfoTestHelper helper_; ::testing::NiceMock<MockObjectWriter> mock_; ExpectingObjectWriter ow_; + bool use_lower_camel_for_enums_; }; INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, @@ -461,6 +474,52 @@ TEST_P(ProtostreamObjectSourceTest, DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + ow_.StartObject("") + ->RenderString("type", "ACTION_AND_ADVENTURE") + ->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) { + Cyclic cyclic; + cyclic.set_m_int(123); + + Book* book = cyclic.mutable_m_book(); + book->set_title("book title"); + Cyclic* current = cyclic.mutable_m_cyclic(); + Author* current_author = cyclic.add_m_author(); + for (int i = 0; i < 63; ++i) { + Author* next = current_author->add_friend_(); + next->set_id(i); + next->set_name(StrCat("author_name_", i)); + next->set_alive(true); + current_author = next; + } + + // Recursive message with depth (65) > max (max is 64). + for (int i = 0; i < 64; ++i) { + Cyclic* next = current->mutable_m_cyclic(); + next->set_m_str(StrCat("count_", i)); + current = next; + } + + Status status = ExecuteTest(cyclic, Cyclic::descriptor()); + EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code()); +} + class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceMapsTest() { @@ -541,6 +600,67 @@ TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { DoTest(out, MapOut::descriptor()); } +TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) { + // MapOutWireFormat has the same wire representation with MapOut but uses + // repeated message fields to represent map fields so we can intentionally + // leave out the key field or the value field of a map entry. + MapOutWireFormat out; + // Create some map entries without keys. They will be rendered with the + // default values ("" for strings, "0" for integers, etc.). + // { + // "map1": { + // "": { + // "foo": "foovalue" + // } + // }, + // "map2": { + // "": { + // "map1": { + // "nested_key1": { + // "foo": "nested_foo" + // } + // } + // } + // }, + // "map3": { + // "0": "one one one" + // }, + // "map4": { + // "false": "bool" + // } + // } + out.add_map1()->mutable_value()->set_foo("foovalue"); + MapOut* nested = out.add_map2()->mutable_value(); + (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo"); + out.add_map3()->set_value("one one one"); + out.add_map4()->set_value("bool"); + + ow_.StartObject("") + ->StartObject("map1") + ->StartObject("") + ->RenderString("foo", "foovalue") + ->EndObject() + ->EndObject() + ->StartObject("map2") + ->StartObject("") + ->StartObject("map1") + ->StartObject("nested_key1") + ->RenderString("foo", "nested_foo") + ->EndObject() + ->EndObject() + ->EndObject() + ->EndObject() + ->StartObject("map3") + ->RenderString("0", "one one one") + ->EndObject() + ->StartObject("map4") + ->RenderString("false", "bool") + ->EndObject() + ->EndObject(); + + DoTest(out, MapOut::descriptor()); +} + class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceAnysTest() { @@ -824,6 +944,63 @@ TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { DoTest(out, FieldMaskTest::descriptor()); } +class ProtostreamObjectSourceTimestampTest + : public ProtostreamObjectSourceTest { + protected: + ProtostreamObjectSourceTimestampTest() { + helper_.ResetTypeInfo(TimestampDuration::descriptor()); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtostreamObjectSourceTimestampTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Min allowed seconds - 1 + ts->set_seconds(kTimestampMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Max allowed seconds + 1 + ts->set_seconds(kTimestampMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds - 1 + dur->set_seconds(kDurationMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds + 1 + dur->set_seconds(kDurationMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 786bf0be..97a7909a 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -58,17 +58,20 @@ using util::StatusOr; ProtoStreamObjectWriter::ProtoStreamObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) + strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options) : ProtoWriter(type_resolver, type, output, listener), master_type_(type), - current_(NULL) {} + current_(NULL), + options_(options) {} ProtoStreamObjectWriter::ProtoStreamObjectWriter( const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener) : ProtoWriter(typeinfo, type, output, listener), master_type_(type), - current_(NULL) {} + current_(NULL), + options_(ProtoStreamObjectWriter::Options::Defaults()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { if (current_ == NULL) return; @@ -179,7 +182,8 @@ ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) data_(), output_(&data_), depth_(0), - has_injected_value_message_(false) {} + is_well_known_type_(false), + well_known_type_render_(NULL) {} ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} @@ -197,10 +201,19 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { parent_->master_type_.name())); invalid_ = true; } - } else if (!has_injected_value_message_ || depth_ != 1 || name != "value") { - // We don't propagate to ow_ StartObject("value") calls for nested Anys or - // Struct at depth 1 as they are nested one level deep with an injected + } else if (is_well_known_type_ && depth_ == 1) { + // For well-known types, the only other field besides "@type" should be a // "value" field. + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; + } + ow_->StartObject(""); + } else { + // Forward the call to the child writer if: + // 1. the type is not a well-known type. + // 2. or, we are in a nested Any, Struct, or Value object. ow_->StartObject(name); } } @@ -208,10 +221,9 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { bool ProtoStreamObjectWriter::AnyWriter::EndObject() { --depth_; // As long as depth_ >= 0, we know we haven't reached the end of Any. - // Propagate these EndObject() calls to the contained ow_. If we are in a - // nested Any or Struct type, ignore the second to last EndObject call (depth_ - // == -1) - if (ow_ != NULL && (!has_injected_value_message_ || depth_ >= 0)) { + // Propagate these EndObject() calls to the contained ow_. For regular + // message types, we propagate the end of Any as well. + if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) { ow_->EndObject(); } // A negative depth_ implies that we have reached the end of Any @@ -233,6 +245,13 @@ void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { parent_->master_type_.name())); invalid_ = true; } + } else if (is_well_known_type_ && depth_ == 1) { + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; + } + ow_->StartList(""); } else { ow_->StartList(name); } @@ -263,17 +282,27 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( parent_->master_type_.name())); invalid_ = true; } - } else { - // Check to see if the data needs to be rendered with well-known-type - // renderer. - const TypeRenderer* type_renderer = - FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name())); - if (type_renderer) { - Status status = (*type_renderer)(ow_.get(), value); - if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); + } else if (depth_ == 0 && is_well_known_type_) { + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; + } + if (well_known_type_render_ == NULL) { + // Only Any and Struct don't have a special type render but both of + // them expect a JSON object (i.e., a StartObject() call). + if (!invalid_) { + parent_->InvalidValue("Any", "Expect a JSON object."); + invalid_ = true; + } } else { - ow_->RenderDataPiece(name, value); + ow_->ProtoWriter::StartObject(""); + Status status = (*well_known_type_render_)(ow_.get(), value); + if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); + ow_->ProtoWriter::EndObject(); } + } else { + ow_->RenderDataPiece(name, value); } } @@ -302,19 +331,31 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { // At this point, type is never null. const google::protobuf::Type* type = resolved_type.ValueOrDie(); - // If this is the case of an Any in an Any or Struct in an Any, we need to - // expect a StartObject call with "value" while we're at depth_ 0, which we - // should ignore (not propagate to our nested object writer). We also need to - // ignore the second-to-last EndObject call, and not propagate that either. - if (type->name() == kAnyType || type->name() == kStructType) { - has_injected_value_message_ = true; + well_known_type_render_ = FindTypeRenderer(type_url_); + if (well_known_type_render_ != NULL || + // Explicitly list Any and Struct here because they don't have a + // custom renderer. + type->name() == kAnyType || type->name() == kStructType) { + is_well_known_type_ = true; } // Create our object writer and initialize it with the first StartObject // call. ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, parent_->listener())); - ow_->StartObject(""); + + // Don't call StartObject() for well-known types yet. Depending on the + // type of actual data, we may not need to call StartObject(). For + // example: + // { + // "@type": "type.googleapis.com/google.protobuf.Value", + // "value": [1, 2, 3], + // } + // With the above JSON representation, we will only call StartList() on the + // contained ow_. + if (!is_well_known_type_) { + ow_->StartObject(""); + } } void ProtoStreamObjectWriter::AnyWriter::WriteAny() { @@ -439,7 +480,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( // name): // { "key": "<name>", "value": { Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); Push("value", Item::MESSAGE, true, false); // Make sure we are valid so far after starting map fields. @@ -604,7 +646,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Render // { "key": "<name>", "value": { Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); Push("value", Item::MESSAGE, true, false); // Make sure we are valid after pushing all above items. @@ -758,8 +801,36 @@ Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow, string struct_field_name; switch (data.type()) { // Our JSON parser parses numbers as either int64, uint64, or double. - case DataPiece::TYPE_INT64: - case DataPiece::TYPE_UINT64: + case DataPiece::TYPE_INT64: { + // If the option to treat integers as strings is set, then render them as + // strings. Otherwise, fallback to rendering them as double. + if (ow->options_.struct_integers_as_strings) { + StatusOr<int64> int_value = data.ToInt64(); + if (int_value.ok()) { + ow->ProtoWriter::RenderDataPiece( + "string_value", + DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); + return Status::OK; + } + } + struct_field_name = "number_value"; + break; + } + case DataPiece::TYPE_UINT64: { + // If the option to treat integers as strings is set, then render them as + // strings. Otherwise, fallback to rendering them as double. + if (ow->options_.struct_integers_as_strings) { + StatusOr<uint64> int_value = data.ToUint64(); + if (int_value.ok()) { + ow->ProtoWriter::RenderDataPiece( + "string_value", + DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); + return Status::OK; + } + } + struct_field_name = "number_value"; + break; + } case DataPiece::TYPE_DOUBLE: { struct_field_name = "number_value"; break; @@ -812,7 +883,7 @@ Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, StringPiece path) { ow->ProtoWriter::RenderDataPiece( - "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase))); + "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); return Status::OK; } @@ -828,7 +899,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, // conversions as much as possible. Because ToSnakeCase sometimes returns the // wrong value. google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback( - google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); + ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); } @@ -871,7 +942,7 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, nanos = sign * nanos; int64 seconds = sign * unsigned_seconds; - if (seconds > kMaxSeconds || seconds < kMinSeconds || + if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds || nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { return Status(INVALID_ARGUMENT, "Duration value exceeds limits"); } @@ -925,7 +996,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( // Render an item in repeated map list. // { "key": "<name>", "value": Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); field = Lookup("value"); if (field == NULL) { GOOGLE_LOG(DFATAL) << "Map does not have a value field."; @@ -952,6 +1024,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( // not of the google.protobuf.NullType type, we do nothing. if (data.type() == DataPiece::TYPE_NULL && field->type_url() != kStructNullValueTypeUrl) { + Pop(); return this; } diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index 08ac6e33..e1162d43 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -74,10 +74,30 @@ class ObjectLocationTracker; // It also supports streaming. class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { public: + // Options that control ProtoStreamObjectWriter class's behavior. + struct Options { + // Treats integer inputs in google.protobuf.Struct as strings. Normally, + // integer values are returned in double field "number_value" of + // google.protobuf.Struct. However, this can cause precision loss for + // int64/uint64 inputs. This option is provided for cases that want to + // preserve integer precision. + bool struct_integers_as_strings; + + Options() : struct_integers_as_strings(false) {} + + // Default instance of Options with all options set to defaults. + static const Options& Defaults() { + static Options defaults; + return defaults; + } + }; + // Constructor. Does not take ownership of any parameter passed in. ProtoStreamObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener); + strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options = + ProtoStreamObjectWriter::Options::Defaults()); virtual ~ProtoStreamObjectWriter(); // ObjectWriter methods. @@ -147,9 +167,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { // The depth within the Any, so we can track when we're done. int depth_; - // True if the message type contained in Any has a special "value" message - // injected. This is true for well-known message types like Any or Struct. - bool has_injected_value_message_; + // True if the type is a well-known type. Well-known types in Any + // has a special formating: + // { + // "@type": "type.googleapis.com/google.protobuf.XXX", + // "value": <JSON representation of the type>, + // } + bool is_well_known_type_; + TypeRenderer* well_known_type_render_; }; // Represents an item in a stack of items used to keep state between @@ -301,6 +326,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { // The current element, variable for internal state processing. google::protobuf::scoped_ptr<Item> current_; + // Reference to the options that control this class's behavior. + const ProtoStreamObjectWriter::Options options_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter); }; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 5f9ffb95..9a0dcde1 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -90,6 +90,12 @@ string GetTypeUrl(const Descriptor* descriptor) { } } // namespace +#if __cplusplus >= 201103L + using std::get; +#else + using std::tr1::get; +#endif + class BaseProtoStreamObjectWriterTest : public ::testing::TestWithParam<testing::TypeInfoSource> { protected: @@ -122,7 +128,13 @@ class BaseProtoStreamObjectWriterTest GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!"; helper_.ResetTypeInfo(descriptors); ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(), - &listener_)); + &listener_, options_)); + } + + void ResetTypeInfo(const Descriptor* descriptor) { + vector<const Descriptor*> descriptors; + descriptors.push_back(descriptor); + ResetTypeInfo(descriptors); } virtual ~BaseProtoStreamObjectWriterTest() {} @@ -155,16 +167,12 @@ class BaseProtoStreamObjectWriterTest MockErrorListener listener_; google::protobuf::scoped_ptr<GrowingArrayByteSink> output_; google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_; + ProtoStreamObjectWriter::Options options_; }; MATCHER_P(HasObjectLocation, expected, "Verifies the expected object location") { - string actual; -#if __cplusplus >= 201103L - actual = std::get<0>(arg).ToString(); -#else - actual = std::tr1::get<0>(arg).ToString(); -#endif + string actual = get<0>(arg).ToString(); if (actual.compare(expected) == 0) return true; *result_listener << "actual location is: " << actual; return false; @@ -289,8 +297,7 @@ TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { full.add_rep_double(-8.05L); full.add_rep_bool(false); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); ow_->StartObject("") ->RenderString("fix32", "101") @@ -363,8 +370,7 @@ TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) { full.set_float_(std::numeric_limits<float>::infinity()); full.set_str("-Infinity"); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), StringPiece("\"Infinity\""))) @@ -397,8 +403,7 @@ TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) { full.set_float_(std::numeric_limits<float>::quiet_NaN()); full.set_str("NaN"); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), StringPiece("\"NaN\""))) @@ -887,6 +892,124 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) { CheckOutput(timestamp); } +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampYearNotZeroPadded) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(-61665654145); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "15-11-23T03:37:35.033155Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampYearZeroPadded) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(-61665654145); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "0015-11-23T03:37:35.033155Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampWithPositiveOffset) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(1448249855); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampWithNegativeOffset) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(1448249855); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset1) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+"))); + + ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset2) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+08-10"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+08-10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset3) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+24:10"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+24:10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset4) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+04:60"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+04:60") + ->EndObject(); + CheckOutput(timestamp); +} + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { TimestampDuration timestamp; @@ -937,10 +1060,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("Field 'ts', Invalid time format: " - "-8032-10-18T00:00:00.000Z"))); + "-8031-10-18T00:00:00.000Z"))); ow_->StartObject("") - ->RenderString("ts", "-8032-10-18T00:00:00.000Z") + ->RenderString("ts", "-8031-10-18T00:00:00.000Z") ->EndObject(); CheckOutput(timestamp); } @@ -996,6 +1119,22 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) { CheckOutput(timestamp); } +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "0-12-31T23:59:59.000Z"))); + + ow_->StartObject("") + ->RenderString("ts", "0-12-31T23:59:59.000Z") + ->EndObject(); + CheckOutput(timestamp); +} + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) { TimestampDuration duration; google::protobuf::Duration* dur = duration.mutable_dur(); @@ -1105,7 +1244,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, class ProtoStreamObjectWriterStructTest : public BaseProtoStreamObjectWriterTest { protected: - ProtoStreamObjectWriterStructTest() { + ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); } + + // Resets ProtoWriter with current set of options and other state. + void ResetProtoWriter() { vector<const Descriptor*> descriptors; descriptors.push_back(StructType::descriptor()); descriptors.push_back(google::protobuf::Struct::descriptor()); @@ -1201,6 +1343,28 @@ TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) { ->EndObject(); } +TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) { + StructType struct_type; + google::protobuf::Struct* s = struct_type.mutable_object(); + s->mutable_fields()->operator[]("k1").set_number_value(123); + s->mutable_fields()->operator[]("k2").set_bool_value(true); + s->mutable_fields()->operator[]("k3").set_string_value("-222222222"); + s->mutable_fields()->operator[]("k4").set_string_value("33333333"); + + options_.struct_integers_as_strings = true; + ResetProtoWriter(); + + ow_->StartObject("") + ->StartObject("object") + ->RenderDouble("k1", 123) + ->RenderBool("k2", true) + ->RenderInt64("k3", -222222222) + ->RenderUint64("k4", 33333333) + ->EndObject() + ->EndObject(); + CheckOutput(struct_type); +} + class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterMapTest() @@ -1249,6 +1413,8 @@ class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { descriptors.push_back(google::protobuf::DoubleValue::descriptor()); descriptors.push_back(google::protobuf::Timestamp::descriptor()); descriptors.push_back(google::protobuf::Any::descriptor()); + descriptors.push_back(google::protobuf::Value::descriptor()); + descriptors.push_back(google::protobuf::Struct::descriptor()); ResetTypeInfo(descriptors); } }; @@ -1457,6 +1623,222 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) { CheckOutput(any); } +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": "abc" +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + value.set_string_value("abc"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->RenderString("value", "abc") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": { +// "foo": "abc" +// } +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value( + "abc"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartObject("value") + ->RenderString("foo", "abc") + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": ["hello"], +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + value.mutable_list_value()->add_values()->set_string_value("hello"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartList("value") + ->RenderString("", "hello") + ->EndList() + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": "" +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, + AnyWellKnownTypesNoValueFieldForPrimitive) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->RenderString("not_value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": {} +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartObject("not_value") + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": [], +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartList("not_value") + ->EndList() + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Struct", +// "value": "", +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) { + EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), + StringPiece("Expect a JSON object."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Struct"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct") + ->RenderString("value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Any", +// "value": "", +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) { + EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), + StringPiece("Expect a JSON object."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Any"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") + ->RenderString("value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + class ProtoStreamObjectWriterFieldMaskTest : public BaseProtoStreamObjectWriterTest { protected: diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto index 82b81760..1cbbba47 100644 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ b/src/google/protobuf/util/internal/testdata/books.proto @@ -56,6 +56,13 @@ message Book { optional Publisher publisher = 9; repeated Label labels = 10; + enum Type { + FICTION = 1; + KIDS = 2; + ACTION_AND_ADVENTURE = 3; + } + optional Type type = 11; + extensions 200 to 499; } @@ -169,3 +176,12 @@ message NestedBook { message BadNestedBook { repeated uint32 book = 1 [packed=true]; // Packed to optional message. } + +// A recursively defined message. +message Cyclic { + optional int32 m_int = 1; + optional string m_str = 2; + optional Book m_book = 3; + repeated Author m_author = 5; + optional Cyclic m_cyclic = 4; +} diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc index 1b9c5154..49e18ed0 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ b/src/google/protobuf/util/internal/type_info_test_helper.cc @@ -102,13 +102,13 @@ ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( } ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( - const string& type_url, strings::ByteSink* output, - ErrorListener* listener) { + const string& type_url, strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options) { const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output, - listener); + listener, options); } } GOOGLE_LOG(FATAL) << "Can not reach here."; diff --git a/src/google/protobuf/util/internal/type_info_test_helper.h b/src/google/protobuf/util/internal/type_info_test_helper.h index 6916a73b..1a279849 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.h +++ b/src/google/protobuf/util/internal/type_info_test_helper.h @@ -39,8 +39,8 @@ #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/util/internal/type_info.h> #include <google/protobuf/util/internal/default_value_objectwriter.h> +#include <google/protobuf/util/internal/type_info.h> #include <google/protobuf/util/internal/protostream_objectsource.h> #include <google/protobuf/util/internal/protostream_objectwriter.h> #include <google/protobuf/util/type_resolver.h> @@ -77,9 +77,9 @@ class TypeInfoTestHelper { ProtoStreamObjectSource* NewProtoSource(io::CodedInputStream* coded_input, const string& type_url); - ProtoStreamObjectWriter* NewProtoWriter(const string& type_url, - strings::ByteSink* output, - ErrorListener* listener); + ProtoStreamObjectWriter* NewProtoWriter( + const string& type_url, strings::ByteSink* output, + ErrorListener* listener, const ProtoStreamObjectWriter::Options& options); DefaultValueObjectWriter* NewDefaultValueWriter(const string& type_url, ObjectWriter* writer); diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 1ddf2487..ee7a51fc 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -222,6 +222,7 @@ string ToCamelCase(const StringPiece input) { if (!result.empty() && is_cap && (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { first_word = false; + result.push_back(input[i]); } else { result.push_back(ascii_tolower(input[i])); continue; @@ -231,9 +232,13 @@ string ToCamelCase(const StringPiece input) { if (ascii_islower(input[i])) { result.push_back(ascii_toupper(input[i])); continue; + } else { + result.push_back(input[i]); + continue; } + } else { + result.push_back(ascii_tolower(input[i])); } - result.push_back(input[i]); } return result; } diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc index c3b8d502..2659320a 100644 --- a/src/google/protobuf/util/json_util.cc +++ b/src/google/protobuf/util/json_util.cc @@ -102,6 +102,42 @@ util::Status BinaryToJsonString(TypeResolver* resolver, options); } +namespace { +class StatusErrorListener : public converter::ErrorListener { + public: + StatusErrorListener() : status_(util::Status::OK) {} + virtual ~StatusErrorListener() {} + + util::Status GetStatus() { return status_; } + + virtual void InvalidName(const converter::LocationTrackerInterface& loc, + StringPiece unknown_name, StringPiece message) { + status_ = util::Status(util::error::INVALID_ARGUMENT, + loc.ToString() + ": " + message.ToString()); + } + + virtual void InvalidValue(const converter::LocationTrackerInterface& loc, + StringPiece type_name, StringPiece value) { + status_ = + util::Status(util::error::INVALID_ARGUMENT, + loc.ToString() + ": invalid value " + value.ToString() + + " for type " + type_name.ToString()); + } + + virtual void MissingField(const converter::LocationTrackerInterface& loc, + StringPiece missing_name) { + status_ = util::Status( + util::error::INVALID_ARGUMENT, + loc.ToString() + ": missing field " + missing_name.ToString()); + } + + private: + util::Status status_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StatusErrorListener); +}; +} // namespace + util::Status JsonToBinaryStream(TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* json_input, @@ -109,7 +145,7 @@ util::Status JsonToBinaryStream(TypeResolver* resolver, google::protobuf::Type type; RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type)); internal::ZeroCopyStreamByteSink sink(binary_output); - converter::NoopErrorListener listener; + StatusErrorListener listener; converter::ProtoStreamObjectWriter proto_writer(resolver, type, &sink, &listener); @@ -123,7 +159,7 @@ util::Status JsonToBinaryStream(TypeResolver* resolver, } RETURN_IF_ERROR(parser.FinishParse()); - return util::Status::OK; + return listener.GetStatus(); } util::Status JsonToBinaryString(TypeResolver* resolver, diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index da68495f..a4d3cc98 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -77,8 +77,11 @@ class JsonUtilTest : public testing::Test { bool FromJson(const string& json, Message* message) { string binary; - GOOGLE_CHECK_OK(JsonToBinaryString( - resolver_.get(), GetTypeUrl(message->GetDescriptor()), json, &binary)); + if (!JsonToBinaryString(resolver_.get(), + GetTypeUrl(message->GetDescriptor()), json, &binary) + .ok()) { + return false; + } return message->ParseFromString(binary); } @@ -99,28 +102,36 @@ TEST_F(JsonUtilTest, TestWhitespaces) { ToJson(m, options)); } -// TODO(skarvaje): Uncomment after cl/96232915 is submitted. -// TEST_F(JsonUtilTest, TestDefaultValues) { - // TestMessage m; - // JsonOptions options; - // EXPECT_EQ("{}", ToJson(m, options)); - // options.always_print_primitive_fields = true; - // EXPECT_EQ( - // "{\"boolValue\":false," - // "\"int32Value\":0," - // "\"int64Value\":\"0\"," - // "\"uint32Value\":0," - // "\"uint64Value\":\"0\"," - // "\"floatValue\":0," - // "\"doubleValue\":0," - // "\"stringValue\":\"\"," - // "\"bytesValue\":\"\"," - // // TODO(xiaofeng): The default enum value should be FOO. I believe - // // this is a bug in DefaultValueObjectWriter. - // "\"enumValue\":null" - // "}", - // ToJson(m, options)); -// } +TEST_F(JsonUtilTest, TestDefaultValues) { + TestMessage m; + JsonOptions options; + EXPECT_EQ("{}", ToJson(m, options)); + options.always_print_primitive_fields = true; + EXPECT_EQ( + "{\"boolValue\":false," + "\"int32Value\":0," + "\"int64Value\":\"0\"," + "\"uint32Value\":0," + "\"uint64Value\":\"0\"," + "\"floatValue\":0," + "\"doubleValue\":0," + "\"stringValue\":\"\"," + "\"bytesValue\":\"\"," + "\"enumValue\":\"FOO\"," + "\"repeatedBoolValue\":[]," + "\"repeatedInt32Value\":[]," + "\"repeatedInt64Value\":[]," + "\"repeatedUint32Value\":[]," + "\"repeatedUint64Value\":[]," + "\"repeatedFloatValue\":[]," + "\"repeatedDoubleValue\":[]," + "\"repeatedStringValue\":[]," + "\"repeatedBytesValue\":[]," + "\"repeatedEnumValue\":[]," + "\"repeatedMessageValue\":[]" + "}", + ToJson(m, options)); +} TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper @@ -158,6 +169,15 @@ TEST_F(JsonUtilTest, ParseMap) { EXPECT_EQ(message.DebugString(), other.DebugString()); } +TEST_F(JsonUtilTest, TestParseErrors) { + TestMessage m; + JsonOptions options; + // Parsing should fail if the field name can not be recognized. + EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m)); + // Parsing should fail if the value is invalid. + EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m)); +} + typedef pair<char*, int> Segment; // A ZeroCopyOutputStream that writes to multiple buffers. class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 0f879dc7..fe8119bf 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -47,6 +47,7 @@ #include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/any.h> #include <google/protobuf/io/printer.h> @@ -455,7 +456,9 @@ bool MessageDifferencer::Compare( const Descriptor* descriptor2 = message2.GetDescriptor(); if (descriptor1 != descriptor2) { GOOGLE_LOG(DFATAL) << "Comparison between two messages with different " - << "descriptors."; + << "descriptors. " + << descriptor1->full_name() << " vs " + << descriptor2->full_name(); return false; } // Expand google.protobuf.Any payload if possible. @@ -1021,7 +1024,7 @@ bool MessageDifferencer::UnpackAny(const Message& any, any.GetDescriptor()->file()->pool()->FindMessageTypeByName( full_type_name); if (desc == NULL) { - GOOGLE_LOG(ERROR) << "Proto type '" << full_type_name << "' not found"; + GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found"; return false; } @@ -1031,7 +1034,7 @@ bool MessageDifferencer::UnpackAny(const Message& any, data->reset(dynamic_message_factory_->GetPrototype(desc)->New()); string serialized_value = reflection->GetString(any, value_field); if (!(*data)->ParseFromString(serialized_value)) { - GOOGLE_LOG(ERROR) << "Failed to parse value for " << full_type_name; + GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name; return false; } return true; @@ -1384,7 +1387,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( // algorithm will fail to find a maximum matching. // Here we use the argumenting path algorithm. MaximumMatcher::NodeMatchCallback* callback = - google::protobuf::internal::NewPermanentCallback( + ::google::protobuf::internal::NewPermanentCallback( this, &MessageDifferencer::IsMatch, repeated_field, key_comparator, &message1, &message2, parent_fields); diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 7f1093c8..f2517074 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -412,7 +412,7 @@ void WireFormatLite::WriteString(int field_number, const string& value, io::CodedOutputStream* output) { // String is for UTF-8 text only WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteString(value); } @@ -421,14 +421,14 @@ void WireFormatLite::WriteStringMaybeAliased( io::CodedOutputStream* output) { // String is for UTF-8 text only WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } void WireFormatLite::WriteBytes(int field_number, const string& value, io::CodedOutputStream* output) { WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteString(value); } @@ -436,7 +436,7 @@ void WireFormatLite::WriteBytesMaybeAliased( int field_number, const string& value, io::CodedOutputStream* output) { WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index 79493ca0..7bce21cf 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -274,8 +274,8 @@ inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( // The number of bytes each type occupies on the wire. const int per_value_size = tag_size + sizeof(value); - int elements_available = min(values->Capacity() - values->size(), - size / per_value_size); + int elements_available = + std::min(values->Capacity() - values->size(), size / per_value_size); int num_read = 0; while (num_read < elements_available && (buffer = io::CodedInputStream::ExpectTagFromArray( @@ -367,7 +367,7 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive( bytes_limit = input->BytesUntilLimit(); } else { bytes_limit = - min(bytes_limit, static_cast<int64>(input->BytesUntilLimit())); + std::min(bytes_limit, static_cast<int64>(input->BytesUntilLimit())); } if (bytes_limit >= new_bytes) { // Fast-path that pre-allocates *values to the final size. diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 15c37556..4e4add66 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -45,6 +45,7 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> #include <google/protobuf/stubs/stl_util.h> diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 212dd219..60801423 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -263,10 +263,11 @@ void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() { "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013" "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022" "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001" - " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BS\n\023com" - ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242" - "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006" - "proto3", 406); + " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014B\177\n\023com" + ".google.protobufB\rWrappersProtoP\001Z*githu" + "b.com/golang/protobuf/ptypes/wrappers\240\001\001" + "\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTyp" + "esb\006proto3", 450); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/wrappers.proto", &protobuf_RegisterTypes); DoubleValue::default_instance_ = new DoubleValue(); @@ -387,12 +388,13 @@ DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const { } void DoubleValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DoubleValue) value_ = 0; } bool DoubleValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DoubleValue) for (;;) { @@ -459,6 +461,7 @@ void DoubleValue::SerializeWithCachedSizes( } int DoubleValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue) int total_size = 0; // optional double value = 1; @@ -473,18 +476,22 @@ int DoubleValue::ByteSize() const { } void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DoubleValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DoubleValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const DoubleValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DoubleValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DoubleValue) MergeFrom(*source); } } void DoubleValue::MergeFrom(const DoubleValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -492,12 +499,14 @@ void DoubleValue::MergeFrom(const DoubleValue& from) { } void DoubleValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DoubleValue) if (&from == this) return; Clear(); MergeFrom(from); } void DoubleValue::CopyFrom(const DoubleValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DoubleValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -637,12 +646,13 @@ FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const { } void FloatValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FloatValue) value_ = 0; } bool FloatValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FloatValue) for (;;) { @@ -709,6 +719,7 @@ void FloatValue::SerializeWithCachedSizes( } int FloatValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue) int total_size = 0; // optional float value = 1; @@ -723,18 +734,22 @@ int FloatValue::ByteSize() const { } void FloatValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FloatValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FloatValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const FloatValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FloatValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FloatValue) MergeFrom(*source); } } void FloatValue::MergeFrom(const FloatValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -742,12 +757,14 @@ void FloatValue::MergeFrom(const FloatValue& from) { } void FloatValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FloatValue) if (&from == this) return; Clear(); MergeFrom(from); } void FloatValue::CopyFrom(const FloatValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FloatValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -887,12 +904,13 @@ Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const { } void Int64Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Int64Value) value_ = GOOGLE_LONGLONG(0); } bool Int64Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Int64Value) for (;;) { @@ -959,6 +977,7 @@ void Int64Value::SerializeWithCachedSizes( } int Int64Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value) int total_size = 0; // optional int64 value = 1; @@ -975,18 +994,22 @@ int Int64Value::ByteSize() const { } void Int64Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Int64Value* source = ::google::protobuf::internal::DynamicCastToGenerated<const Int64Value>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int64Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int64Value) MergeFrom(*source); } } void Int64Value::MergeFrom(const Int64Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -994,12 +1017,14 @@ void Int64Value::MergeFrom(const Int64Value& from) { } void Int64Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int64Value) if (&from == this) return; Clear(); MergeFrom(from); } void Int64Value::CopyFrom(const Int64Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int64Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1139,12 +1164,13 @@ UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const { } void UInt64Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt64Value) value_ = GOOGLE_ULONGLONG(0); } bool UInt64Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UInt64Value) for (;;) { @@ -1211,6 +1237,7 @@ void UInt64Value::SerializeWithCachedSizes( } int UInt64Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value) int total_size = 0; // optional uint64 value = 1; @@ -1227,18 +1254,22 @@ int UInt64Value::ByteSize() const { } void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UInt64Value* source = ::google::protobuf::internal::DynamicCastToGenerated<const UInt64Value>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt64Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt64Value) MergeFrom(*source); } } void UInt64Value::MergeFrom(const UInt64Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1246,12 +1277,14 @@ void UInt64Value::MergeFrom(const UInt64Value& from) { } void UInt64Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt64Value) if (&from == this) return; Clear(); MergeFrom(from); } void UInt64Value::CopyFrom(const UInt64Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt64Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1391,12 +1424,13 @@ Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const { } void Int32Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Int32Value) value_ = 0; } bool Int32Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Int32Value) for (;;) { @@ -1463,6 +1497,7 @@ void Int32Value::SerializeWithCachedSizes( } int Int32Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value) int total_size = 0; // optional int32 value = 1; @@ -1479,18 +1514,22 @@ int Int32Value::ByteSize() const { } void Int32Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Int32Value* source = ::google::protobuf::internal::DynamicCastToGenerated<const Int32Value>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int32Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int32Value) MergeFrom(*source); } } void Int32Value::MergeFrom(const Int32Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1498,12 +1537,14 @@ void Int32Value::MergeFrom(const Int32Value& from) { } void Int32Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int32Value) if (&from == this) return; Clear(); MergeFrom(from); } void Int32Value::CopyFrom(const Int32Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int32Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1643,12 +1684,13 @@ UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const { } void UInt32Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt32Value) value_ = 0u; } bool UInt32Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UInt32Value) for (;;) { @@ -1715,6 +1757,7 @@ void UInt32Value::SerializeWithCachedSizes( } int UInt32Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value) int total_size = 0; // optional uint32 value = 1; @@ -1731,18 +1774,22 @@ int UInt32Value::ByteSize() const { } void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UInt32Value* source = ::google::protobuf::internal::DynamicCastToGenerated<const UInt32Value>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt32Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt32Value) MergeFrom(*source); } } void UInt32Value::MergeFrom(const UInt32Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1750,12 +1797,14 @@ void UInt32Value::MergeFrom(const UInt32Value& from) { } void UInt32Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt32Value) if (&from == this) return; Clear(); MergeFrom(from); } void UInt32Value::CopyFrom(const UInt32Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt32Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1895,12 +1944,13 @@ BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const { } void BoolValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.BoolValue) value_ = false; } bool BoolValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.BoolValue) for (;;) { @@ -1967,6 +2017,7 @@ void BoolValue::SerializeWithCachedSizes( } int BoolValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue) int total_size = 0; // optional bool value = 1; @@ -1981,18 +2032,22 @@ int BoolValue::ByteSize() const { } void BoolValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BoolValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const BoolValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const BoolValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BoolValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BoolValue) MergeFrom(*source); } } void BoolValue::MergeFrom(const BoolValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -2000,12 +2055,14 @@ void BoolValue::MergeFrom(const BoolValue& from) { } void BoolValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BoolValue) if (&from == this) return; Clear(); MergeFrom(from); } void BoolValue::CopyFrom(const BoolValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BoolValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2147,12 +2204,13 @@ StringValue* StringValue::New(::google::protobuf::Arena* arena) const { } void StringValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.StringValue) value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool StringValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.StringValue) for (;;) { @@ -2232,6 +2290,7 @@ void StringValue::SerializeWithCachedSizes( } int StringValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue) int total_size = 0; // optional string value = 1; @@ -2248,18 +2307,22 @@ int StringValue::ByteSize() const { } void StringValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.StringValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const StringValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const StringValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.StringValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.StringValue) MergeFrom(*source); } } void StringValue::MergeFrom(const StringValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value().size() > 0) { set_value(from.value()); @@ -2267,12 +2330,14 @@ void StringValue::MergeFrom(const StringValue& from) { } void StringValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.StringValue) if (&from == this) return; Clear(); MergeFrom(from); } void StringValue::CopyFrom(const StringValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.StringValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2348,10 +2413,12 @@ void StringValue::clear_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* StringValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* StringValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -2377,7 +2444,7 @@ void StringValue::clear_value() { } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -2464,12 +2531,13 @@ BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const { } void BytesValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.BytesValue) value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool BytesValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.BytesValue) for (;;) { @@ -2537,6 +2605,7 @@ void BytesValue::SerializeWithCachedSizes( } int BytesValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue) int total_size = 0; // optional bytes value = 1; @@ -2553,18 +2622,22 @@ int BytesValue::ByteSize() const { } void BytesValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BytesValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const BytesValue* source = ::google::protobuf::internal::DynamicCastToGenerated<const BytesValue>( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BytesValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BytesValue) MergeFrom(*source); } } void BytesValue::MergeFrom(const BytesValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value().size() > 0) { set_value(from.value()); @@ -2572,12 +2645,14 @@ void BytesValue::MergeFrom(const BytesValue& from) { } void BytesValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BytesValue) if (&from == this) return; Clear(); MergeFrom(from); } void BytesValue::CopyFrom(const BytesValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BytesValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2653,10 +2728,12 @@ void BytesValue::clear_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* BytesValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* BytesValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -2682,7 +2759,7 @@ void BytesValue::clear_value() { } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index 7dca938c..10784778 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -1048,10 +1048,12 @@ inline ::std::string* StringValue::mutable_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* StringValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* StringValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -1077,7 +1079,7 @@ inline void StringValue::unsafe_arena_set_allocated_value( } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) } // ------------------------------------------------------------------- @@ -1116,10 +1118,12 @@ inline ::std::string* BytesValue::mutable_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* BytesValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* BytesValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -1145,7 +1149,7 @@ inline void BytesValue::unsafe_arena_set_allocated_value( } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value) } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index 040d8a24..4828ad9a 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -39,6 +39,7 @@ package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/wrappers"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; |