diff options
Diffstat (limited to 'src')
311 files changed, 18368 insertions, 5616 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 2985b5d8..80065506 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,7 +58,7 @@ MAINTAINERCLEANFILES = \ nobase_include_HEADERS = \ google/protobuf/stubs/atomic_sequence_num.h \ google/protobuf/stubs/atomicops.h \ - google/protobuf/stubs/atomicops_internals_aix.h \ + google/protobuf/stubs/atomicops_internals_power.h \ google/protobuf/stubs/atomicops_internals_arm64_gcc.h \ google/protobuf/stubs/atomicops_internals_arm_gcc.h \ google/protobuf/stubs/atomicops_internals_arm_qnx.h \ @@ -148,15 +148,16 @@ nobase_include_HEADERS = \ google/protobuf/compiler/plugin.h \ google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ + google/protobuf/compiler/csharp/csharp_generator.h \ + google/protobuf/compiler/csharp/csharp_names.h \ google/protobuf/compiler/java/java_generator.h \ google/protobuf/compiler/java/java_names.h \ google/protobuf/compiler/javanano/javanano_generator.h \ + google/protobuf/compiler/js/js_generator.h \ google/protobuf/compiler/objectivec/objectivec_generator.h \ google/protobuf/compiler/objectivec/objectivec_helpers.h \ google/protobuf/compiler/python/python_generator.h \ google/protobuf/compiler/ruby/ruby_generator.h \ - google/protobuf/compiler/csharp/csharp_generator.h \ - google/protobuf/compiler/csharp/csharp_names.h \ google/protobuf/util/type_resolver.h \ google/protobuf/util/field_comparator.h \ google/protobuf/util/field_mask_util.h \ @@ -276,9 +277,9 @@ libprotobuf_la_SOURCES = \ google/protobuf/util/internal/protostream_objectsource.h \ google/protobuf/util/internal/protostream_objectwriter.cc \ google/protobuf/util/internal/protostream_objectwriter.h \ - google/protobuf/util/internal/snake2camel_objectwriter.h \ + google/protobuf/util/internal/proto_writer.cc \ + google/protobuf/util/internal/proto_writer.h \ google/protobuf/util/internal/structured_objectwriter.h \ - google/protobuf/util/internal/testdata \ google/protobuf/util/internal/type_info.cc \ google/protobuf/util/internal/type_info.h \ google/protobuf/util/internal/type_info_test_helper.cc \ @@ -341,6 +342,8 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_enum_lite.h \ google/protobuf/compiler/java/java_extension.cc \ google/protobuf/compiler/java/java_extension.h \ + google/protobuf/compiler/java/java_extension_lite.cc \ + google/protobuf/compiler/java/java_extension_lite.h \ google/protobuf/compiler/java/java_field.cc \ google/protobuf/compiler/java/java_field.h \ google/protobuf/compiler/java/java_file.cc \ @@ -386,6 +389,7 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_string_field_lite.h \ google/protobuf/compiler/java/java_doc_comment.cc \ google/protobuf/compiler/java/java_doc_comment.h \ + google/protobuf/compiler/js/js_generator.cc \ google/protobuf/compiler/javanano/javanano_enum.cc \ google/protobuf/compiler/javanano/javanano_enum.h \ google/protobuf/compiler/javanano/javanano_enum_field.cc \ @@ -451,8 +455,11 @@ 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 \ + google/protobuf/compiler/csharp/csharp_reflection_class.h \ google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \ google/protobuf/compiler/csharp/csharp_repeated_enum_field.h \ google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \ @@ -461,8 +468,6 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h \ google/protobuf/compiler/csharp/csharp_source_generator_base.cc \ google/protobuf/compiler/csharp/csharp_source_generator_base.h \ - google/protobuf/compiler/csharp/csharp_umbrella_class.cc \ - google/protobuf/compiler/csharp/csharp_umbrella_class.h \ google/protobuf/compiler/csharp/csharp_wrapper_field.cc \ google/protobuf/compiler/csharp/csharp_wrapper_field.h @@ -502,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 \ @@ -513,6 +520,7 @@ protoc_inputs = \ google/protobuf/util/internal/testdata/struct.proto \ google/protobuf/util/internal/testdata/timestamp_duration.proto \ google/protobuf/util/json_format_proto3.proto \ + google/protobuf/util/message_differencer_unittest.proto \ google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto EXTRA_DIST = \ @@ -603,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 \ @@ -624,7 +636,9 @@ protoc_outputs = \ google/protobuf/util/internal/testdata/timestamp_duration.pb.cc \ google/protobuf/util/internal/testdata/timestamp_duration.pb.h \ google/protobuf/util/json_format_proto3.pb.cc \ - google/protobuf/util/json_format_proto3.pb.h + google/protobuf/util/json_format_proto3.pb.h \ + google/protobuf/util/message_differencer_unittest.pb.cc \ + google/protobuf/util/message_differencer_unittest.pb.h BUILT_SOURCES = $(protoc_outputs) @@ -702,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 \ @@ -722,6 +738,7 @@ protobuf_test_SOURCES = \ google/protobuf/compiler/cpp/cpp_unittest.h \ google/protobuf/compiler/cpp/cpp_unittest.cc \ google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \ + google/protobuf/compiler/cpp/metadata_test.cc \ google/protobuf/compiler/java/java_plugin_unittest.cc \ google/protobuf/compiler/java/java_doc_comment_unittest.cc \ google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \ @@ -737,6 +754,7 @@ protobuf_test_SOURCES = \ google/protobuf/util/internal/protostream_objectwriter_test.cc \ google/protobuf/util/internal/type_info_test_helper.cc \ google/protobuf/util/json_util_test.cc \ + google/protobuf/util/message_differencer_unittest.cc \ google/protobuf/util/time_util_test.cc \ google/protobuf/util/type_resolver_util_test.cc \ $(COMMON_TEST_SOURCES) diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..63d6e24c --- /dev/null +++ b/src/README.md @@ -0,0 +1,212 @@ +Protocol Buffers - Google's data interchange format +=================================================== + +[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf) + +Copyright 2008 Google Inc. + +https://developers.google.com/protocol-buffers/ + +C++ Installation - Unix +----------------------- + +To build protobuf from source, the following tools are needed: + + * autoconf + * 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 make g++ unzip + +On other platforms, please use the corresponding package managing tool to +install them before proceeding. + +If you get the source from github, you need to generate the configure script +first: + + $ ./autogen.sh + +This will download gmock source (which is used for C++ Protocol Buffer +unit-tests) to the current directory and run automake, autoconf, etc. +to generate the configure script and various template makefiles. + +You can skip this step if you are using a release package (which already +contains gmock and the configure script). + +To build and install the C++ Protocol Buffer runtime and the Protocol +Buffer compiler (protoc) execute the following: + + $ ./configure + $ make + $ make check + $ sudo make install + $ sudo ldconfig # refresh shared library cache. + +If "make check" fails, you can still install, but it is likely that +some features of this library will not work correctly on your system. +Proceed at your own risk. + +For advanced usage information on configure and make, please refer to the +autoconf documentation: + + http://www.gnu.org/software/autoconf/manual/autoconf.html#Running-configure-Scripts + +**Hint on install location** + + By default, the package will be installed to /usr/local. However, + on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH. + You can add it, but it may be easier to just install to /usr + instead. To do this, invoke configure as follows: + + ./configure --prefix=/usr + + If you already built the package with a different prefix, make sure + to run "make clean" before building again. + +**Compiling dependent packages** + + To compile a package that uses Protocol Buffers, you need to pass + various flags to your compiler and linker. As of version 2.2.0, + Protocol Buffers integrates with pkg-config to manage this. If you + have pkg-config installed, then you can invoke it to get a list of + flags like so: + + pkg-config --cflags protobuf # print compiler flags + pkg-config --libs protobuf # print linker flags + pkg-config --cflags --libs protobuf # print both + + For example: + + c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf` + + Note that packages written prior to the 2.2.0 release of Protocol + Buffers may not yet integrate with pkg-config to get flags, and may + not pass the correct set of flags to correctly link against + libprotobuf. If the package in question uses autoconf, you can + often fix the problem by invoking its configure script like: + + configure CXXFLAGS="$(pkg-config --cflags protobuf)" \ + LIBS="$(pkg-config --libs protobuf)" + + This will force it to use the correct flags. + + If you are writing an autoconf-based package that uses Protocol + Buffers, you should probably use the PKG_CHECK_MODULES macro in your + configure script like: + + PKG_CHECK_MODULES([protobuf], [protobuf]) + + See the pkg-config man page for more info. + + If you only want protobuf-lite, substitute "protobuf-lite" in place + of "protobuf" in these examples. + +**Note for Mac users** + + For a Mac system, Unix tools are not available by default. You will first need + to install Xcode from the Mac AppStore and then run the following command from + a terminal: + + $ sudo xcode-select --install + + To install Unix tools, you can install "port" following the instructions at + https://www.macports.org . This will reside in /opt/local/bin/port for most + Mac installations. + + $ sudo /opt/local/bin/port install autoconf automake libtool + + Then follow the Unix instructions above. + +**Note for cross-compiling** + + The makefiles normally invoke the protoc executable that they just + built in order to build tests. When cross-compiling, the protoc + executable may not be executable on the host machine. In this case, + you must build a copy of protoc for the host machine first, then use + the --with-protoc option to tell configure to use it instead. For + example: + + ./configure --with-protoc=protoc + + This will use the installed protoc (found in your $PATH) instead of + trying to execute the one built during the build process. You can + also use an executable that hasn't been installed. For example, if + you built the protobuf package for your host machine in ../host, + you might do: + + ./configure --with-protoc=../host/src/protoc + + Either way, you must make sure that the protoc executable you use + has the same version as the protobuf source code you are trying to + use it with. + +**Note for Solaris users** + + Solaris 10 x86 has a bug that will make linking fail, complaining + about libstdc++.la being invalid. We have included a work-around + in this package. To use the work-around, run configure as follows: + + ./configure LDFLAGS=-L$PWD/src/solaris + + See src/solaris/libstdc++.la for more info on this bug. + +**Note for HP C++ Tru64 users** + + To compile invoke configure as follows: + + ./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM" + + Also, you will need to use gmake instead of make. + +**Note for AIX users** + + Compile using the IBM xlC C++ compiler as follows: + + ./configure CXX=xlC + + Also, you will need to use GNU `make` (`gmake`) instead of AIX `make`. + +C++ Installation - Windows +-------------------------- + +If you only need the protoc binary, you can download it from the release +page: + + https://github.com/google/protobuf/releases + +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](../cmake/README.md). + +To build from source using Cygwin or MinGW, follow the Unix installation +instructions, above. + +Binary Compatibility Warning +---------------------------- + +Due to the nature of C++, it is unlikely that any two versions of the +Protocol Buffers C++ runtime libraries will have compatible ABIs. +That is, if you linked an executable against an older version of +libprotobuf, it is unlikely to work with a newer version without +re-compiling. This problem, when it occurs, will normally be detected +immediately on startup of your app. Still, you may want to consider +using static linkage. You can configure this package to install +static libraries only using: + + ./configure --disable-shared + +Usage +----- + +The complete documentation for Protocol Buffers is available via the +web at: + + https://developers.google.com/protocol-buffers/ diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index 7351d377..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())); } @@ -65,25 +75,22 @@ bool AnyMetadata::UnpackTo(Message* message) const { } bool AnyMetadata::InternalIs(const Descriptor* descriptor) const { - return type_url_->GetNoArena( - &::google::protobuf::internal::GetEmptyString()) == - GetTypeUrl(descriptor); + const string type_url = type_url_->GetNoArena( + &::google::protobuf::internal::GetEmptyString()); + string full_name; + if (!ParseAnyTypeUrl(type_url, &full_name)) { + return false; + } + 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 f760ad5d..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()); @@ -75,7 +91,7 @@ extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/". // Get the proto type name from Any::type_url value. For example, passing // "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in // *full_type_name. Returns false if type_url does not start with -// "type.googleapis.com". +// "type.googleapis.com" or "type.googleprod.com". bool ParseAnyTypeUrl(const string& type_url, string* full_type_name); // See if message is of type google.protobuf.Any, if so, return the descriptors diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index cbb5d233..fbde4a6d 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/any.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/any.pb.h" +#include <google/protobuf/any.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -82,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(); @@ -115,14 +117,19 @@ 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); } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Any::kTypeUrlFieldNumber; const int Any::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Any::Any() : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) { @@ -189,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 (;;) { @@ -301,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; @@ -324,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) { @@ -348,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); @@ -416,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()); } @@ -459,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 c324c4af..100a67f6 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -27,7 +27,7 @@ #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/unknown_field_set.h> -#include "google/protobuf/any.h" +#include <google/protobuf/any.h> // @@protoc_insertion_point(includes) namespace google { @@ -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 423699be..45db6ede 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -27,20 +27,50 @@ // 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"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "AnyProto"; -option java_package = "com.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 // ==== @@ -62,8 +92,8 @@ option objc_class_prefix = "GPB"; // // If the embedded message type is well-known and has a custom JSON // representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the the `@type` -// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]): +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): // // { // "@type": "type.googleapis.com/google.protobuf.Duration", @@ -72,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: @@ -80,7 +110,9 @@ 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`). - // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type] + // 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 // URL, or have them precompiled into a binary to avoid any @@ -93,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 0a2c4ec0..cbeba302 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/api.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/api.pb.h" +#include <google/protobuf/api.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -186,7 +187,7 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Api::kNameFieldNumber; const int Api::kMethodsFieldNumber; const int Api::kOptionsFieldNumber; @@ -194,7 +195,7 @@ const int Api::kVersionFieldNumber; const int Api::kSourceContextFieldNumber; const int Api::kMixinsFieldNumber; const int Api::kSyntaxFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Api::Api() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -264,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_; @@ -276,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 (;;) { @@ -537,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; @@ -597,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_); @@ -630,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); @@ -703,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()); } @@ -806,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()); } @@ -840,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; @@ -904,7 +916,7 @@ void Api::clear_syntax() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Method::kNameFieldNumber; const int Method::kRequestTypeUrlFieldNumber; const int Method::kRequestStreamingFieldNumber; @@ -912,7 +924,7 @@ const int Method::kResponseTypeUrlFieldNumber; const int Method::kResponseStreamingFieldNumber; const int Method::kOptionsFieldNumber; const int Method::kSyntaxFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Method::Method() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -983,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,\ @@ -1004,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 (;;) { @@ -1268,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; @@ -1322,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) { @@ -1360,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); @@ -1433,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()); } @@ -1476,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()); } @@ -1533,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()); } @@ -1608,10 +1639,10 @@ void Method::clear_syntax() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Mixin::kNameFieldNumber; const int Mixin::kRootFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Mixin::Mixin() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1677,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 (;;) { @@ -1801,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; @@ -1824,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) { @@ -1848,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); @@ -1916,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()); } @@ -1959,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 3c5a6f31..bb35e471 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -27,8 +27,8 @@ #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/unknown_field_set.h> -#include "google/protobuf/source_context.pb.h" -#include "google/protobuf/type.pb.h" +#include <google/protobuf/source_context.pb.h> +#include <google/protobuf/type.pb.h> // @@protoc_insertion_point(includes) namespace google { @@ -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/api.proto b/src/google/protobuf/api.proto index 597a6497..dbe87b8f 100644 --- a/src/google/protobuf/api.proto +++ b/src/google/protobuf/api.proto @@ -27,6 +27,7 @@ // 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"; package google.protobuf; @@ -34,11 +35,11 @@ package google.protobuf; import "google/protobuf/source_context.proto"; import "google/protobuf/type.proto"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "ApiProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; // Api is a light-weight descriptor for a protocol buffer service. @@ -75,6 +76,7 @@ message Api { // be omitted. Zero major versions must only be used for // experimental, none-GA apis. // + // string version = 4; // Source context for the protocol buffer service represented by this @@ -141,7 +143,6 @@ message Method { // // package google.storage.v2; // service Storage { -// // (-- see AccessControl.GetAcl --) // rpc GetAcl(GetAclRequest) returns (Acl); // // // Get a data record. 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 16e0d50e..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 { @@ -76,7 +77,7 @@ template<typename T> void arena_destruct_object(void* object) { template<typename T> void arena_delete_object(void* object) { delete reinterpret_cast<T*>(object); } -inline void arena_free(void* object, size_t size) { +inline void arena_free(void* object, size_t /* size */) { free(object); } @@ -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 @@ -490,27 +500,28 @@ class LIBPROTOBUF_EXPORT Arena { return GetArenaInternal(value, static_cast<T*>(0)); } - // Helper typetrait that indicates support for arenas in a type T at compile - // time. This is public only to allow construction of higher-level templated - // utilities. is_arena_constructable<T>::value is an instance of - // google::protobuf::internal::true_type if the message type T has arena support enabled, and - // google::protobuf::internal::false_type otherwise. - // - // 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 { + private: + struct InternalIsArenaConstructableHelper { template<typename U> static char ArenaConstructable( const typename U::InternalArenaConstructable_*); template<typename U> static double ArenaConstructable(...); + }; - // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. - typedef google::protobuf::internal::integral_constant<bool, - sizeof(ArenaConstructable<const T>(static_cast<const T*>(0))) == - sizeof(char)> type; - static const type value; + public: + // Helper typetrait that indicates support for arenas in a type T at compile + // time. This is public only to allow construction of higher-level templated + // utilities. is_arena_constructable<T>::value is true if the message type T + // has arena support enabled, and false otherwise. + // + // 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)> { }; private: @@ -572,34 +583,30 @@ class LIBPROTOBUF_EXPORT Arena { return google::protobuf::internal::has_trivial_destructor<T>::value; } - // Helper typetrait that indicates whether the desctructor of type T should be - // called when arena is destroyed at compile time. This is only to allow - // construction of higher-level templated utilities. - // is_destructor_skippable<T>::value is an instance of google::protobuf::internal::true_type if the - // destructor of the message type T should not be called when arena is - // destroyed or google::protobuf::internal::has_trivial_destructor<T>::value == true, and - // google::protobuf::internal::false_type otherwise. - // - // This is inside Arena because only Arena has the friend relationships - // necessary to see the underlying generated code traits. - template<typename T> - struct is_destructor_skippable { + private: + struct InternalIsDestructorSkippableHelper { template<typename U> static char DestructorSkippable( const typename U::DestructorSkippable_*); template<typename U> static double DestructorSkippable(...); - - // The raw_skippable_value const bool variable is separated from the typedef - // line below as a work-around of an NVCC 7.0 (and earlier) compiler bug. - static const bool raw_skippable_value = - sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) == - sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true; - // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. - typedef google::protobuf::internal::integral_constant<bool, raw_skippable_value> type; - static const type value; }; + public: + // Helper typetrait that indicates whether the desctructor of type T should be + // called when arena is destroyed at compile time. This is only to allow + // construction of higher-level templated utilities. + // is_destructor_skippable<T>::value is true if the destructor of the message + // type T should not be called when arena is destroyed or false otherwise. + // This is inside Arena because only Arena has the friend relationships + // necessary to see the underlying generated code traits. + template<typename T> + struct is_destructor_skippable + : public google::protobuf::internal::integral_constant< + bool, + sizeof(InternalIsDestructorSkippableHelper::DestructorSkippable< + const T>(static_cast<const T*>(0))) == sizeof(char) || + google::protobuf::internal::has_trivial_destructor<T>::value> {}; // CreateMessage<T> requires that T supports arenas, but this private method // works whether or not T supports arenas. These are not exposed to user code @@ -780,8 +787,10 @@ class LIBPROTOBUF_EXPORT Arena { // which needs to declare google::protobuf::Map as friend of generated message. template <typename T> static void CreateInArenaStorage(T* ptr, Arena* arena) { - CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value); - RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>::value); + CreateInArenaStorageInternal(ptr, arena, + typename is_arena_constructable<T>::type()); + RegisterDestructorInternal(ptr, arena, + typename is_destructor_skippable<T>::type()); } template <typename T> @@ -910,16 +919,6 @@ class LIBPROTOBUF_EXPORT Arena { // Defined above for supporting environments without RTTI. #undef RTTI_TYPE_ID -template<typename T> -const typename Arena::is_arena_constructable<T>::type - Arena::is_arena_constructable<T>::value = - typename Arena::is_arena_constructable<T>::type(); - -template<typename T> -const typename Arena::is_destructor_skippable<T>::type - Arena::is_destructor_skippable<T>::value = - typename Arena::is_destructor_skippable<T>::type(); - } // namespace protobuf } // namespace google 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 1dacdc68..590ffce9 100755 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -36,7 +36,6 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/fastmem.h> - #include <google/protobuf/arena.h> #include <google/protobuf/generated_message_util.h> @@ -65,7 +64,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { } // Basic accessors. - inline const ::std::string& Get(const ::std::string* default_value) const { + inline const ::std::string& Get(const ::std::string* /* default_value */) const { return *ptr_; } @@ -103,7 +102,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // state. Used to implement unsafe_arena_release_<field>() methods on // generated classes. inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value, - ::google::protobuf::Arena* arena) { + ::google::protobuf::Arena* /* arena */) { if (ptr_ == default_value) { return NULL; } @@ -135,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 { @@ -164,7 +164,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // the user) will always be the empty string. Assumes that |default_value| // is an empty string. inline void ClearToEmpty(const ::std::string* default_value, - ::google::protobuf::Arena* arena) { + ::google::protobuf::Arena* /* arena */) { if (ptr_ == default_value) { // Already set to default (which is empty) -- do nothing. } else { @@ -176,7 +176,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // overhead of heap operations. After this returns, the content (as seen by // the user) will always be equal to |default_value|. inline void ClearToDefault(const ::std::string* default_value, - ::google::protobuf::Arena* arena) { + ::google::protobuf::Arena* /* arena */) { if (ptr_ == default_value) { // Already set to default -- do nothing. } else { @@ -216,7 +216,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value); - inline const ::std::string& GetNoArena(const ::std::string* default_value) const { + inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const { return *ptr_; } 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 26a4f0b0..fcad6b61 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/stubs/platform_macros.h> #include <stdio.h> #include <sys/types.h> @@ -45,9 +46,14 @@ #include <unistd.h> #endif #include <errno.h> +#include <fstream> #include <iostream> #include <ctype.h> +#ifdef GOOGLE_PROTOBUF_ARCH_SPARC +#include <limits.h> //For PATH_MAX +#endif + #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> @@ -271,15 +277,35 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, // implements MultiFileErrorCollector ------------------------------ void AddError(const string& filename, int line, int column, const string& message) { + AddErrorOrWarning(filename, line, column, message, "error", std::cerr); + } + void AddWarning(const string& filename, int line, int column, + const string& message) { + AddErrorOrWarning(filename, line, column, message, "warning", std::clog); + } + + // implements io::ErrorCollector ----------------------------------- + void AddError(int line, int column, const string& message) { + AddError("input", line, column, message); + } + + void AddWarning(int line, int column, const string& message) { + AddErrorOrWarning("input", line, column, message, "warning", std::clog); + } + + private: + void AddErrorOrWarning( + const string& filename, int line, int column, + const string& message, const string& type, ostream& out) { // Print full path when running under MSVS string dfile; if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && tree_ != NULL && tree_->VirtualFileToDiskFile(filename, &dfile)) { - std::cerr << dfile; + out << dfile; } else { - std::cerr << filename; + out << filename; } // Users typically expect 1-based line/column numbers, so we add 1 @@ -288,24 +314,22 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, // Allow for both GCC- and Visual-Studio-compatible output. switch (format_) { case CommandLineInterface::ERROR_FORMAT_GCC: - std::cerr << ":" << (line + 1) << ":" << (column + 1); + out << ":" << (line + 1) << ":" << (column + 1); break; case CommandLineInterface::ERROR_FORMAT_MSVS: - std::cerr << "(" << (line + 1) - << ") : error in column=" << (column + 1); + out << "(" << (line + 1) << ") : " + << type << " in column=" << (column + 1); break; } } - std::cerr << ": " << message << std::endl; - } - - // implements io::ErrorCollector ----------------------------------- - void AddError(int line, int column, const string& message) { - AddError("input", line, column, message); + if (type == "warning") { + out << ": warning: " << message << std::endl; + } else { + out << ": " << message << std::endl; + } } - private: const ErrorFormat format_; DiskSourceTree *tree_; }; @@ -925,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." @@ -944,7 +974,7 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { return PARSE_ARGUMENT_FAIL; } else { ++i; - value = argv[i]; + value = arguments[i]; } } @@ -1353,7 +1383,7 @@ void CommandLineInterface::PrintHelpText() { " defined in the given proto files. Groups share\n" " the same field number space with the parent \n" " message. Extension ranges are counted as \n" -" occupied fields numbers." +" occupied fields numbers.\n" << std::endl; if (!plugin_prefix_.empty()) { std::cerr << @@ -1443,6 +1473,7 @@ bool CommandLineInterface::GenerateDependencyManifestFile( for (int i = 0; i < parsed_files.size(); i++) { GetTransitiveDependencies(parsed_files[i], false, + false, &already_seen, file_set.mutable_file()); } @@ -1522,6 +1553,7 @@ bool CommandLineInterface::GeneratePluginOutput( for (int i = 0; i < parsed_files.size(); i++) { request.add_file_to_generate(parsed_files[i]->name()); GetTransitiveDependencies(parsed_files[i], + true, // Include json_name for plugins. true, // Include source code info. &already_seen, request.mutable_proto_file()); } @@ -1654,6 +1686,7 @@ bool CommandLineInterface::WriteDescriptorSet( set<const FileDescriptor*> already_seen; for (int i = 0; i < parsed_files.size(); i++) { GetTransitiveDependencies(parsed_files[i], + true, // Include json_name source_info_in_descriptor_set_, &already_seen, file_set.mutable_file()); } @@ -1665,6 +1698,7 @@ bool CommandLineInterface::WriteDescriptorSet( } FileDescriptorProto* file_proto = file_set.add_file(); parsed_files[i]->CopyTo(file_proto); + parsed_files[i]->CopyJsonNameTo(file_proto); if (source_info_in_descriptor_set_) { parsed_files[i]->CopySourceCodeInfoTo(file_proto); } @@ -1699,7 +1733,9 @@ bool CommandLineInterface::WriteDescriptorSet( } void CommandLineInterface::GetTransitiveDependencies( - const FileDescriptor* file, bool include_source_code_info, + const FileDescriptor* file, + bool include_json_name, + bool include_source_code_info, set<const FileDescriptor*>* already_seen, RepeatedPtrField<FileDescriptorProto>* output) { if (!already_seen->insert(file).second) { @@ -1709,13 +1745,18 @@ void CommandLineInterface::GetTransitiveDependencies( // Add all dependencies. for (int i = 0; i < file->dependency_count(); i++) { - GetTransitiveDependencies(file->dependency(i), include_source_code_info, + GetTransitiveDependencies(file->dependency(i), + include_json_name, + include_source_code_info, already_seen, output); } // Add this file. FileDescriptorProto* new_descriptor = output->Add(); file->CopyTo(new_descriptor); + if (include_json_name) { + file->CopyJsonNameTo(new_descriptor); + } if (include_source_code_info) { file->CopySourceCodeInfoTo(new_descriptor); } diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index 7e611c44..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. @@ -262,8 +263,11 @@ class LIBPROTOC_EXPORT CommandLineInterface { // in order. Any files in *already_seen will not be added, and each file // added will be inserted into *already_seen. If include_source_code_info is // true then include the source code information in the FileDescriptorProtos. + // If include_json_name is true, populate the json_name field of + // FieldDescriptorProto for all fields. static void GetTransitiveDependencies( const FileDescriptor* file, + bool include_json_name, bool include_source_code_info, set<const FileDescriptor*>* already_seen, RepeatedPtrField<FileDescriptorProto>* output); diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 46ea5c4e..9b504d25 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -60,17 +60,19 @@ #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> -// 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 { +// 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 + #if defined(_WIN32) #ifndef STDIN_FILENO #define STDIN_FILENO 0 @@ -294,6 +296,10 @@ void CommandLineInterfaceTest::Run(const string& command) { if (!disallow_plugins_) { cli_.AllowPlugins("prefix-"); #ifndef GOOGLE_THIRD_PARTY_PROTOBUF + string plugin_path; +#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH + plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH; +#else const char* possible_paths[] = { // When building with shared libraries, libtool hides the real executable // in .libs and puts a fake wrapper in the current directory. @@ -311,15 +317,13 @@ void CommandLineInterfaceTest::Run(const string& command) { "test_plugin.exe", // Other Win32 (MSVC) "test_plugin", // Unix }; - - string plugin_path; - for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) { if (access(possible_paths[i], F_OK) == 0) { plugin_path = possible_paths[i]; break; } } +#endif if (plugin_path.empty()) { #else @@ -374,7 +378,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) { @@ -884,6 +890,10 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); // Descriptor set should not have source code info. EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); + // Descriptor set should have json_name. + EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name()); + EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name()); + EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name()); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { @@ -917,6 +927,10 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { EXPECT_EQ("baz.proto", descriptor_set.file(2).name()); // Descriptor set should not have source code info. EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); + // Descriptor set should have json_name. + EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name()); + EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name()); + EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name()); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { @@ -1080,6 +1094,7 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { } #endif // !_WIN32 + // ------------------------------------------------------------------- TEST_F(CommandLineInterfaceTest, ParseErrors) { @@ -1411,6 +1426,18 @@ TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) { "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1."); } +TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_HasJsonName {\n" + " optional int32 value = 1;\n" + "}\n"); + + Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw json_name: 1"); +} + TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { // Test what happens if the plugin isn't found. @@ -1800,8 +1827,8 @@ TEST_F(EncodeDecodeTest, ProtoParseError) { } // anonymous namespace +#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN + } // namespace compiler } // namespace protobuf - -#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index c3e9fe74..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> @@ -107,7 +108,7 @@ class MockGeneratorContext : public GeneratorContext { virtual io::ZeroCopyOutputStream* Open(const string& filename) { string** map_slot = &files_[filename]; - if (*map_slot != NULL) delete *map_slot; + delete *map_slot; *map_slot = new string; return new io::StringOutputStream(*map_slot); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index de4d7cc7..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" @@ -178,12 +183,16 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { map<string, string> vars; vars["nested_name"] = descriptor_->name(); vars["classname"] = classname_; + vars["constexpr"] = options_.proto_h ? "constexpr " : ""; printer->Print(vars, "typedef $classname$ $nested_name$;\n"); 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 const $nested_name$ $tag$ = $classname$_$tag$;\n"); + "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n" + " $classname$_$tag$;\n"); } printer->Print(vars, @@ -200,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" @@ -237,8 +248,9 @@ void EnumGenerator::GenerateDescriptorInitializer( void EnumGenerator::GenerateMethods(io::Printer* printer) { map<string, string> vars; 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" @@ -278,16 +290,16 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { if (descriptor_->containing_type() != NULL) { // We need to "define" the static constants which were declared in the // header, to give the linker a place to put them. Or at least the C++ - // standard says we have to. MSVC actually insists tha we do _not_ define - // them again in the .cc file. - printer->Print("#ifndef _MSC_VER\n"); + // standard says we have to. MSVC actually insists that we do _not_ define + // them again in the .cc file, prior to VC++ 2015. + printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); vars["parent"] = ClassName(descriptor_->containing_type(), false); vars["nested_name"] = descriptor_->name(); for (int i = 0; i < descriptor_->value_count(); i++) { vars["value"] = EnumValueName(descriptor_->value(i)); printer->Print(vars, - "const $classname$ $parent$::$value$;\n"); + "$constexpr$const $classname$ $parent$::$value$;\n"); } printer->Print(vars, "const $classname$ $parent$::$nested_name$_MIN;\n" @@ -297,7 +309,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { "const int $parent$::$nested_name$_ARRAYSIZE;\n"); } - printer->Print("#endif // _MSC_VER\n"); + printer->Print("#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\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_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 468ca484..c42f1627 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -155,7 +155,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { // Likewise, class members need to declare the field constant variable. if (descriptor_->extension_scope() != NULL) { printer->Print(vars, - "#ifndef _MSC_VER\n" + "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n" "const int $scope$$constant_name$;\n" "#endif\n"); } 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 8e8bd8b7..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,6 +242,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { } void FileGenerator::GenerateSource(io::Printer* printer) { + const bool use_system_include = IsWellKnownMessage(file_); string header = StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( @@ -246,24 +252,27 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // The generated code calls accessors that might be deprecated. We don't // want the compiler to warn in generated code. "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" - "#include \"$header$\"\n" + "#include $left$$header$$right$\n" "\n" "#include <algorithm>\n" // for swap() "\n" "#include <google/protobuf/stubs/common.h>\n" + "#include <google/protobuf/stubs/port.h>\n" "#include <google/protobuf/stubs/once.h>\n" "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), - "header", header); + "header", header, + "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" @@ -288,7 +297,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { GenerateNamespaceOpeners(printer); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" @@ -302,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", @@ -327,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" @@ -352,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"); @@ -397,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(), @@ -427,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) { @@ -449,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", @@ -482,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); } @@ -548,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(); @@ -580,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. @@ -674,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) { @@ -747,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( @@ -795,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 { @@ -814,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 { @@ -824,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 { @@ -833,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"); } @@ -846,7 +859,20 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (IsAnyMessage(file_)) { printer->Print( - "#include \"google/protobuf/any.h\"\n"); + "#include <google/protobuf/any.h>\n"); + } +} + +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); } } @@ -857,14 +883,17 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { } for (int i = 0; i < file_->dependency_count(); 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 \"$dependency$.pb.h\"$iwyu$\n", + "#include $left$$dependency$.pb.h$right$$iwyu$\n", "dependency", StripProto(name), - "iwyu", (public_import) ? " // IWYU pragma: export" : ""); + "iwyu", (public_import) ? " // IWYU pragma: export" : "", + "left", use_system_include ? "<" : "\"", + "right", use_system_include ? ">" : "\""); } } @@ -891,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); } } @@ -924,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 09845458..2ad4d36a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -54,6 +54,7 @@ namespace { static const char kAnyMessageName[] = "Any"; static const char kAnyProtoFile[] = "google/protobuf/any.proto"; +static const char kGoogleProtobufPrefix[] = "google/protobuf/"; string DotsToUnderscores(const string& name) { return StringReplace(name, ".", "_", true); @@ -67,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() { @@ -170,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() { @@ -484,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) { @@ -497,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; @@ -509,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( @@ -600,6 +606,10 @@ bool IsAnyMessage(const Descriptor* descriptor) { descriptor->file()->name() == kAnyProtoFile; } +bool IsWellKnownMessage(const FileDescriptor* descriptor) { + return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix); +} + enum Utf8CheckMode { STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields. VERIFY = 1, // Only log an error but parsing will succeed. @@ -607,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 { @@ -619,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_("); @@ -669,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 985cb04c..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) { @@ -265,19 +278,25 @@ inline bool SupportsArenas(const FieldDescriptor* field) { bool IsAnyMessage(const FileDescriptor* descriptor); bool IsAnyMessage(const Descriptor* 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); +bool IsWellKnownMessage(const FileDescriptor* descriptor); + +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 8cc8c7ba..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", @@ -1772,12 +1775,29 @@ GenerateShutdownCode(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + // mutable_unknown_fields wrapper function for LazyStringOutputStream + // callback. + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file(), options_)) { + printer->Print( + "static ::std::string* MutableUnknownFieldsFor$classname$(\n" + " $classname$* ptr) {\n" + " return ptr->mutable_unknown_fields();\n" + "}\n" + "\n", + "classname", classname_); + } if (IsAnyMessage(descriptor_)) { printer->Print( "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" " _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" @@ -1807,7 +1827,7 @@ GenerateClassMethods(io::Printer* printer) { } // Generate field number constants. - printer->Print("#ifndef _MSC_VER\n"); + printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor *field = descriptor_->field(i); printer->Print( @@ -1816,7 +1836,7 @@ GenerateClassMethods(io::Printer* printer) { "constant_name", FieldConstantName(field)); } printer->Print( - "#endif // !_MSC_VER\n" + "#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n" "\n"); // Define extension identifiers. @@ -1832,7 +1852,7 @@ GenerateClassMethods(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { GenerateClear(printer); printer->Print("\n"); @@ -1842,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"); } @@ -1863,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" @@ -1888,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++) { @@ -1941,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"); @@ -1986,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" @@ -2017,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 @@ -2101,7 +2120,7 @@ GenerateStructors(io::Printer* printer) { superclass = DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - superclass = SuperClassName(descriptor_); + superclass = SuperClassName(descriptor_, options_); } string initializer_with_arena = superclass + "()"; @@ -2109,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)"; @@ -2129,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_)"; @@ -2183,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); } @@ -2216,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_)) { @@ -2267,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" @@ -2285,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" @@ -2334,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 @@ -2372,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" @@ -2501,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" @@ -2531,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"); @@ -2617,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); @@ -2638,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"); @@ -2665,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 @@ -2683,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"); @@ -2704,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 @@ -2807,14 +2842,16 @@ 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" "}\n"); } else { printer->Print( - "mutable_unknown_fields()->append(from.unknown_fields());\n"); + "if (!from.unknown_fields().empty()) {\n" + " mutable_unknown_fields()->append(from.unknown_fields());\n" + "}\n"); } } @@ -2824,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( @@ -2843,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( @@ -2866,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"); @@ -2884,16 +2925,22 @@ 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())) { - printer->Print( - " ::google::protobuf::io::StringOutputStream unknown_fields_string(\n" - " mutable_unknown_fields());\n" + 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. + printer->Print( + " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" + " ::google::protobuf::internal::NewPermanentCallback(\n" + " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" - " &unknown_fields_string);\n"); + " &unknown_fields_string, false);\n", + "classname", classname_); } printer->Print( @@ -3111,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" @@ -3145,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"); @@ -3238,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"); @@ -3278,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" @@ -3344,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) { @@ -3364,7 +3411,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } else { printer->Print( "output->WriteRaw(unknown_fields().data(),\n" - " unknown_fields().size());\n"); + " static_cast<int>(unknown_fields().size()));\n"); } } } @@ -3411,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" @@ -3433,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++) { @@ -3457,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" @@ -3634,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" @@ -3700,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 new file mode 100644 index 00000000..edd30780 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -0,0 +1,242 @@ +// 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 <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif + +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl_lite.h> +#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> + +namespace google { +namespace protobuf { +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 +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto deleted file mode 100644 index cb6ca1b1..00000000 --- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto +++ /dev/null @@ -1,43 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Test that proto2 compiler can generate valid code when the enum value -// is INT_MAX. Note that this is a compile-only test and this proto is not -// referenced in any C++ code. -syntax = "proto2"; - -package protobuf_unittest; - -message TestLargeEnumValue { - enum EnumWithLargeValue { - VALUE_1 = 1; - VALUE_MAX = 0x7fffffff; - } -} diff --git a/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc index 9ad2cbb5..587e0222 100644 --- a/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc +++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc @@ -56,10 +56,26 @@ void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) { // node of a summary element, not part of an attribute. comments = StringReplace(comments, "&", "&", true); comments = StringReplace(comments, "<", "<", true); - vector<string> lines = Split(comments, "\n"); + vector<string> lines = Split(comments, "\n", false /* skip_empty */); + // TODO: We really should work out which part to put in the summary and which to put in the remarks... + // but that needs to be part of a bigger effort to understand the markdown better anyway. printer->Print("/// <summary>\n"); + bool last_was_empty = false; + // We squash multiple blank lines down to one, and remove any trailing blank lines. We need + // to preserve the blank lines themselves, as this is relevant in the markdown. + // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too. + // (We don't skip "just whitespace" lines, either.) for (std::vector<string>::iterator it = lines.begin(); it != lines.end(); ++it) { - printer->Print("/// $line$\n", "line", *it); + string line = *it; + if (line.empty()) { + last_was_empty = true; + } else { + if (last_was_empty) { + printer->Print("///\n"); + } + last_was_empty = false; + printer->Print("/// $line$\n", "line", *it); + } } printer->Print("/// </summary>\n"); } 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 95ff48ae..d74e8c88 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -41,7 +41,8 @@ #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_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> +#include <google/protobuf/compiler/csharp/csharp_reflection_class.h> using google::protobuf::internal::scoped_ptr; @@ -50,45 +51,11 @@ namespace protobuf { namespace compiler { namespace csharp { -std::string GetOutputFile( - const google::protobuf::FileDescriptor* file, - const std::string file_extension, - const bool generate_directories, - const std::string base_namespace, - string* error) { - string relative_filename = GetUmbrellaClassUnqualifiedName(file) + file_extension; - if (!generate_directories) { - return relative_filename; - } - string ns = GetFileNamespace(file); - string namespace_suffix = ns; - if (!base_namespace.empty()) { - // Check that the base_namespace is either equal to or a leading part of - // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't - // be regarded as a prefix of "Foo.Bar". The simplest option is to add "." - // to both. - string extended_ns = ns + "."; - if (extended_ns.find(base_namespace + ".") != 0) { - *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace; - return ""; // This will be ignored, because we've set an error. - } - namespace_suffix = ns.substr(base_namespace.length()); - if (namespace_suffix.find(".") == 0) { - namespace_suffix = namespace_suffix.substr(1); - } - } - - string namespace_dir = StringReplace(namespace_suffix, ".", "/", true); - if (!namespace_dir.empty()) { - namespace_dir += "/"; - } - return namespace_dir + relative_filename; -} - void GenerateFile(const google::protobuf::FileDescriptor* file, - io::Printer* printer) { - UmbrellaClassGenerator umbrellaGenerator(file); - umbrellaGenerator.Generate(printer); + io::Printer* printer, + const Options* options) { + ReflectionClassGenerator reflectionClassGenerator(file, options); + reflectionClassGenerator.Generate(printer); } bool Generator::Generate( @@ -106,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; @@ -122,8 +93,13 @@ bool Generator::Generate( } string filename_error = ""; - std::string filename = GetOutputFile(file, file_extension, generate_directories, base_namespace, &filename_error); - if (!filename_error.empty()) { + 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; } @@ -131,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 333b4912..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> @@ -117,43 +118,19 @@ std::string GetFileNamespace(const FileDescriptor* descriptor) { return UnderscoresToCamelCase(descriptor->package(), true, true); } -std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor) { - // We manually rename Descriptor to DescriptorProtoFile to avoid collisions with - // the static Descriptor property. It would be nice to be able to do this with an - // option, but it would be rarely used. - if (IsDescriptorProto(descriptor)) { - return "DescriptorProtoFile"; - } - // umbrella_classname can no longer be set using message option. - std::string proto_file = descriptor->name(); - int lastslash = proto_file.find_last_of("/"); - std::string base = proto_file.substr(lastslash + 1); - return UnderscoresToPascalCase(StripDotProto(base)); +// Returns the Pascal-cased last part of the proto file. For example, +// input of "google/protobuf/foo_bar.proto" would result in "FooBar". +std::string GetFileNameBase(const FileDescriptor* descriptor) { + std::string proto_file = descriptor->name(); + int lastslash = proto_file.find_last_of("/"); + std::string base = proto_file.substr(lastslash + 1); + return UnderscoresToPascalCase(StripDotProto(base)); } -std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor) { - // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option - bool collision = false; - std::string umbrella_classname = GetUmbrellaClassUnqualifiedName(descriptor); - for(int i = 0; i < descriptor->message_type_count(); i++) { - if (descriptor->message_type(i)->name() == umbrella_classname) { - collision = true; - break; - } - } - for (int i = 0; i < descriptor->service_count(); i++) { - if (descriptor->service(i)->name() == umbrella_classname) { - collision = true; - break; - } - } - for (int i = 0; i < descriptor->enum_type_count(); i++) { - if (descriptor->enum_type(i)->name() == umbrella_classname) { - collision = true; - break; - } - } - return collision ? "Proto" : ""; +std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) { + // TODO: Detect collisions with existing messages, + // and append an underscore if necessary. + return GetFileNameBase(descriptor) + "Reflection"; } // TODO(jtattermusch): can we reuse a utility function? @@ -201,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 != "") { @@ -218,16 +293,12 @@ std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { return "global::" + result; } -std::string GetUmbrellaClassName(const FileDescriptor* descriptor) { +std::string GetReflectionClassName(const FileDescriptor* descriptor) { std::string result = GetFileNamespace(descriptor); if (!result.empty()) { result += '.'; } - std::string umbrellaNamespace = GetUmbrellaClassNestedNamespace(descriptor); - if (!umbrellaNamespace.empty()) { - result += umbrellaNamespace + "."; - } - result += GetUmbrellaClassUnqualifiedName(descriptor); + result += GetReflectionClassUnqualifiedName(descriptor); return "global::" + result; } @@ -269,6 +340,41 @@ std::string GetPropertyName(const FieldDescriptor* descriptor) { return property_name; } +std::string GetOutputFile( + const google::protobuf::FileDescriptor* descriptor, + const std::string file_extension, + const bool generate_directories, + const std::string base_namespace, + string* error) { + string relative_filename = GetFileNameBase(descriptor) + file_extension; + if (!generate_directories) { + return relative_filename; + } + string ns = GetFileNamespace(descriptor); + string namespace_suffix = ns; + if (!base_namespace.empty()) { + // Check that the base_namespace is either equal to or a leading part of + // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't + // be regarded as a prefix of "Foo.Bar". The simplest option is to add "." + // to both. + string extended_ns = ns + "."; + if (extended_ns.find(base_namespace + ".") != 0) { + *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace; + return ""; // This will be ignored, because we've set an error. + } + namespace_suffix = ns.substr(base_namespace.length()); + if (namespace_suffix.find(".") == 0) { + namespace_suffix = namespace_suffix.substr(1); + } + } + + string namespace_dir = StringReplace(namespace_suffix, ".", "/", true); + if (!namespace_dir.empty()) { + namespace_dir += "/"; + } + return namespace_dir + relative_filename; +} + // TODO: c&p from Java protoc plugin // For encodings with fixed sizes, returns that size in bytes. Otherwise // returns -1. @@ -345,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 e293faca..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. @@ -69,14 +71,8 @@ CSharpType GetCSharpType(FieldDescriptor::Type type); std::string StripDotProto(const std::string& proto_file); -// Gets unqualified name of the umbrella class -std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor); - -// Gets name of the nested for umbrella class (just the nested part, -// not including the GetFileNamespace part). -std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor); - -std::string GetClassName(const Descriptor* descriptor); +// Gets unqualified name of the reflection class +std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor); std::string GetClassName(const EnumDescriptor* descriptor); @@ -88,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); @@ -96,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 b493495d..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,9 +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); - variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : ""; - 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_, @@ -76,7 +78,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { printer->Print( variables_, ", $tag$);\n" - "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n"); + "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n"); WritePropertyDocComment(printer, descriptor_); AddDeprecatedFlag(printer); printer->Print( 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 21fbf7e3..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 @@ -119,7 +120,7 @@ void MessageGenerator::Generate(io::Printer* printer) { // Access the message descriptor via the relevant file descriptor or containing message descriptor. if (!descriptor_->containing_type()) { - vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file()) + vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file()) + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]"; } else { vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type()) @@ -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++) { @@ -323,6 +327,10 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { CreateFieldGeneratorInternal(descriptor_->field(i))); generator->WriteEquals(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n", + "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); + } printer->Outdent(); printer->Print( " return true;\n" @@ -339,13 +347,17 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { CreateFieldGeneratorInternal(descriptor_->field(i))); generator->WriteHash(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print("hash ^= (int) $name$Case_;\n", + "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false)); + } printer->Print("return hash;\n"); printer->Outdent(); printer->Print("}\n\n"); printer->Print( "public override string ToString() {\n" - " return pb::JsonFormatter.Default.Format(this);\n" + " return pb::JsonFormatter.ToDiagnosticString(this);\n" "}\n\n"); } @@ -441,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( @@ -482,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_names.h b/src/google/protobuf/compiler/csharp/csharp_names.h index ccd2e720..30805187 100644 --- a/src/google/protobuf/compiler/csharp/csharp_names.h +++ b/src/google/protobuf/compiler/csharp/csharp_names.h @@ -72,7 +72,28 @@ string GetClassName(const Descriptor* descriptor); // The fully-qualified name of the C# class that provides // access to the file descriptor. Proto compiler generates // such class for each .proto file processed. -std::string GetUmbrellaClassName(const FileDescriptor* descriptor); +string GetReflectionClassName(const FileDescriptor* descriptor); + +// Generates output file name for given file descriptor. If generate_directories +// is true, the output file will be put under directory corresponding to file's +// namespace. base_namespace can be used to strip some of the top level +// directories. E.g. for file with namespace "Bar.Foo" and base_namespace="Bar", +// the resulting file will be put under directory "Foo" (and not "Bar/Foo"). +// +// Requires: +// descriptor != NULL +// error != NULL +// +// Returns: +// The file name to use as output file for given file descriptor. In case +// of failure, this function will return empty string and error parameter +// will contain the error message. +string GetOutputFile( + const google::protobuf::FileDescriptor* descriptor, + const string file_extension, + const bool generate_directories, + const string base_namespace, + string* error); } // namespace csharp } // namespace compiler 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 76d5b247..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; @@ -83,7 +84,7 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { } else { printer->Print( variables_, - " $name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n"); + " $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n"); } printer->Print( " }\n" @@ -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_); } @@ -186,7 +187,7 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { } else { printer->Print( variables_, - " $oneof_name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n"); + " $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n"); } printer->Print( 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_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index 7cf101b0..f7397c0f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -43,25 +43,26 @@ #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_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_options.h> +#include <google/protobuf/compiler/csharp/csharp_reflection_class.h> namespace google { namespace protobuf { namespace compiler { namespace csharp { -UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file) - : SourceGeneratorBase(file), +ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file, + const Options* options) + : SourceGeneratorBase(file, options), file_(file) { namespace_ = GetFileNamespace(file); - umbrellaClassname_ = GetUmbrellaClassUnqualifiedName(file); - umbrellaNamespace_ = GetUmbrellaClassNestedNamespace(file); + reflectionClassname_ = GetReflectionClassUnqualifiedName(file); } -UmbrellaClassGenerator::~UmbrellaClassGenerator() { +ReflectionClassGenerator::~ReflectionClassGenerator() { } -void UmbrellaClassGenerator::Generate(io::Printer* printer) { +void ReflectionClassGenerator::Generate(io::Printer* printer) { WriteIntroduction(printer); WriteDescriptor(printer); @@ -69,17 +70,11 @@ void UmbrellaClassGenerator::Generate(io::Printer* printer) { printer->Outdent(); printer->Print("}\n"); - // Close the namespace around the umbrella class if defined - if (!umbrellaNamespace_.empty()) { - printer->Outdent(); - printer->Print("}\n"); - } - // write children: Enums 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"); @@ -90,7 +85,7 @@ void UmbrellaClassGenerator::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"); @@ -107,7 +102,7 @@ void UmbrellaClassGenerator::Generate(io::Printer* printer) { printer->Print("#endregion Designer generated code\n"); } -void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) { +void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) { printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $file_name$\n" @@ -126,28 +121,20 @@ void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) { printer->Print("\n"); } - // Add the namespace around the umbrella class if defined - if (!umbrellaNamespace_.empty()) { - printer->Print("namespace $umbrella_namespace$ {\n", - "umbrella_namespace", umbrellaNamespace_); - printer->Indent(); - printer->Print("\n"); - } - printer->Print( "/// <summary>Holder for reflection information generated from $file_name$</summary>\n" "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n", "file_name", file_->name()); WriteGeneratedCodeAttributes(printer); printer->Print( - "$access_level$ static partial class $umbrella_class_name$ {\n" + "$access_level$ static partial class $reflection_class_name$ {\n" "\n", "access_level", class_access_level(), - "umbrella_class_name", umbrellaClassname_); + "reflection_class_name", reflectionClassname_); printer->Indent(); } -void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { +void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) { printer->Print( "#region Descriptor\n" "/// <summary>File descriptor for $file_name$</summary>\n" @@ -156,9 +143,9 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { "}\n" "private static pbr::FileDescriptor descriptor;\n" "\n" - "static $umbrella_class_name$() {\n", + "static $reflection_class_name$() {\n", "file_name", file_->name(), - "umbrella_class_name", umbrellaClassname_); + "reflection_class_name", reflectionClassname_); printer->Indent(); printer->Print( "byte[] descriptorData = global::System.Convert.FromBase64String(\n"); @@ -181,7 +168,7 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { // ----------------------------------------------------------------- // Invoke InternalBuildGeneratedFileFrom() to build the file. printer->Print( - "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n"); + "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n"); printer->Print(" new pbr::FileDescriptor[] { "); for (int i = 0; i < file_->dependency_count(); i++) { // descriptor.proto is special: we don't allow access to the generated code, but there's @@ -191,13 +178,13 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, "); } else { printer->Print( - "$full_umbrella_class_name$.Descriptor, ", - "full_umbrella_class_name", - GetUmbrellaClassName(file_->dependency(i))); + "$full_reflection_class_name$.Descriptor, ", + "full_reflection_class_name", + GetReflectionClassName(file_->dependency(i))); } } printer->Print("},\n" - " new pbr::GeneratedCodeInfo("); + " new pbr::GeneratedClrTypeInfo("); // Specify all the generated code information, recursively. if (file_->enum_type_count() > 0) { printer->Print("new[] {"); @@ -210,7 +197,7 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { printer->Print("null, "); } if (file_->message_type_count() > 0) { - printer->Print("new pbr::GeneratedCodeInfo[] {\n"); + printer->Print("new pbr::GeneratedClrTypeInfo[] {\n"); printer->Indent(); printer->Indent(); printer->Indent(); @@ -241,13 +228,13 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { // The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate // context. It governs whether or not a trailing comma and newline is written after the constructor, effectively // just controlling the formatting in the generated code. -void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) { +void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) { if (IsMapEntryMessage(descriptor)) { printer->Print("null, "); return; } // Generated message type - printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), ", "type_name", GetClassName(descriptor)); + printer->Print("new pbr::GeneratedClrTypeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor)); // Fields if (descriptor->field_count() > 0) { @@ -288,7 +275,7 @@ void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor // Nested types if (descriptor->nested_type_count() > 0) { // Need to specify array type explicitly here, as all elements may be null. - printer->Print("new pbr::GeneratedCodeInfo[] { "); + printer->Print("new pbr::GeneratedClrTypeInfo[] { "); for (int i = 0; i < descriptor->nested_type_count(); i++) { WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1); } diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h index b8bd2133..e0c69f31 100644 --- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h @@ -28,8 +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. -#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ -#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ #include <string> @@ -41,10 +41,10 @@ namespace protobuf { namespace compiler { namespace csharp { -class UmbrellaClassGenerator : public SourceGeneratorBase { +class ReflectionClassGenerator : public SourceGeneratorBase { public: - UmbrellaClassGenerator(const FileDescriptor* file); - ~UmbrellaClassGenerator(); + ReflectionClassGenerator(const FileDescriptor* file, const Options* options); + ~ReflectionClassGenerator(); void Generate(io::Printer* printer); @@ -52,14 +52,15 @@ class UmbrellaClassGenerator : public SourceGeneratorBase { const FileDescriptor* file_; std::string namespace_; - std::string umbrellaClassname_; - std::string umbrellaNamespace_; + std::string reflectionClassname_; 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(UmbrellaClassGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator); }; } // namespace csharp @@ -67,4 +68,4 @@ class UmbrellaClassGenerator : public SourceGeneratorBase { } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__ 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.cc b/src/google/protobuf/compiler/importer.cc index 8333684e..0d9093c0 100644 --- a/src/google/protobuf/compiler/importer.cc +++ b/src/google/protobuf/compiler/importer.cc @@ -185,6 +185,19 @@ void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError( owner_->error_collector_->AddError(filename, line, column, message); } +void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning( + const string& filename, + const string& element_name, + const Message* descriptor, + ErrorLocation location, + const string& message) { + if (owner_->error_collector_ == NULL) return; + + int line, column; + owner_->source_locations_.Find(descriptor, location, &line, &column); + owner_->error_collector_->AddWarning(filename, line, column, message); +} + // =================================================================== Importer::Importer(SourceTree* source_tree, diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h index f010fd08..cc8fcc39 100644 --- a/src/google/protobuf/compiler/importer.h +++ b/src/google/protobuf/compiler/importer.h @@ -121,6 +121,12 @@ class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabas ErrorLocation location, const string& message); + virtual void AddWarning(const string& filename, + const string& element_name, + const Message* descriptor, + ErrorLocation location, + const string& message); + private: SourceTreeDescriptorDatabase* owner_; }; @@ -188,6 +194,9 @@ class LIBPROTOBUF_EXPORT MultiFileErrorCollector { virtual void AddError(const string& filename, int line, int column, const string& message) = 0; + virtual void AddWarning(const string& filename, int line, int column, + const string& message) {} + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector); }; diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 33c9328f..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 { @@ -71,6 +72,7 @@ class MockErrorCollector : public MultiFileErrorCollector { ~MockErrorCollector() {} string text_; + string warning_text_; // implements ErrorCollector --------------------------------------- void AddError(const string& filename, int line, int column, @@ -78,6 +80,12 @@ class MockErrorCollector : public MultiFileErrorCollector { strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column, message); } + + void AddWarning(const string& filename, int line, int column, + const string& message) { + strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n", + filename, line, column, message); + } }; // ------------------------------------------------------------------- @@ -123,6 +131,7 @@ class ImporterTest : public testing::Test { // Return the collected error text string error() const { return error_collector_.text_; } + string warning() const { return error_collector_.warning_text_; } MockErrorCollector error_collector_; MockSourceTree source_tree_; 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 c06988c8..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); @@ -85,19 +86,22 @@ EnumGenerator::~EnumGenerator() {} void EnumGenerator::Generate(io::Printer* printer) { WriteEnumDocComment(printer, descriptor_); - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public enum $classname$\n" - " implements com.google.protobuf.ProtocolMessageEnum {\n", - "classname", descriptor_->name()); - } else { - printer->Print( - "public enum $classname$\n" - " implements com.google.protobuf.Internal.EnumLite {\n", - "classname", descriptor_->name()); - } + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", + "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(); @@ -107,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( @@ -147,16 +160,28 @@ 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" @@ -198,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 @@ -240,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", @@ -315,17 +341,27 @@ void EnumGenerator::Generate(io::Printer* printer) { "}\n" "\n"); - // index is only used for reflection; lite implementation does not need it - 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 ae53b11b..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. @@ -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$.forNumber((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$.forNumber((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" @@ -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"); } 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 27c992bc..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. @@ -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."; } @@ -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$.forNumber((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:: @@ -596,9 +588,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - // TODO(dweis): Switch to IntList? - "private com.google.protobuf.Internal.ProtobufList<\n" - " java.lang.Integer> $name$_;\n" + "private com.google.protobuf.Internal.IntList $name$_;\n" "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$> $name$_converter_ =\n" " new com.google.protobuf.Internal.ListAdapter.Converter<\n" @@ -623,7 +613,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $name$_converter_.convert($name$_.get(index));\n" + " return $name$_converter_.convert($name$_.getInt(index));\n" "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); @@ -635,12 +625,12 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public int get$capitalized_name$Value(int index) {\n" - " return $name$_.get(index);\n" + " return $name$_.getInt(index);\n" "}\n"); } if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); } @@ -649,7 +639,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"); WriteFieldDocComment(printer, descriptor_); @@ -660,7 +651,7 @@ GenerateMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.set(index, value.getNumber());\n" + " $name$_.setInt(index, value.getNumber());\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -669,7 +660,7 @@ GenerateMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value.getNumber());\n" + " $name$_.addInt(value.getNumber());\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -677,13 +668,13 @@ GenerateMembers(io::Printer* printer) const { " java.lang.Iterable<? extends $type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" " for ($type$ value : values) {\n" - " $name$_.add(value.getNumber());\n" + " $name$_.addInt(value.getNumber());\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "private void clear$capitalized_name$() {\n" - " $name$_ = emptyProtobufList();\n" + " $name$_ = emptyIntList();\n" "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { @@ -692,13 +683,13 @@ GenerateMembers(io::Printer* printer) const { "private void set$capitalized_name$Value(\n" " int index, int value) {\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.set(index, value);\n" + " $name$_.setInt(index, value);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "private void add$capitalized_name$Value(int value) {\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.addInt(value);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -706,7 +697,7 @@ GenerateMembers(io::Printer* printer) const { " java.lang.Iterable<java.lang.Integer> values) {\n" " ensure$capitalized_name$IsMutable();\n" " for (int value : values) {\n" - " $name$_.add(value);\n" + " $name$_.addInt(value);\n" " }\n" "}\n"); } @@ -805,26 +796,13 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateInitializationCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = emptyProtobufList();\n"); + printer->Print(variables_, "$name$_ = emptyIntList();\n"); } 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:: @@ -836,35 +814,35 @@ 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$_ = newProtobufList();\n" - "}\n" - "$name$_.add(rawValue);\n"); + "$name$_.addInt(input.readEnum());\n"); } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" "$type$ value = $type$.forNumber(rawValue);\n" - "if (value == null) {\n"); - if (PreserveUnknownFields(descriptor_->containing_type())) { - printer->Print(variables_, - " super.mergeVarintField($number$, rawValue);\n"); - } - printer->Print(variables_, + "if (value == null) {\n" + // We store the unknown value in unknown fields. + " super.mergeVarintField($number$, rawValue);\n" "} else {\n" - " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" - " }\n" - " $name$_.add(rawValue);\n" + " $name$_.addInt(rawValue);\n" "}\n"); } } 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" @@ -872,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_, @@ -897,12 +889,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnumNoTag($name$_.get(i));\n" + " output.writeEnumNoTag($name$_.getInt(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnum($number$, $name$_.get(i));\n" + " output.writeEnum($number$, $name$_.getInt(i));\n" "}\n"); } } @@ -917,7 +909,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSizeNoTag($name$_.get(i));\n" + " .computeEnumSizeNoTag($name$_.getInt(i));\n" "}\n"); printer->Print( "size += dataSize;\n"); 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 4d7cd3f0..c22da8d7 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -85,34 +85,26 @@ EnumLiteGenerator::~EnumLiteGenerator() {} void EnumLiteGenerator::Generate(io::Printer* printer) { WriteEnumDocComment(printer, descriptor_); - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public enum $classname$\n" - " implements com.google.protobuf.ProtocolMessageEnum {\n", - "classname", descriptor_->name()); - } else { - printer->Print( - "public enum $classname$\n" - " implements com.google.protobuf.Internal.EnumLite {\n", - "classname", descriptor_->name()); - } + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.Internal.EnumLite {\n", + "classname", descriptor_->name()); printer->Indent(); for (int i = 0; i < canonical_values_.size(); i++) { map<string, string> vars; vars["name"] = canonical_values_[i]->name(); - vars["index"] = SimpleItoa(canonical_values_[i]->index()); vars["number"] = SimpleItoa(canonical_values_[i]->number()); WriteEnumValueDocComment(printer, canonical_values_[i]); if (canonical_values_[i]->options().deprecated()) { printer->Print("@java.lang.Deprecated\n"); } printer->Print(vars, - "$name$($index$, $number$),\n"); + "$name$($number$),\n"); } if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print("UNRECOGNIZED(-1, -1),\n"); + printer->Print("UNRECOGNIZED(-1),\n"); } printer->Print( @@ -145,18 +137,14 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { printer->Print( "\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"); - } - printer->Print( + "public final int getNumber() {\n" " 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" @@ -197,7 +185,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { printer->Print( "private final int value;\n\n" - "private $classname$(int index, int value) {\n", + "private $classname$(int value) {\n", "classname", descriptor_->name()); printer->Print( " this.value = value;\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 new file mode 100644 index 00000000..23261bac --- /dev/null +++ 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/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/compiler/java/java_extension_lite.h index e5db844c..4cd49bda 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc +++ b/src/google/protobuf/compiler/java/java_extension_lite.h @@ -28,30 +28,49 @@ // (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/util/internal/snake2camel_objectwriter.h> -#include <google/protobuf/util/internal/expecting_objectwriter.h> -#include <gtest/gtest.h> +#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 util { -namespace converter { +namespace compiler { +namespace java { -class Snake2CamelObjectWriterTest : public ::testing::Test { - protected: - Snake2CamelObjectWriterTest() : mock_(), expects_(&mock_), testing_(&mock_) {} - virtual ~Snake2CamelObjectWriterTest() {} +// 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(); - MockObjectWriter mock_; - ExpectingObjectWriter expects_; - Snake2CamelObjectWriter testing_; -}; + 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); -// All tests are deleted as they are no longer needed. This file will be removed -// after the component dependecies are cleaned up. -// TODO(skarvaje): Remove this file. + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateRegistrationCode(io::Printer* printer); -} // namespace converter -} // namespace util + 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 68b47ee1..c53aae6b 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -42,6 +42,7 @@ #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum.h> +#include <google/protobuf/compiler/java/java_enum_lite.h> #include <google/protobuf/compiler/java/java_extension.h> #include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> @@ -176,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); @@ -192,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_( @@ -203,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) { @@ -261,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(); @@ -281,14 +285,19 @@ void FileGenerator::Generate(io::Printer* printer) { if (!MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) - .Generate(printer); + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) + .Generate(printer); + } else { + EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get()) + .Generate(printer); + } } for (int i = 0; i < file_->message_type_count(); i++) { 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))); @@ -303,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 { @@ -352,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_); @@ -447,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(); @@ -543,13 +558,23 @@ 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++) { - EnumGenerator generator(file_->enum_type(i), immutable_api_, - context_.get()); - GenerateSibling<EnumGenerator>(package_dir, java_package_, - file_->enum_type(i), - context, file_list, "", - &generator, - &EnumGenerator::Generate); + if (HasDescriptorMethods(file_, context_->EnforceLite())) { + EnumGenerator generator(file_->enum_type(i), immutable_api_, + context_.get()); + GenerateSibling<EnumGenerator>(package_dir, java_package_, + file_->enum_type(i), + context, file_list, "", + &generator, + &EnumGenerator::Generate); + } else { + EnumLiteGenerator generator(file_->enum_type(i), immutable_api_, + context_.get()); + GenerateSibling<EnumLiteGenerator>(package_dir, java_package_, + file_->enum_type(i), + context, file_list, "", + &generator, + &EnumLiteGenerator::Generate); + } } for (int i = 0; i < file_->message_type_count(); i++) { if (immutable_api_) { @@ -566,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 a26030dd..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,11 +424,15 @@ 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" @@ -430,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" @@ -463,7 +482,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); } @@ -668,34 +687,40 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " 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 PARSER.parseFrom(input, extensionRegistry);\n" + " 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 PARSER.parseDelimitedFrom(input);\n" + " 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 PARSER.parseDelimitedFrom(input, extensionRegistry);\n" + " 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 PARSER.parseFrom(input);\n" + " 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 PARSER.parseFrom(input, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -1053,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"); @@ -1109,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(); @@ -1169,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"); } @@ -1219,11 +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(\n" - " new com.google.protobuf.InvalidProtocolBufferException(\n" - " e.getMessage()).setUnfinishedMessage(this));\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e).setUnfinishedMessage(this);\n" "} finally {\n"); printer->Indent(); @@ -1265,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 @@ -1333,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" @@ -1349,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" @@ -1360,7 +1430,7 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { " throws com.google.protobuf.InvalidProtocolBufferException {\n" " if (!is(clazz)) {\n" " throw new com.google.protobuf.InvalidProtocolBufferException(\n" - " \"Type of the Any messsage does not match the given class.\");\n" + " \"Type of the Any message does not match the given class.\");\n" " }\n" " if (cachedUnpackValue != null) {\n" " return (T) 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 1b86d2a9..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); } @@ -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" @@ -538,7 +539,7 @@ GenerateBuilderParsingMethods(io::Printer* printer) { " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" - " throw e;\n" + " throw e.unwrapIOException();\n" " } finally {\n" " if (parsedMessage != null) {\n" " mergeFrom(parsedMessage);\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 b6f42d16..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,11 +261,15 @@ 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" @@ -281,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" @@ -317,11 +322,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateMessageSerializationMethods(printer); - if (HasEqualsAndHashCode(descriptor_)) { - GenerateEqualsAndHashCode(printer); - } - - GenerateParseFromMethods(printer); GenerateBuilder(printer); @@ -338,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_)); @@ -378,10 +370,18 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "}\n" - "case MERGE_FROM: {\n"); + "case VISIT: {\n"); + + printer->Indent(); + GenerateDynamicMethodVisit(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case MERGE_FROM_STREAM: {\n"); printer->Indent(); - GenerateDynamicMethodMergeFrom(printer); + GenerateDynamicMethodMergeFromStream(printer); printer->Outdent(); printer->Print( @@ -429,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()); @@ -450,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); } @@ -561,9 +558,6 @@ GenerateMessageSerializationMethods(io::Printer* printer) { " return size;\n" "}\n" "\n"); - - printer->Print( - "private static final long serialVersionUID = 0L;\n"); } void ImmutableMessageLiteGenerator:: @@ -575,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_)); @@ -793,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"); } @@ -812,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); } } @@ -843,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(); @@ -852,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(); @@ -1081,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(), @@ -1134,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"); } @@ -1171,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 392333b8..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,29 +86,30 @@ 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)["empty_list"] = "empty" + capitalized_type + "List()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; - (*variables)["repeated_index_get"] = - (*variables)["name"] + "_.get" + capitalized_type + "(index)"; + (*variables)["repeated_get"] = + (*variables)["name"] + "_.get" + capitalized_type; (*variables)["repeated_add"] = (*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)["empty_list"] = "emptyProtobufList()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; - (*variables)["repeated_index_get"] = - (*variables)["name"] + "_.get(index)"; + (*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))) { @@ -127,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. @@ -297,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"); } } @@ -539,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:: @@ -629,11 +628,11 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $repeated_index_get$;\n" + " return $repeated_get$(index);\n" "}\n"); if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); } @@ -641,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"); @@ -742,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:: @@ -773,9 +760,13 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { void RepeatedImmutablePrimitiveFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { + // TODO(dweis): Scan the input buffer to count, then initialize + // appropriately. + // 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"); } @@ -785,8 +776,24 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" - "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = $new_list$();\n" + "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"); + + int fixed_size = FixedSize(GetType(descriptor_)); + if (fixed_size == -1) { + // TODO(dweis): Scan the input buffer to count, then initialize + // appropriately. + printer->Print(variables_, + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"); + } else { + printer->Print(variables_, + " 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. + printer->Print(variables_, "}\n" "while (input.getBytesUntilLimit() > 0) {\n" " $repeated_add$(input.read$capitalized_type$());\n" @@ -814,12 +821,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " output.write$capitalized_type$NoTag($repeated_get$(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$($number$, $name$_.get(i));\n" + " output.write$capitalized_type$($number$, $repeated_get$(i));\n" "}\n"); } } @@ -835,7 +842,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n" + " .compute$capitalized_type$SizeNoTag($repeated_get$(i));\n" "}\n"); } else { printer->Print(variables_, 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 72ebaeca..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. @@ -405,16 +404,7 @@ void ImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "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_, - "String s = input.readString();\n" + "java.lang.String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); } else { @@ -665,16 +655,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "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_, - "String s = input.readString();\n" + "java.lang.String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); } else { @@ -773,12 +754,6 @@ GenerateMembers(io::Printer* printer) const { " get$capitalized_name$Bytes(int index) {\n" " return $name$_.getByteString(index);\n" "}\n"); - - if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { - printer->Print(variables_, - "private int $name$MemoizedSerializedSize = -1;\n"); - } } void RepeatedImmutableStringFieldGenerator:: @@ -939,14 +914,7 @@ void RepeatedImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "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_, - "String s = input.readString();\n"); + "java.lang.String s = input.readStringRequireUtf8();\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n"); @@ -956,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 { @@ -966,30 +934,6 @@ GenerateParsingCode(io::Printer* printer) const { } void RepeatedImmutableStringFieldGenerator:: -GenerateParsingCodeFromPacked(io::Printer* printer) const { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" - " $set_mutable_bit_parser$;\n" - "}\n" - "while (input.getBytesUntilLimit() > 0) {\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " String s = input.readStringRequireUtf8();\n"); - } else { - printer->Print(variables_, - " String s = input.readString();\n"); - } - printer->Print(variables_, - " $name$.add(s);\n"); - printer->Print(variables_, - "}\n" - "input.popLimit(limit);\n"); -} - -void RepeatedImmutableStringFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_mutable_bit_parser$) {\n" @@ -999,21 +943,10 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() > 0) {\n" - " output.writeRawVarint32($tag$);\n" - " output.writeRawVarint32($name$MemoizedSerializedSize);\n" - "}\n" - "for (int i = 0; i < $name$_.size(); i++) {\n" - " writeStringNoTag(output, $name$_.getRaw(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for (int i = 0; i < $name$_.size(); i++) {\n" - " $writeString$(output, $number$, $name$_.getRaw(i));\n" - "}\n"); - } + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " $writeString$(output, $number$, $name$_.getRaw(i));\n" + "}\n"); } void RepeatedImmutableStringFieldGenerator:: @@ -1031,23 +964,8 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print( "size += dataSize;\n"); - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (!get$capitalized_name$List().isEmpty()) {\n" - " size += $tag_size$;\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeInt32SizeNoTag(dataSize);\n" - "}\n"); - } else { - printer->Print(variables_, - "size += $tag_size$ * get$capitalized_name$List().size();\n"); - } - - // cache the data size for packed fields. - if (descriptor_->options().packed()) { - printer->Print(variables_, - "$name$MemoizedSerializedSize = dataSize;\n"); - } + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h index 1ea44dec..a3b57351 100644 --- a/src/google/protobuf/compiler/java/java_string_field.h +++ b/src/google/protobuf/compiler/java/java_string_field.h @@ -131,7 +131,6 @@ class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator { void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; - void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateParsingDoneCode(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_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index 092e3c29..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:: @@ -647,17 +636,11 @@ GenerateMembers(io::Printer* printer) const { " $name$_.get(index));\n" "}\n"); - if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { - printer->Print(variables_, - "private int $name$MemoizedSerializedSize = -1;\n"); - } - 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"); @@ -784,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:: @@ -823,38 +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"); - } -} - -void RepeatedImmutableStringFieldLiteGenerator:: -GenerateParsingCodeFromPacked(io::Printer* printer) const { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" - "}\n" - "while (input.getBytesUntilLimit() > 0) {\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " String s = input.readStringRequireUtf8();\n"); - } else { - printer->Print(variables_, - " String s = input.readString();\n"); - } - printer->Print(variables_, - " $name$.add(s);\n"); printer->Print(variables_, - "}\n" - "input.popLimit(limit);\n"); + "$name$_.add(s);\n"); } void RepeatedImmutableStringFieldLiteGenerator:: @@ -870,21 +813,10 @@ GenerateSerializationCode(io::Printer* printer) const { // Lite runtime should reduce allocations by serializing the string directly. // This avoids spurious intermediary ByteString allocations, cutting overall // allocations in half. - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() > 0) {\n" - " output.writeRawVarint32($tag$);\n" - " output.writeRawVarint32($name$MemoizedSerializedSize);\n" - "}\n" - "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeStringNoTag($name$_.get(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeString($number$, $name$_.get(i));\n" - "}\n"); - } + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeString($number$, $name$_.get(i));\n" + "}\n"); } void RepeatedImmutableStringFieldLiteGenerator:: @@ -906,23 +838,9 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print( "size += dataSize;\n"); - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (!get$capitalized_name$List().isEmpty()) {\n" - " size += $tag_size$;\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeInt32SizeNoTag(dataSize);\n" - "}\n"); - } else { - printer->Print(variables_, - "size += $tag_size$ * get$capitalized_name$List().size();\n"); - } - // cache the data size for packed fields. - if (descriptor_->options().packed()) { - printer->Print(variables_, - "$name$MemoizedSerializedSize = dataSize;\n"); - } + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); printer->Outdent(); printer->Print("}\n"); 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 9d93b307..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,10 +126,9 @@ 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 GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(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 new file mode 100755 index 00000000..3de61e80 --- /dev/null +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -0,0 +1,3053 @@ +// 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/js/js_generator.h" + +#include <assert.h> +#include <algorithm> +#include <limits> +#include <map> +#include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif +#include <string> +#include <utility> +#include <vector> + +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/stringprintf.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/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace js { + +// Sorted list of JavaScript keywords. These cannot be used as names. If they +// appear, we prefix them with "pb_". +const char* kKeyword[] = { + "abstract", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "double", + "else", + "enum", + "export", + "extends", + "false", + "final", + "finally", + "float", + "for", + "function", + "goto", + "if", + "implements", + "import", + "in", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "try", + "typeof", + "var", + "void", + "volatile", + "while", + "with", +}; + +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]) { + return true; + } + } + return false; +} + +// Returns a copy of |filename| with any trailing ".protodevel" or ".proto +// suffix stripped. +// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. +string StripProto(const string& filename) { + const char* suffix = HasSuffixString(filename, ".protodevel") + ? ".protodevel" : ".proto"; + return StripSuffixString(filename, suffix); +} + +// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript +// file foo/bar/baz.js. +string GetJSFilename(const string& filename) { + return StripProto(filename) + "_pb.js"; +} + +// Given a filename like foo/bar/baz.proto, returns the root directory +// path ../../ +string GetRootPath(const string& filename) { + size_t slashes = std::count(filename.begin(), filename.end(), '/'); + if (slashes == 0) { + return "./"; + } + string result = ""; + for (size_t i = 0; i < slashes; i++) { + result += "../"; + } + return result; +} + +// Returns the alias we assign to the module of the given .proto filename +// when importing. +string ModuleAlias(const string& filename) { + // This scheme could technically cause problems if a file includes any 2 of: + // foo/bar_baz.proto + // foo_bar_baz.proto + // foo_bar/baz.proto + // + // We'll worry about this problem if/when we actually see it. This name isn't + // exposed to users so we can change it later if we need to. + string basename = StripProto(filename); + StripString(&basename, "-", '$'); + StripString(&basename, "/", '_'); + return basename + "_pb"; +} + +// Returns the fully normalized JavaScript path for the given +// file descriptor's package. +string GetPath(const GeneratorOptions& options, + const FileDescriptor* file) { + if (!options.namespace_prefix.empty()) { + return options.namespace_prefix; + } else if (!file->package().empty()) { + return "proto." + file->package(); + } else { + return "proto"; + } +} + +// Forward declare, so that GetPrefix can call this method, +// which in turn, calls GetPrefix. +string GetPath(const GeneratorOptions& options, + const Descriptor* descriptor); + +// Returns the path prefix for a message or enumeration that +// lives under the given file and containing type. +string GetPrefix(const GeneratorOptions& options, + const FileDescriptor* file_descriptor, + const Descriptor* containing_type) { + string prefix = ""; + + if (containing_type == NULL) { + prefix = GetPath(options, file_descriptor); + } else { + prefix = GetPath(options, containing_type); + } + + if (!prefix.empty()) { + prefix += "."; + } + + return prefix; +} + + +// Returns the fully normalized JavaScript path for the given +// message descriptor. +string GetPath(const GeneratorOptions& options, + const Descriptor* descriptor) { + return GetPrefix( + options, descriptor->file(), + descriptor->containing_type()) + descriptor->name(); +} + + +// Returns the fully normalized JavaScript path for the given +// field's containing message descriptor. +string GetPath(const GeneratorOptions& options, + const FieldDescriptor* descriptor) { + return GetPath(options, descriptor->containing_type()); +} + +// Returns the fully normalized JavaScript path for the given +// enumeration descriptor. +string GetPath(const GeneratorOptions& options, + const EnumDescriptor* enum_descriptor) { + return GetPrefix( + options, enum_descriptor->file(), + enum_descriptor->containing_type()) + enum_descriptor->name(); +} + + +// Returns the fully normalized JavaScript path for the given +// enumeration value descriptor. +string GetPath(const GeneratorOptions& options, + const EnumValueDescriptor* value_descriptor) { + return GetPath( + options, + value_descriptor->type()) + "." + value_descriptor->name(); +} + +string MaybeCrossFileRef(const GeneratorOptions& options, + const FileDescriptor* from_file, + const Descriptor* to_message) { + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS && + from_file != to_message->file()) { + // Cross-file ref in CommonJS needs to use the module alias instead of + // the global name. + return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); + } else { + // Within a single file we use a full name. + return GetPath(options, to_message); + } +} + +string SubmessageTypeRef(const GeneratorOptions& options, + const FieldDescriptor* field) { + GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + return MaybeCrossFileRef(options, field->file(), field->message_type()); +} + +// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields +// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, +// and with reserved words triggering a "pb_" prefix. +// - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields +// (use the name directly), then append "List" if appropriate, then append "$" +// if resulting name is equal to a reserved word. +// - Enums: just uppercase. + +// Locale-independent version of ToLower that deals only with ASCII A-Z. +char ToLowerASCII(char c) { + if (c >= 'A' && c <= 'Z') { + return (c - 'A') + 'a'; + } else { + return c; + } +} + +vector<string> ParseLowerUnderscore(const string& input) { + vector<string> words; + string running = ""; + for (int i = 0; i < input.size(); i++) { + if (input[i] == '_') { + if (!running.empty()) { + words.push_back(running); + running.clear(); + } + } else { + running += ToLowerASCII(input[i]); + } + } + if (!running.empty()) { + words.push_back(running); + } + return words; +} + +vector<string> ParseUpperCamel(const string& input) { + vector<string> words; + string running = ""; + for (int i = 0; i < input.size(); i++) { + if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) { + words.push_back(running); + running.clear(); + } + running += ToLowerASCII(input[i]); + } + if (!running.empty()) { + words.push_back(running); + } + return words; +} + +string ToLowerCamel(const vector<string>& words) { + string result; + for (int i = 0; i < words.size(); i++) { + string word = words[i]; + if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) { + word[0] = (word[0] - 'A') + 'a'; + } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) { + word[0] = (word[0] - 'a') + 'A'; + } + result += word; + } + return result; +} + +string ToUpperCamel(const vector<string>& words) { + string result; + for (int i = 0; i < words.size(); i++) { + string word = words[i]; + if (word[0] >= 'a' && word[0] <= 'z') { + word[0] = (word[0] - 'a') + 'A'; + } + result += word; + } + return result; +} + +// Based on code from descriptor.cc (Thanks Kenton!) +// Uppercases the entire string, turning ValueName into +// VALUENAME. +string ToEnumCase(const string& input) { + string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + result.push_back(input[i] - 'a' + 'A'); + } else { + result.push_back(input[i]); + } + } + + return result; +} + +string ToFileName(const string& input) { + string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if ('A' <= input[i] && input[i] <= 'Z') { + result.push_back(input[i] - 'A' + 'a'); + } else { + result.push_back(input[i]); + } + } + + 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 IgnoreExtensionField(field); +} + + +// Does JSPB ignore this entire oneof? True only if all fields are ignored. +bool IgnoreOneof(const OneofDescriptor* oneof) { + for (int i = 0; i < oneof->field_count(); i++) { + if (!IgnoreField(oneof->field(i))) { + return false; + } + } + return true; +} + +string JSIdent(const FieldDescriptor* field, + bool is_upper_camel, + bool is_map) { + string result; + if (field->type() == FieldDescriptor::TYPE_GROUP) { + result = is_upper_camel ? + ToUpperCamel(ParseUpperCamel(field->message_type()->name())) : + ToLowerCamel(ParseUpperCamel(field->message_type()->name())); + } else { + result = is_upper_camel ? + ToUpperCamel(ParseLowerUnderscore(field->name())) : + ToLowerCamel(ParseLowerUnderscore(field->name())); + } + if (is_map) { + result += "Map"; + } else if (field->is_repeated()) { + result += "List"; + } + return result; +} + +string JSObjectFieldName(const FieldDescriptor* field) { + string name = JSIdent( + field, + /* is_upper_camel = */ false, + /* is_map = */ false); + if (IsReserved(name)) { + name = "pb_" + name; + } + 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, + 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 += "$"; + } + return name; +} + +string JSMapGetterName(const FieldDescriptor* field) { + return JSIdent(field, + /* is_upper_camel = */ true, + /* is_map = */ true); +} + + + +string JSOneofName(const OneofDescriptor* oneof) { + return ToUpperCamel(ParseLowerUnderscore(oneof->name())); +} + +// Returns the index corresponding to this field in the JSPB array (underlying +// data storage array). +string JSFieldIndex(const FieldDescriptor* field) { + // Determine whether this field is a member of a group. Group fields are a bit + // wonky: their "containing type" is a message type created just for the + // group, and that type's parent type has a field with the group-message type + // as its message type and TYPE_GROUP as its field type. For such fields, the + // index we use is relative to the field number of the group submessage field. + // For all other fields, we just use the field number. + const Descriptor* containing_type = field->containing_type(); + const Descriptor* parent_type = containing_type->containing_type(); + if (parent_type != NULL) { + for (int i = 0; i < parent_type->field_count(); i++) { + if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP && + parent_type->field(i)->message_type() == containing_type) { + return SimpleItoa(field->number() - parent_type->field(i)->number()); + } + } + } + return SimpleItoa(field->number()); +} + +string JSOneofIndex(const OneofDescriptor* oneof) { + int index = -1; + for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) { + const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i); + // If at least one field in this oneof is not JSPB-ignored, count the oneof. + for (int j = 0; j < o->field_count(); j++) { + const FieldDescriptor* f = o->field(j); + if (!IgnoreField(f)) { + index++; + break; // inner loop + } + } + if (o == oneof) { + break; + } + } + return SimpleItoa(index); +} + +// Decodes a codepoint in \x0000 -- \xFFFF. +uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { + if (*length == 0) { + return 0; + } + size_t expected = 0; + if ((*bytes & 0x80) == 0) { + expected = 1; + } else if ((*bytes & 0xe0) == 0xc0) { + expected = 2; + } else if ((*bytes & 0xf0) == 0xe0) { + expected = 3; + } else { + // Too long -- don't accept. + *length = 0; + return 0; + } + + if (*length < expected) { + // Not enough bytes -- don't accept. + *length = 0; + return 0; + } + + *length = expected; + switch (expected) { + case 1: return bytes[0]; + case 2: return ((bytes[0] & 0x1F) << 6) | + ((bytes[1] & 0x3F) << 0); + case 3: return ((bytes[0] & 0x0F) << 12) | + ((bytes[1] & 0x3F) << 6) | + ((bytes[2] & 0x3F) << 0); + default: return 0; + } +} + +// Escapes the contents of a string to be included within double-quotes ("") in +// 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; + // 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) { + return false; + } + decoded = have_bytes; + + switch (codepoint) { + 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: + // 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) { + *out += static_cast<char>(codepoint); + } else if (codepoint >= 0x100) { + *out += StringPrintf("\\u%04x", codepoint); + } else { + *out += StringPrintf("\\x%02x", codepoint); + } + break; + } + } + return true; +} + +string EscapeBase64(const string& in) { + static const char* kAlphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + string result; + + for (size_t i = 0; i < in.size(); i += 3) { + int value = (in[i] << 16) | + (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) | + (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0); + result += kAlphabet[(value >> 18) & 0x3f]; + result += kAlphabet[(value >> 12) & 0x3f]; + if ((i + 1) < in.size()) { + result += kAlphabet[(value >> 6) & 0x3f]; + } else { + result += '='; + } + if ((i + 2) < in.size()) { + result += kAlphabet[(value >> 0) & 0x3f]; + } else { + result += '='; + } + } + + return result; +} + +// Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the +// original codegen's formatting (which is just .toString() on java.lang.Double +// or java.lang.Float). +string PostProcessFloat(string result) { + // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN. + if (result == "inf") { + return "Infinity"; + } else if (result == "-inf") { + return "-Infinity"; + } else if (result == "nan") { + return "NaN"; + } + + // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii) + // ensure that the mantissa (portion prior to the "e") has at least one + // fractional digit (after the decimal point), and (iii) strip any unnecessary + // leading zeroes and/or '+' signs from the exponent. + string::size_type exp_pos = result.find('e'); + if (exp_pos != string::npos) { + string mantissa = result.substr(0, exp_pos); + string exponent = result.substr(exp_pos + 1); + + // Add ".0" to mantissa if no fractional part exists. + if (mantissa.find('.') == string::npos) { + mantissa += ".0"; + } + + // Strip the sign off the exponent and store as |exp_neg|. + bool exp_neg = false; + if (!exponent.empty() && exponent[0] == '+') { + exponent = exponent.substr(1); + } else if (!exponent.empty() && exponent[0] == '-') { + exp_neg = true; + exponent = exponent.substr(1); + } + + // Strip any leading zeroes off the exponent. + while (exponent.size() > 1 && exponent[0] == '0') { + exponent = exponent.substr(1); + } + + return mantissa + "E" + string(exp_neg ? "-" : "") + exponent; + } + + // Otherwise, this is an ordinary decimal number. Append ".0" if result has no + // decimal/fractional part in order to match output of original codegen. + if (result.find('.') == string::npos) { + result += ".0"; + } + + return result; +} + +string FloatToString(float value) { + string result = SimpleFtoa(value); + return PostProcessFloat(result); +} + +string DoubleToString(double value) { + string result = SimpleDtoa(value); + return PostProcessFloat(result); +} + +string MaybeNumberString(const FieldDescriptor* field, const string& orig) { + return orig; +} + +string JSFieldDefault(const FieldDescriptor* field) { + assert(field->has_default_value()); + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return MaybeNumberString( + field, SimpleItoa(field->default_value_int32())); + case FieldDescriptor::CPPTYPE_UINT32: + // The original codegen is in Java, and Java protobufs store unsigned + // integer values as signed integer values. In order to exactly match the + // output, we need to reinterpret as base-2 signed. Ugh. + return MaybeNumberString( + field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); + case FieldDescriptor::CPPTYPE_INT64: + return MaybeNumberString( + field, SimpleItoa(field->default_value_int64())); + case FieldDescriptor::CPPTYPE_UINT64: + // See above note for uint32 -- reinterpreting as signed. + return MaybeNumberString( + field, SimpleItoa(static_cast<int64>(field->default_value_uint64()))); + case FieldDescriptor::CPPTYPE_ENUM: + return SimpleItoa(field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_FLOAT: + return FloatToString(field->default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: + return DoubleToString(field->default_value_double()); + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_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"; + } + GOOGLE_LOG(FATAL) << "Shouldn't reach here."; + return ""; +} + +string ProtoTypeName(const GeneratorOptions& options, + const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_BOOL: + return "bool"; + case FieldDescriptor::TYPE_INT32: + return "int32"; + case FieldDescriptor::TYPE_UINT32: + return "uint32"; + case FieldDescriptor::TYPE_SINT32: + return "sint32"; + case FieldDescriptor::TYPE_FIXED32: + return "fixed32"; + case FieldDescriptor::TYPE_SFIXED32: + return "sfixed32"; + case FieldDescriptor::TYPE_INT64: + return "int64"; + case FieldDescriptor::TYPE_UINT64: + return "uint64"; + case FieldDescriptor::TYPE_SINT64: + return "sint64"; + case FieldDescriptor::TYPE_FIXED64: + return "fixed64"; + case FieldDescriptor::TYPE_SFIXED64: + return "sfixed64"; + case FieldDescriptor::TYPE_FLOAT: + return "float"; + case FieldDescriptor::TYPE_DOUBLE: + return "double"; + case FieldDescriptor::TYPE_STRING: + return "string"; + case FieldDescriptor::TYPE_BYTES: + return "bytes"; + case FieldDescriptor::TYPE_GROUP: + return GetPath(options, field->message_type()); + case FieldDescriptor::TYPE_ENUM: + return GetPath(options, field->enum_type()); + case FieldDescriptor::TYPE_MESSAGE: + return GetPath(options, field->message_type()); + default: + return ""; + } +} + +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, + BytesMode bytes_mode) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: + return "boolean"; + case FieldDescriptor::CPPTYPE_INT32: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_INT64: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_UINT32: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_UINT64: + return JSIntegerTypeName(field); + case FieldDescriptor::CPPTYPE_FLOAT: + return "number"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "number"; + case FieldDescriptor::CPPTYPE_STRING: + return JSStringTypeName(options, field, bytes_mode); + case FieldDescriptor::CPPTYPE_ENUM: + return GetPath(options, field->enum_type()); + case FieldDescriptor::CPPTYPE_MESSAGE: + return GetPath(options, field->message_type()); + default: + return ""; + } +} + +bool HasFieldPresence(const FieldDescriptor* field); + +string JSFieldTypeAnnotation(const GeneratorOptions& options, + const FieldDescriptor* field, + bool force_optional, + bool force_present, + bool singular_if_not_packed, + BytesMode bytes_mode = BYTES_DEFAULT) { + bool is_primitive = + (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && + (field->type() != FieldDescriptor::TYPE_BYTES || + bytes_mode == BYTES_B64)); + + string jstype = JSTypeName(options, field, bytes_mode); + + if (field->is_repeated() && + (field->is_packed() || !singular_if_not_packed)) { + if (field->type() == FieldDescriptor::TYPE_BYTES && + bytes_mode == BYTES_DEFAULT) { + jstype = "(Array<!Uint8Array>|Array<string>)"; + } else { + if (!is_primitive) { + jstype = "!" + jstype; + } + jstype = "Array.<" + jstype + ">"; + } + if (!force_optional) { + jstype = "!" + jstype; + } + } + + if (field->is_optional() && is_primitive && + (!field->has_default_value() || force_optional) && !force_present) { + jstype += "?"; + } else if (field->is_required() && !is_primitive && !force_optional) { + jstype = "!" + jstype; + } + + if (force_optional && HasFieldPresence(field)) { + jstype += "|undefined"; + } + if (force_present && jstype[0] != '!' && !is_primitive) { + jstype = "!" + jstype; + } + + return jstype; +} + +string JSBinaryReaderMethodType(const FieldDescriptor* field) { + string name = field->type_name(); + if (name[0] >= 'a' && name[0] <= 'z') { + name[0] = (name[0] - 'a') + 'A'; + } + + return name; +} + +string JSBinaryReadWriteMethodName(const FieldDescriptor* field, + bool is_writer) { + string name = JSBinaryReaderMethodType(field); + if (field->is_packed()) { + name = "Packed" + name; + } else if (is_writer && field->is_repeated()) { + name = "Repeated" + name; + } + return name; +} + +string JSBinaryReaderMethodName(const FieldDescriptor* field) { + return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false); +} + +string JSBinaryWriterMethodName(const FieldDescriptor* field) { + return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true); +} + +string JSReturnClause(const FieldDescriptor* desc) { + return ""; +} + +string JSReturnDoc(const GeneratorOptions& options, + const FieldDescriptor* desc) { + return ""; +} + +bool HasRepeatedFields(const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->is_repeated()) { + return true; + } + } + return false; +} + +static const char* kRepeatedFieldArrayName = ".repeatedFields_"; + +string RepeatedFieldsArrayName(const GeneratorOptions& options, + const Descriptor* desc) { + return HasRepeatedFields(desc) ? + (GetPath(options, desc) + kRepeatedFieldArrayName) : "null"; +} + +bool HasOneofFields(const Descriptor* desc) { + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->containing_oneof()) { + return true; + } + } + return false; +} + +static const char* kOneofGroupArrayName = ".oneofGroups_"; + +string OneofFieldsArrayName(const GeneratorOptions& options, + const Descriptor* desc) { + return HasOneofFields(desc) ? + (GetPath(options, desc) + kOneofGroupArrayName) : "null"; +} + +string RepeatedFieldNumberList(const Descriptor* desc) { + std::vector<string> numbers; + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->is_repeated()) { + numbers.push_back(JSFieldIndex(desc->field(i))); + } + } + return "[" + Join(numbers, ",") + "]"; +} + +string OneofGroupList(const Descriptor* desc) { + // List of arrays (one per oneof), each of which is a list of field indices + std::vector<string> oneof_entries; + for (int i = 0; i < desc->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = desc->oneof_decl(i); + if (IgnoreOneof(oneof)) { + continue; + } + + std::vector<string> oneof_fields; + for (int j = 0; j < oneof->field_count(); j++) { + if (IgnoreField(oneof->field(j))) { + continue; + } + oneof_fields.push_back(JSFieldIndex(oneof->field(j))); + } + oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]"); + } + return "[" + Join(oneof_entries, ",") + "]"; +} + +string JSOneofArray(const GeneratorOptions& options, + const FieldDescriptor* field) { + return OneofFieldsArrayName(options, field->containing_type()) + "[" + + JSOneofIndex(field->containing_oneof()) + "]"; +} + +string RelativeTypeName(const FieldDescriptor* field) { + assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM || + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + // For a field with an enum or message type, compute a name relative to the + // path name of the message type containing this field. + string package = field->file()->package(); + string containing_type = field->containing_type()->full_name() + "."; + string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) ? + field->enum_type()->full_name() : field->message_type()->full_name(); + + // |prefix| is advanced as we find separators '.' past the common package + // prefix that yield common prefixes in the containing type's name and this + // type's name. + int prefix = 0; + for (int i = 0; i < type.size() && i < containing_type.size(); i++) { + if (type[i] != containing_type[i]) { + break; + } + if (type[i] == '.' && i >= package.size()) { + prefix = i + 1; + } + } + + return type.substr(prefix); +} + +string JSExtensionsObjectName(const GeneratorOptions& options, + const FileDescriptor* from_file, + const Descriptor* desc) { + if (desc->full_name() == "google.protobuf.bridge.MessageSet") { + // TODO(haberman): fix this for the IMPORT_COMMONJS case. + return "jspb.Message.messageSetExtensions"; + } else { + return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; + } +} + +string FieldDefinition(const GeneratorOptions& options, + const FieldDescriptor* field) { + string qualifier = field->is_repeated() ? "repeated" : + (field->is_optional() ? "optional" : "required"); + string type, name; + if (field->type() == FieldDescriptor::TYPE_ENUM || + field->type() == FieldDescriptor::TYPE_MESSAGE) { + type = RelativeTypeName(field); + name = field->name(); + } else if (field->type() == FieldDescriptor::TYPE_GROUP) { + type = "group"; + name = field->message_type()->name(); + } else { + type = ProtoTypeName(options, field); + name = field->name(); + } + return StringPrintf("%s %s %s = %d;", + qualifier.c_str(), + type.c_str(), + name.c_str(), + field->number()); +} + +string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { + string comments; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { + comments += + " * Note that Boolean fields may be set to 0/1 when serialized from " + "a Java server.\n" + " * You should avoid comparisons like {@code val === true/false} in " + "those cases.\n"; + } + if (field->is_repeated()) { + comments += + " * If you change this array by adding, removing or replacing " + "elements, or if you\n" + " * 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; +} + +bool ShouldGenerateExtension(const FieldDescriptor* field) { + return + field->is_extension() && + !IgnoreField(field); +} + +bool HasExtensions(const Descriptor* desc) { + 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))) { + return true; + } + } + return false; +} + +bool HasExtensions(const FileDescriptor* file) { + for (int i = 0; i < file->extension_count(); i++) { + if (ShouldGenerateExtension(file->extension(i))) { + return true; + } + } + for (int i = 0; i < file->message_type_count(); i++) { + if (HasExtensions(file->message_type(i))) { + return true; + } + } + return false; +} + +bool IsExtendable(const Descriptor* desc) { + return desc->extension_range_count() > 0; +} + +// Returns the max index in the underlying data storage array beyond which the +// extension object is used. +string GetPivot(const Descriptor* desc) { + static const int kDefaultPivot = (1 << 29); // max field number (29 bits) + + // Find the max field number + int max_field_number = 0; + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i)) && + desc->field(i)->number() > max_field_number) { + max_field_number = desc->field(i)->number(); + } + } + + int pivot = -1; + if (IsExtendable(desc)) { + pivot = ((max_field_number + 1) < kDefaultPivot) ? + (max_field_number + 1) : kDefaultPivot; + } + + return SimpleItoa(pivot); +} + +// Returns true for fields that represent "null" as distinct from the default +// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. +bool HasFieldPresence(const FieldDescriptor* field) { + return + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || + (field->containing_oneof() != NULL) || + (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3); +} + +// For proto3 fields without presence, returns a string representing the default +// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more +// information. +string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: { + return "0"; + } + + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + return "0"; + + case FieldDescriptor::CPPTYPE_BOOL: + return "false"; + + case FieldDescriptor::CPPTYPE_STRING: // includes BYTES + return "\"\""; + + default: + // MESSAGE is handled separately. + assert(false); + return ""; + } +} + +// 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, + io::Printer* printer) const { + printer->Print("/**\n" + " * @fileoverview\n" + " * @enhanceable\n" + " * @public\n" + " */\n" + "// GENERATED CODE -- DO NOT EDIT!\n" + "\n"); +} + +void Generator::FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file, + std::set<string>* provided) const { + for (int i = 0; i < file->message_type_count(); i++) { + FindProvidesForMessage(options, printer, file->message_type(i), provided); + } + for (int i = 0; i < file->enum_type_count(); i++) { + FindProvidesForEnum(options, printer, file->enum_type(i), provided); + } +} + +void Generator::FindProvides(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& files, + std::set<string>* provided) const { + for (int i = 0; i < files.size(); i++) { + FindProvidesForFile(options, printer, files[i], provided); + } + + printer->Print("\n"); +} + +void Generator::FindProvidesForMessage( + const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set<string>* provided) const { + string name = GetPath(options, desc); + provided->insert(name); + + for (int i = 0; i < desc->enum_type_count(); i++) { + FindProvidesForEnum(options, printer, desc->enum_type(i), + provided); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + FindProvidesForMessage(options, printer, desc->nested_type(i), + provided); + } +} + +void Generator::FindProvidesForEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc, + std::set<string>* provided) const { + string name = GetPath(options, enumdesc); + provided->insert(name); +} + +void Generator::FindProvidesForFields( + const GeneratorOptions& options, + io::Printer* printer, + const vector<const FieldDescriptor*>& fields, + std::set<string>* provided) const { + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + + if (IgnoreField(field)) { + continue; + } + + string name = + GetPath(options, field->file()) + "." + JSObjectFieldName(field); + provided->insert(name); + } +} + +void Generator::GenerateProvides(const GeneratorOptions& options, + io::Printer* printer, + std::set<string>* provided) const { + for (std::set<string>::iterator it = provided->begin(); + it != provided->end(); ++it) { + printer->Print("goog.provide('$name$');\n", + "name", *it); + } +} + +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; + FindRequiresForMessage(options, desc, + &required, &forwards, &have_message); + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ HasExtensions(desc)); +} + +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 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); +} + +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++) { + const FieldDescriptor* field = fields[i]; + if (IgnoreField(field)) { + continue; + } + FindRequiresForExtension(options, field, &required, &forwards); + } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ false, + /* require_extension = */ fields.size() > 0); +} + +void Generator::GenerateRequiresImpl(const GeneratorOptions& options, + io::Printer* printer, + std::set<string>* required, + std::set<string>* forwards, + std::set<string>* provided, + bool require_jspb, + bool require_extension) const { + if (require_jspb) { + printer->Print( + "goog.require('jspb.Message');\n"); + if (options.binary) { + printer->Print( + "goog.require('jspb.BinaryReader');\n" + "goog.require('jspb.BinaryWriter');\n"); + } + } + if (require_extension) { + printer->Print( + "goog.require('jspb.ExtensionFieldInfo');\n"); + } + + std::set<string>::iterator it; + for (it = required->begin(); it != required->end(); ++it) { + if (provided->find(*it) != provided->end()) { + continue; + } + printer->Print("goog.require('$name$');\n", + "name", *it); + } + + printer->Print("\n"); + + for (it = forwards->begin(); it != forwards->end(); ++it) { + if (provided->find(*it) != provided->end()) { + continue; + } + printer->Print("goog.forwardDeclare('$name$');\n", + "name", *it); + } +} + +bool NamespaceOnly(const Descriptor* desc) { + return false; +} + +void Generator::FindRequiresForMessage( + const GeneratorOptions& options, + const Descriptor* desc, + std::set<string>* required, + std::set<string>* forwards, + bool* have_message) const { + + + if (!NamespaceOnly(desc)) { + *have_message = true; + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + if (IgnoreField(field)) { + continue; + } + FindRequiresForField(options, field, required, forwards); + } + } + + for (int i = 0; i < desc->extension_count(); i++) { + const FieldDescriptor* field = desc->extension(i); + if (IgnoreField(field)) { + continue; + } + FindRequiresForExtension(options, field, required, forwards); + } + + for (int i = 0; i < desc->nested_type_count(); i++) { + FindRequiresForMessage(options, desc->nested_type(i), required, forwards, + have_message); + } +} + +void Generator::FindRequiresForField(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<string>* required, + std::set<string>* forwards) const { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && + // N.B.: file-level extensions with enum type do *not* create + // dependencies, as per original codegen. + !(field->is_extension() && field->extension_scope() == NULL)) { + if (options.add_require_for_enums) { + required->insert(GetPath(options, field->enum_type())); + } else { + forwards->insert(GetPath(options, field->enum_type())); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + required->insert(GetPath(options, field->message_type())); + } +} + +void Generator::FindRequiresForExtension(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<string>* required, + std::set<string>* forwards) const { + if (field->containing_type()->full_name() != "google.protobuf.bridge.MessageSet") { + required->insert(GetPath(options, field->containing_type())); + } + FindRequiresForField(options, field, required, forwards); +} + +void Generator::GenerateTestOnly(const GeneratorOptions& options, + io::Printer* printer) const { + if (options.testonly) { + printer->Print("goog.setTestOnly();\n\n"); + } + printer->Print("\n"); +} + +void Generator::GenerateClassesAndEnums(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const { + for (int i = 0; i < file->message_type_count(); i++) { + GenerateClass(options, printer, file->message_type(i)); + } + for (int i = 0; i < file->enum_type_count(); i++) { + GenerateEnum(options, printer, file->enum_type(i)); + } +} + +void Generator::GenerateClass(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (!NamespaceOnly(desc)) { + printer->Print("\n"); + GenerateClassConstructor(options, printer, desc); + GenerateClassFieldInfo(options, printer, desc); + + + GenerateClassToObject(options, printer, desc); + if (options.binary) { + // These must come *before* the extension-field info generation in + // GenerateClassRegistration so that references to the binary + // serialization/deserialization functions may be placed in the extension + // objects. + GenerateClassDeserializeBinary(options, printer, desc); + GenerateClassSerializeBinary(options, printer, desc); + } + GenerateClassClone(options, printer, desc); + GenerateClassRegistration(options, printer, desc); + GenerateClassFields(options, printer, desc); + if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") { + GenerateClassExtensionFieldInfo(options, printer, desc); + } + + if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) { + for (int i = 0; i < desc->extension_count(); i++) { + GenerateExtension(options, printer, desc->extension(i)); + } + } + } + + // Recurse on nested types. + for (int i = 0; i < desc->enum_type_count(); i++) { + GenerateEnum(options, printer, desc->enum_type(i)); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + GenerateClass(options, printer, desc->nested_type(i)); + } +} + +void Generator::GenerateClassConstructor(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "/**\n" + " * Generated by JsPbCodeGenerator.\n" + " * @param {Array=} opt_data Optional initial data array, typically " + "from a\n" + " * server response, or constructed directly in Javascript. The array " + "is used\n" + " * in place and becomes part of the constructed object. It is not " + "cloned.\n" + " * If no data is provided, the constructed object will be empty, but " + "still\n" + " * valid.\n" + " * @extends {jspb.Message}\n" + " * @constructor\n" + " */\n" + "$classname$ = function(opt_data) {\n", + "classname", GetPath(options, desc)); + string message_id = GetMessageId(desc); + printer->Print( + " jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, " + "$rptfields$, $oneoffields$);\n", + "messageId", !message_id.empty() ? + ("'" + message_id + "'") : + (IsResponse(desc) ? "''" : "0"), + "pivot", GetPivot(desc), + "rptfields", RepeatedFieldsArrayName(options, desc), + "oneoffields", OneofFieldsArrayName(options, desc)); + printer->Print( + "};\n" + "goog.inherits($classname$, jspb.Message);\n" + "if (goog.DEBUG && !COMPILED) {\n" + " $classname$.displayName = '$classname$';\n" + "}\n", + "classname", GetPath(options, desc)); +} + +void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (HasRepeatedFields(desc)) { + printer->Print( + "/**\n" + " * List of repeated fields within this message type.\n" + " * @private {!Array<number>}\n" + " * @const\n" + " */\n" + "$classname$$rptfieldarray$ = $rptfields$;\n" + "\n", + "classname", GetPath(options, desc), + "rptfieldarray", kRepeatedFieldArrayName, + "rptfields", RepeatedFieldNumberList(desc)); + } + + if (HasOneofFields(desc)) { + printer->Print( + "/**\n" + " * Oneof group definitions for this message. Each group defines the " + "field\n" + " * numbers belonging to that group. When of these fields' value is " + "set, all\n" + " * other fields in the group are cleared. During deserialization, if " + "multiple\n" + " * fields are encountered for a group, only the last value seen will " + "be kept.\n" + " * @private {!Array<!Array<number>>}\n" + " * @const\n" + " */\n" + "$classname$$oneofgrouparray$ = $oneofgroups$;\n" + "\n", + "classname", GetPath(options, desc), + "oneofgrouparray", kOneofGroupArrayName, + "oneofgroups", OneofGroupList(desc)); + + for (int i = 0; i < desc->oneof_decl_count(); i++) { + if (IgnoreOneof(desc->oneof_decl(i))) { + continue; + } + GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i)); + } + } +} + +void Generator::GenerateClassXid(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "\n" + "\n" + "$class$.prototype.messageXid = xid('$class$');\n", + "class", GetPath(options, desc)); +} + +void Generator::GenerateOneofCaseDefinition( + const GeneratorOptions& options, + io::Printer* printer, + const OneofDescriptor* oneof) const { + printer->Print( + "/**\n" + " * @enum {number}\n" + " */\n" + "$classname$.$oneof$Case = {\n" + " $upcase$_NOT_SET: 0", + "classname", GetPath(options, oneof->containing_type()), + "oneof", JSOneofName(oneof), + "upcase", ToEnumCase(oneof->name())); + + for (int i = 0; i < oneof->field_count(); i++) { + if (IgnoreField(oneof->field(i))) { + continue; + } + + printer->Print( + ",\n" + " $upcase$: $number$", + "upcase", ToEnumCase(oneof->field(i)->name()), + "number", JSFieldIndex(oneof->field(i))); + } + + printer->Print( + "\n" + "};\n" + "\n" + "/**\n" + " * @return {$class$.$oneof$Case}\n" + " */\n" + "$class$.prototype.get$oneof$Case = function() {\n" + " return /** @type {$class$.$oneof$Case} */(jspb.Message." + "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n" + "};\n" + "\n", + "class", GetPath(options, oneof->containing_type()), + "oneof", JSOneofName(oneof), + "oneofindex", JSOneofIndex(oneof)); +} + +void Generator::GenerateClassToObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "\n" + "\n" + "if (jspb.Message.GENERATE_TO_OBJECT) {\n" + "/**\n" + " * Creates an object representation of this proto suitable for use in " + "Soy templates.\n" + " * Field names that are reserved in JavaScript and will be renamed to " + "pb_name.\n" + " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n" + " * For the list of reserved names please see:\n" + " * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.\n" + " * @param {boolean=} opt_includeInstance Whether to include the JSPB " + "instance\n" + " * for transitional soy proto support: http://goto/soy-param-" + "migration\n" + " * @return {!Object}\n" + " */\n" + "$classname$.prototype.toObject = function(opt_includeInstance) {\n" + " return $classname$.toObject(opt_includeInstance, this);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Static version of the {@see toObject} method.\n" + " * @param {boolean|undefined} includeInstance Whether to include the " + "JSPB\n" + " * instance for transitional soy proto support:\n" + " * http://goto/soy-param-migration\n" + " * @param {!$classname$} msg The msg instance to transform.\n" + " * @return {!Object}\n" + " */\n" + "$classname$.toObject = function(includeInstance, msg) {\n" + " var f, obj = {", + "classname", GetPath(options, desc)); + + bool first = true; + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + if (IgnoreField(field)) { + continue; + } + + if (!first) { + printer->Print(",\n "); + } else { + printer->Print("\n "); + first = false; + } + + GenerateClassFieldToObject(options, printer, field); + } + + if (!first) { + printer->Print("\n };\n\n"); + } else { + printer->Print("\n\n };\n\n"); + } + + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), " + "obj,\n" + " $extObject$, $class$.prototype.getExtension,\n" + " includeInstance);\n", + "extObject", JSExtensionsObjectName(options, desc->file(), desc), + "class", GetPath(options, desc)); + } + + printer->Print( + " if (includeInstance) {\n" + " obj.$$jspbMessageInstance = msg;\n" + " }\n" + " return obj;\n" + "};\n" + "}\n" + "\n" + "\n", + "classname", GetPath(options, desc)); +} + +void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print("$fieldname$: ", + "fieldname", JSObjectFieldName(field)); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message field. + if (field->is_repeated()) { + { + printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" + " $type$.toObject, includeInstance)", + "getter", JSGetterName(field), + "type", SubmessageTypeRef(options, field)); + } + } else { + printer->Print("(f = msg.get$getter$()) && " + "$type$.toObject(includeInstance, f)", + "getter", JSGetterName(field), + "type", SubmessageTypeRef(options, field)); + } + } else { + // Simple field (singular or repeated). + if ((!HasFieldPresence(field) && !field->is_repeated()) || + field->type() == FieldDescriptor::TYPE_BYTES) { + // Delegate to the generated get<field>() method in order not to duplicate + // the proto3-field-default-value or byte-coercion logic here. + printer->Print("msg.get$getter$()", + "getter", JSGetterName(field, BYTES_B64)); + } else { + if (field->has_default_value()) { + 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)); + } + } + } +} + +void Generator::GenerateClassFromObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "if (jspb.Message.GENERATE_FROM_OBJECT) {\n" + "/**\n" + " * Loads data from an object into a new instance of this proto.\n" + " * @param {!Object} obj The object representation of this proto to\n" + " * load the data from.\n" + " * @return {!$classname$}\n" + " */\n" + "$classname$.fromObject = function(obj) {\n" + " var f, msg = new $classname$();\n", + "classname", GetPath(options, desc)); + + for (int i = 0; i < desc->field_count(); i++) { + const FieldDescriptor* field = desc->field(i); + GenerateClassFieldFromObject(options, printer, field); + } + + printer->Print( + " return msg;\n" + "};\n" + "}\n"); +} + +void Generator::GenerateClassFieldFromObject( + const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message field (singular or repeated) + if (field->is_repeated()) { + { + printer->Print( + " goog.isDef(obj.$name$) && " + "jspb.Message.setRepeatedWrapperField(\n" + " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" + " return $fieldclass$.fromObject(i);\n" + " }));\n", + "name", JSObjectFieldName(field), + "index", JSFieldIndex(field), + "fieldclass", SubmessageTypeRef(options, field)); + } + } else { + printer->Print( + " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" + " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", + "name", JSObjectFieldName(field), + "index", JSFieldIndex(field), + "fieldclass", SubmessageTypeRef(options, field)); + } + } else { + // Simple (primitive) field. + printer->Print( + " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " + "obj.$name$);\n", + "name", JSObjectFieldName(field), + "index", JSFieldIndex(field)); + } +} + +void Generator::GenerateClassClone(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "/**\n" + " * Creates a deep clone of this proto. No data is shared with the " + "original.\n" + " * @return {!$name$} The clone.\n" + " */\n" + "$name$.prototype.cloneMessage = function() {\n" + " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n" + "};\n\n\n", + "name", GetPath(options, desc)); +} + +void Generator::GenerateClassRegistration(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + // Register any extensions defined inside this message type. + for (int i = 0; i < desc->extension_count(); i++) { + const FieldDescriptor* extension = desc->extension(i); + if (ShouldGenerateExtension(extension)) { + GenerateExtension(options, printer, extension); + } + } + +} + +void Generator::GenerateClassFields(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + for (int i = 0; i < desc->field_count(); i++) { + if (!IgnoreField(desc->field(i))) { + GenerateClassField(options, printer, desc->field(i)); + } + } +} + +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 { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * @return {$type$}\n" + " */\n", + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field, BYTES_DEFAULT), + "type", JSFieldTypeAnnotation(options, field, + /* force_optional = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false)); + printer->Print( + "$class$.prototype.get$name$ = function() {\n" + " return /** @type{$type$} */ (\n" + " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " + "$index$$required$));\n" + "};\n" + "\n" + "\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field), + "type", JSFieldTypeAnnotation(options, field, + /* force_optional = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false), + "rpt", (field->is_repeated() ? "Repeated" : ""), + "index", JSFieldIndex(field), + "wrapperclass", SubmessageTypeRef(options, field), + "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? + ", 1" : "")); + printer->Print( + "/** @param {$optionaltype$} value $returndoc$ */\n" + "$class$.prototype.set$name$ = function(value) {\n" + " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", + "optionaltype", + JSFieldTypeAnnotation(options, field, + /* force_optional = */ true, + /* force_present = */ false, + /* singular_if_not_packed = */ false), + "returndoc", JSReturnDoc(options, field), + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field), + "oneoftag", (field->containing_oneof() ? "Oneof" : ""), + "repeatedtag", (field->is_repeated() ? "Repeated" : "")); + + printer->Print( + "this, $index$$oneofgroup$, value);$returnvalue$\n" + "};\n" + "\n" + "\n", + "index", JSFieldIndex(field), + "oneofgroup", (field->containing_oneof() ? + (", " + JSOneofArray(options, field)) : ""), + "returnvalue", JSReturnClause(field)); + + printer->Print( + "$class$.prototype.clear$name$ = function() {\n" + " this.set$name$($clearedvalue$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field), + "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), + "returnvalue", JSReturnClause(field)); + + } else { + bool untyped = + false; + + // Simple (primitive) field, either singular or repeated. + + // 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, + /* bytes_mode = */ bytes_mode); + if (untyped) { + printer->Print( + "/**\n" + " * @return {?} Raw field, untyped.\n" + " */\n"); + } else { + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * @return {$type$}\n" + " */\n", + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field, bytes_mode), + "type", typed_annotation); + } + + printer->Print( + "$class$.prototype.get$name$ = function() {\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field)); + + if (untyped) { + printer->Print( + " return "); + } else { + printer->Print( + " return /** @type {$type$} */ (", + "type", typed_annotation); + } + + // For proto3 fields without presence, use special getters that will return + // defaults when the field is unset, possibly constructing a value if + // required. + if (!HasFieldPresence(field) && !field->is_repeated()) { + printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)", + "index", JSFieldIndex(field), + "default", Proto3PrimitiveFieldDefault(field)); + } else { + if (field->has_default_value()) { + 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" + "\n" + "\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), + "returndoc", JSReturnDoc(options, field)); + } + printer->Print( + "$class$.prototype.set$name$ = function(value) {\n" + " jspb.Message.set$oneoftag$Field(this, $index$", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field), + "oneoftag", (field->containing_oneof() ? "Oneof" : ""), + "index", JSFieldIndex(field)); + printer->Print( + "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "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( + "$class$.prototype.clear$name$ = function() {\n" + " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field), + "oneoftag", (field->containing_oneof() ? "Oneof" : ""), + "oneofgroup", (field->containing_oneof() ? + (", " + JSOneofArray(options, field)) : ""), + "index", JSFieldIndex(field)); + printer->Print( + "$clearedvalue$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), + "returnvalue", JSReturnClause(field)); + } + } +} + +void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + if (IsExtendable(desc)) { + printer->Print( + "\n" + "/**\n" + " * The extensions registered with this message class. This is a " + "map of\n" + " * extension field number to fieldInfo object.\n" + " *\n" + " * For example:\n" + " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " + "ctor: proto.example.MyMessage} }\n" + " *\n" + " * fieldName contains the JsCompiler renamed field name property " + "so that it\n" + " * works in OPTIMIZED mode.\n" + " *\n" + " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" + " */\n" + "$class$.extensions = {};\n" + "\n", + "class", GetPath(options, desc)); + } +} + + +void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + // TODO(cfallin): Handle lazy decoding when requested by field option and/or + // by default for 'bytes' fields and packed repeated fields. + + printer->Print( + "/**\n" + " * Deserializes binary data (in protobuf wire format).\n" + " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n" + " * @return {!$class$}\n" + " */\n" + "$class$.deserializeBinary = function(bytes) {\n" + " var reader = new jspb.BinaryReader(bytes);\n" + " var msg = new $class$;\n" + " return $class$.deserializeBinaryFromReader(msg, reader);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Deserializes binary data (in protobuf wire format) from the\n" + " * given reader into the given message object.\n" + " * @param {!$class$} msg The message object to deserialize into.\n" + " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n" + " * @return {!$class$}\n" + " */\n" + "$class$.deserializeBinaryFromReader = function(msg, reader) {\n" + " while (reader.nextField()) {\n" + " if (reader.isEndGroup()) {\n" + " break;\n" + " }\n" + " var field = reader.getFieldNumber();\n" + " switch (field) {\n", + "class", GetPath(options, desc)); + + for (int i = 0; i < desc->field_count(); i++) { + GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); + } + + printer->Print( + " default:\n"); + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n" + " $class$.prototype.getExtension,\n" + " $class$.prototype.setExtension);\n" + " break;\n", + "extobj", JSExtensionsObjectName(options, desc->file(), desc), + "class", GetPath(options, desc)); + } else { + printer->Print( + " reader.skipField();\n" + " break;\n"); + } + + printer->Print( + " }\n" + " }\n" + " return msg;\n" + "};\n" + "\n" + "\n"); +} + +void Generator::GenerateClassDeserializeBinaryField( + const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + + printer->Print(" case $num$:\n", + "num", SimpleItoa(field->number())); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + " var value = new $fieldclass$;\n" + " reader.read$msgOrGroup$($grpfield$value," + "$fieldclass$.deserializeBinaryFromReader);\n", + "fieldclass", SubmessageTypeRef(options, field), + "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? + "Group" : "Message", + "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? + (SimpleItoa(field->number()) + ", ") : ""); + } else { + printer->Print( + " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", + "fieldtype", JSFieldTypeAnnotation(options, field, false, true, + /* singular_if_not_packed = */ true, + 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$(). 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 + // the field's value directly. + printer->Print( + " msg.set$name$(value);\n", + "name", JSGetterName(field)); + } + + printer->Print(" break;\n"); +} + +void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const { + printer->Print( + "/**\n" + " * Class method variant: serializes the given message to binary data\n" + " * (in protobuf wire format), writing to the given BinaryWriter.\n" + " * @param {!$class$} message\n" + " * @param {!jspb.BinaryWriter} writer\n" + " */\n" + "$class$.serializeBinaryToWriter = function(message, " + "writer) {\n" + " message.serializeBinaryToWriter(writer);\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Serializes the message to binary data (in protobuf wire format).\n" + " * @return {!Uint8Array}\n" + " */\n" + "$class$.prototype.serializeBinary = function() {\n" + " var writer = new jspb.BinaryWriter();\n" + " this.serializeBinaryToWriter(writer);\n" + " return writer.getResultBuffer();\n" + "};\n" + "\n" + "\n" + "/**\n" + " * Serializes the message to binary data (in protobuf wire format),\n" + " * writing to the given BinaryWriter.\n" + " * @param {!jspb.BinaryWriter} writer\n" + " */\n" + "$class$.prototype.serializeBinaryToWriter = function (writer) {\n" + " var f = undefined;\n", + "class", GetPath(options, desc)); + + for (int i = 0; i < desc->field_count(); i++) { + GenerateClassSerializeBinaryField(options, printer, desc->field(i)); + } + + if (IsExtendable(desc)) { + printer->Print( + " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n" + " $class$.prototype.getExtension);\n", + "extobj", JSExtensionsObjectName(options, desc->file(), desc), + "class", GetPath(options, desc)); + } + + printer->Print( + "};\n" + "\n" + "\n"); +} + +void Generator::GenerateClassSerializeBinaryField( + const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + printer->Print( + " f = this.get$name$();\n", + "name", JSGetterName(field, BYTES_U8)); + + if (field->is_repeated()) { + printer->Print( + " if (f.length > 0) {\n"); + } else { + if (HasFieldPresence(field)) { + printer->Print( + " if (f != null) {\n"); + } else { + // No field presence: serialize onto the wire only if value is + // non-default. Defaults are documented here: + // https://goto.google.com/lhdfm + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: { + { + printer->Print(" if (f !== 0) {\n"); + } + break; + } + + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + printer->Print( + " if (f !== 0.0) {\n"); + break; + case FieldDescriptor::CPPTYPE_BOOL: + printer->Print( + " if (f) {\n"); + break; + case FieldDescriptor::CPPTYPE_STRING: + printer->Print( + " if (f.length > 0) {\n"); + break; + default: + assert(false); + break; + } + } + } + + printer->Print( + " writer.$writer$(\n" + " $index$,\n" + " f", + "writer", JSBinaryWriterMethodName(field), + "index", SimpleItoa(field->number())); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + ",\n" + " $submsg$.serializeBinaryToWriter\n", + "submsg", SubmessageTypeRef(options, field)); + } else { + printer->Print("\n"); + } + printer->Print( + " );\n" + " }\n"); +} + +void Generator::GenerateEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc) const { + printer->Print( + "/**\n" + " * @enum {number}\n" + " */\n" + "$name$ = {\n", + "name", GetPath(options, enumdesc)); + + for (int i = 0; i < enumdesc->value_count(); i++) { + const EnumValueDescriptor* value = enumdesc->value(i); + printer->Print( + " $name$: $value$$comma$\n", + "name", ToEnumCase(value->name()), + "value", SimpleItoa(value->number()), + "comma", (i == enumdesc->value_count() - 1) ? "" : ","); + } + + printer->Print( + "};\n" + "\n"); +} + +void Generator::GenerateExtension(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const { + string extension_scope = + (field->extension_scope() ? + GetPath(options, field->extension_scope()) : + GetPath(options, field->file())); + + printer->Print( + "\n" + "/**\n" + " * A tuple of {field number, class constructor} for the extension\n" + " * field named `$name$`.\n" + " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" + " */\n" + "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", + "name", JSObjectFieldName(field), + "class", extension_scope, + "extensionType", JSFieldTypeAnnotation( + options, field, + /* force_optional = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false)); + printer->Print( + " $index$,\n" + " {$name$: 0},\n" + " $ctor$,\n" + " /** @type {?function((boolean|undefined),!jspb.Message=): " + "!Object} */ (\n" + " $toObject$),\n" + " $repeated$", + "index", SimpleItoa(field->number()), + "name", JSObjectFieldName(field), + "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? + SubmessageTypeRef(options, field) : string("null")), + "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? + (SubmessageTypeRef(options, field) + ".toObject") : + string("null")), + "repeated", (field->is_repeated() ? "1" : "0")); + + if (options.binary) { + printer->Print( + ",\n" + " jspb.BinaryReader.prototype.$binaryReaderFn$,\n" + " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n" + " $binaryMessageSerializeFn$,\n" + " $binaryMessageDeserializeFn$,\n" + " $isPacked$);\n", + "binaryReaderFn", JSBinaryReaderMethodName(field), + "binaryWriterFn", JSBinaryWriterMethodName(field), + "binaryMessageSerializeFn", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? + (SubmessageTypeRef(options, field) + + ".serializeBinaryToWriter") : "null", + "binaryMessageDeserializeFn", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? + (SubmessageTypeRef(options, field) + + ".deserializeBinaryFromReader") : "null", + "isPacked", (field->is_packed() ? "true" : "false")); + } else { + printer->Print(");\n"); + } + + printer->Print( + "// This registers the extension field with the extended class, so that\n" + "// toObject() will function correctly.\n" + "$extendName$[$index$] = $class$.$name$;\n" + "\n", + "extendName", JSExtensionsObjectName(options, field->file(), + field->containing_type()), + "index", SimpleItoa(field->number()), + "class", extension_scope, + "name", JSObjectFieldName(field)); +} + +bool GeneratorOptions::ParseFromOptions( + const vector< pair< string, string > >& options, + string* error) { + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "add_require_for_enums") { + if (options[i].second != "") { + *error = "Unexpected option value for add_require_for_enums"; + return false; + } + add_require_for_enums = true; + } else if (options[i].first == "binary") { + if (options[i].second != "") { + *error = "Unexpected option value for binary"; + return false; + } + binary = true; + } else if (options[i].first == "testonly") { + if (options[i].second != "") { + *error = "Unexpected option value for testonly"; + return false; + } + testonly = true; + } else if (options[i].first == "error_on_name_conflict") { + if (options[i].second != "") { + *error = "Unexpected option value for error_on_name_conflict"; + return false; + } + error_on_name_conflict = true; + } else if (options[i].first == "output_dir") { + output_dir = options[i].second; + } else if (options[i].first == "namespace_prefix") { + namespace_prefix = options[i].second; + } else if (options[i].first == "library") { + library = options[i].second; + } else if (options[i].first == "import_style") { + if (options[i].second == "closure") { + import_style = IMPORT_CLOSURE; + } else if (options[i].second == "commonjs") { + import_style = IMPORT_COMMONJS; + } else if (options[i].second == "browser") { + import_style = IMPORT_BROWSER; + } else if (options[i].second == "es6") { + import_style = IMPORT_ES6; + } else { + *error = "Unknown import style " + options[i].second + ", expected " + + "one of: closure, commonjs, browser, es6."; + } + } else { + // Assume any other option is an output directory, as long as it is a bare + // `key` rather than a `key=value` option. + if (options[i].second != "") { + *error = "Unknown option: " + options[i].first; + return false; + } + output_dir = options[i].first; + } + } + + if (!library.empty() && import_style != IMPORT_CLOSURE) { + *error = "The library option should only be used for " + "import_style=closure"; + } + + return true; +} + +void Generator::GenerateFilesInDepOrder( + const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& files) const { + // Build a std::set over all files so that the DFS can detect when it recurses + // into a dep not specified in the user's command line. + std::set<const FileDescriptor*> all_files(files.begin(), files.end()); + // Track the in-progress set of files that have been generated already. + std::set<const FileDescriptor*> generated; + for (int i = 0; i < files.size(); i++) { + GenerateFileAndDeps(options, printer, files[i], &all_files, &generated); + } +} + +void Generator::GenerateFileAndDeps( + const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* root, + std::set<const FileDescriptor*>* all_files, + std::set<const FileDescriptor*>* generated) const { + // Skip if already generated. + if (generated->find(root) != generated->end()) { + return; + } + generated->insert(root); + + // Generate all dependencies before this file's content. + for (int i = 0; i < root->dependency_count(); i++) { + const FileDescriptor* dep = root->dependency(i); + GenerateFileAndDeps(options, printer, dep, all_files, generated); + } + + // Generate this file's content. Only generate if the file is part of the + // original set requested to be generated; i.e., don't take all transitive + // deps down to the roots. + if (all_files->find(root) != all_files->end()) { + GenerateClassesAndEnums(options, printer, root); + } +} + +void Generator::GenerateFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const { + GenerateHeader(options, printer); + + // Generate "require" statements. + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + printer->Print("var jspb = require('google-protobuf');\n"); + printer->Print("var goog = jspb;\n"); + printer->Print("var global = Function('return this')();\n\n"); + + for (int i = 0; i < file->dependency_count(); i++) { + const string& name = file->dependency(i)->name(); + printer->Print( + "var $alias$ = require('$file$');\n", + "alias", ModuleAlias(name), + "file", GetRootPath(file->name()) + GetJSFilename(name)); + } + } + + // We aren't using Closure's import system, but we use goog.exportSymbol() + // to construct the expected tree of objects, eg. + // + // goog.exportSymbol('foo.bar.Baz', null, this); + // + // // Later generated code expects foo.bar = {} to exist: + // foo.bar.Baz = function() { /* ... */ } + set<string> provided; + + // Cover the case where this file declares extensions but no messages. + // This will ensure that the file-level object will be declared to hold + // the extensions. + for (int i = 0; i < file->extension_count(); i++) { + provided.insert(file->extension(i)->full_name()); + } + + FindProvidesForFile(options, printer, file, &provided); + for (std::set<string>::iterator it = provided.begin(); + it != provided.end(); ++it) { + printer->Print("goog.exportSymbol('$name$', null, global);\n", + "name", *it); + } + + GenerateClassesAndEnums(options, printer, file); + + // Extensions nested inside messages are emitted inside + // GenerateClassesAndEnums(). + for (int i = 0; i < file->extension_count(); i++) { + GenerateExtension(options, printer, file->extension(i)); + } + + if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + printer->Print("goog.object.extend(exports, $package$);\n", + "package", GetPath(options, file)); + } +} + +bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, + const string& parameter, + GeneratorContext* context, + string* error) const { + vector< pair< string, string > > option_pairs; + ParseGeneratorParameter(parameter, &option_pairs); + GeneratorOptions options; + if (!options.ParseFromOptions(option_pairs, error)) { + return false; + } + + + // There are three schemes for where output files go: + // + // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file + // - import_style = IMPORT_CLOSURE, library empty: one output file per type + // - import_style != IMPORT_CLOSURE: one output file per .proto file + if (options.import_style == GeneratorOptions::IMPORT_CLOSURE && + options.library != "") { + // All output should go in a single file. + string filename = options.output_dir + "/" + options.library + ".js"; + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + + // Pull out all extensions -- we need these to generate all + // provides/requires. + vector<const FieldDescriptor*> extensions; + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + extensions.push_back(extension); + } + } + + GenerateHeader(options, &printer); + + std::set<string> provided; + FindProvides(options, &printer, files, &provided); + FindProvidesForFields(options, &printer, extensions, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForLibrary(options, &printer, files, &provided); + + GenerateFilesInDepOrder(options, &printer, files); + + for (int i = 0; i < extensions.size(); i++) { + if (ShouldGenerateExtension(extensions[i])) { + GenerateExtension(options, &printer, extensions[i]); + } + } + + if (printer.failed()) { + return false; + } + } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { + set<const void*> allowed_set; + if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { + return false; + } + + 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_set.count(desc) == 0) { + continue; + } + + string filename = GetMessageFileName(options, desc); + 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; + FindProvidesForMessage(options, &printer, desc, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForMessage(options, &printer, desc, &provided); + + GenerateClass(options, &printer, desc); + + if (printer.failed()) { + return false; + } + } + for (int j = 0; j < file->enum_type_count(); j++) { + const EnumDescriptor* enumdesc = file->enum_type(j); + if (allowed_set.count(enumdesc) == 0) { + continue; + } + + string filename = GetEnumFileName(options, enumdesc); + 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; + FindProvidesForEnum(options, &printer, enumdesc, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + + GenerateEnum(options, &printer, enumdesc); + + if (printer.failed()) { + return false; + } + } + // File-level extensions (message-level extensions are generated under + // the enclosing message). + if (allowed_set.count(file) == 1) { + string filename = GetExtensionFileName(options, file); + + 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; + + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + fields.push_back(files[i]->extension(j)); + } + } + + FindProvidesForFields(options, &printer, fields, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForExtensions(options, &printer, fields, &provided); + + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + GenerateExtension(options, &printer, files[i]->extension(j)); + } + } + } + } + } else { + // Generate one output file per input (.proto) file. + + for (int i = 0; i < files.size(); i++) { + const google::protobuf::FileDescriptor* file = files[i]; + + string filename = options.output_dir + "/" + GetJSFilename(file->name()); + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + + GenerateFile(options, &printer, file); + + if (printer.failed()) { + return false; + } + } + } + + return true; +} + +} // namespace js +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h new file mode 100755 index 00000000..6fd7ca50 --- /dev/null +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -0,0 +1,281 @@ +// 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_JS_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__ + +#include <string> +#include <set> + +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class FieldDescriptor; +class OneofDescriptor; +class FileDescriptor; + +namespace io { class Printer; } + +namespace compiler { +namespace js { + +struct GeneratorOptions { + // Add a `goog.requires()` call for each enum type used. If not set, a forward + // declaration with `goog.forwardDeclare` is produced instead. + bool add_require_for_enums; + // Set this as a test-only module via `goog.setTestOnly();`. + bool testonly; + // Output path. + string output_dir; + // Namespace prefix. + string namespace_prefix; + // Create a library with name <name>_lib.js rather than a separate .js file + // per type? + string library; + // Error if there are two types that would generate the same output file? + bool error_on_name_conflict; + // Enable binary-format support? + bool binary; + // What style of imports should be used. + enum ImportStyle { + IMPORT_CLOSURE, // goog.require() + IMPORT_COMMONJS, // require() + IMPORT_BROWSER, // no import statements + IMPORT_ES6, // import { member } from '' + } import_style; + + GeneratorOptions() + : add_require_for_enums(false), + testonly(false), + output_dir("."), + namespace_prefix(""), + library(""), + error_on_name_conflict(false), + binary(false), + import_style(IMPORT_CLOSURE) {} + + bool ParseFromOptions( + const vector< pair< string, string > >& options, + string* error); +}; + +class LIBPROTOC_EXPORT Generator : public CodeGenerator { + public: + Generator() {} + virtual ~Generator() {} + + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* context, + string* error) const { + *error = "Unimplemented Generate() method. Call GenerateAll() instead."; + return false; + } + + virtual bool HasGenerateAll() const { return true; } + + virtual bool GenerateAll(const vector<const FileDescriptor*>& files, + const string& parameter, + GeneratorContext* context, + string* error) const; + + private: + void GenerateHeader(const GeneratorOptions& options, + io::Printer* printer) const; + + // Generate goog.provides() calls. + void FindProvides(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& file, + std::set<string>* provided) const; + void FindProvidesForFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file, + std::set<string>* provided) const; + void FindProvidesForMessage(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set<string>* provided) const; + void FindProvidesForEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc, + std::set<string>* provided) const; + // For extension fields at file scope. + void FindProvidesForFields(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FieldDescriptor*>& fields, + std::set<string>* provided) const; + // Print the goog.provides() found by the methods above. + void GenerateProvides(const GeneratorOptions& options, + io::Printer* printer, + std::set<string>* provided) const; + + // Generate goog.setTestOnly() if indicated. + void GenerateTestOnly(const GeneratorOptions& options, + io::Printer* printer) const; + + // Generate goog.requires() calls. + 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 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, + std::set<string>* forwards, + std::set<string>* provided, + bool require_jspb, + bool require_extension) const; + void FindRequiresForMessage(const GeneratorOptions& options, + const Descriptor* desc, + std::set<string>* required, + std::set<string>* forwards, + bool* have_message) const; + void FindRequiresForField(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<string>* required, + std::set<string>* forwards) const; + void FindRequiresForExtension(const GeneratorOptions& options, + const FieldDescriptor* field, + std::set<string>* required, + std::set<string>* forwards) const; + + void GenerateFile(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const; + + // Generate definitions for all message classes and enums in all files, + // processing the files in dependence order. + void GenerateFilesInDepOrder(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& file) const; + // Helper for above. + void GenerateFileAndDeps(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* root, + std::set<const FileDescriptor*>* all_files, + std::set<const FileDescriptor*>* generated) const; + + // Generate definitions for all message classes and enums. + void GenerateClassesAndEnums(const GeneratorOptions& options, + io::Printer* printer, + const FileDescriptor* file) const; + + // Generate definition for one class. + void GenerateClass(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassConstructor(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassXid(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateOneofCaseDefinition(const GeneratorOptions& options, + io::Printer* printer, + const OneofDescriptor* oneof) const; + void GenerateClassToObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldToObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassFromObject(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFieldFromObject(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassClone(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassRegistration(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassFields(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* desc) const; + void GenerateClassExtensionFieldInfo(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserialize(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassDeserializeBinaryField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + void GenerateClassSerializeBinary(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc) const; + void GenerateClassSerializeBinaryField(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + + // Generate definition for one enum. + void GenerateEnum(const GeneratorOptions& options, + io::Printer* printer, + const EnumDescriptor* enumdesc) const; + + // Generate an extension definition. + void GenerateExtension(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); +}; + +} // namespace js +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 584e5a40..66ad13b7 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -38,6 +38,7 @@ #include <google/protobuf/compiler/ruby/ruby_generator.h> #include <google/protobuf/compiler/csharp/csharp_generator.h> #include <google/protobuf/compiler/objectivec/objectivec_generator.h> +#include <google/protobuf/compiler/js/js_generator.h> int main(int argc, char* argv[]) { @@ -77,8 +78,13 @@ int main(int argc, char* argv[]) { // Objective C google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator; - cli.RegisterGenerator("--objc_out", &objc_generator, + cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator, "Generate Objective C header and source."); + // JavaScript + google::protobuf::compiler::js::Generator js_generator; + cli.RegisterGenerator("--js_out", &js_generator, + "Generate JavaScript source."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc index 98261431..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 { @@ -147,6 +153,12 @@ bool MockCodeGenerator::Generate( std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: " << has_source_code_info << "." << std::endl; abort(); + } else if (command == "HasJsonName") { + FieldDescriptorProto field_descriptor_proto; + file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto); + std::cerr << "Saw json_name: " + << field_descriptor_proto.has_json_name() << std::endl; + abort(); } else { GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command; } 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 d6f01c60..e76f8e99 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -72,18 +72,21 @@ 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(); if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { // Include the unknown value. printer->Print( + "/// Value used if any message's field encounters a value that is not defined\n" + "/// by this enum. The message will also have C functions to get/set the rawValue\n" + "/// of the field.\n" "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", "name", name_); } - for (int i = 0; i < all_values_.size(); i++) { SourceLocation location; if (all_values_[i]->GetSourceLocation(&location)) { @@ -97,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(); @@ -107,6 +111,8 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { "\n" "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" "\n" + "/// Checks to see if the given value is defined by the enum or was not known at\n" + "/// the time this source was generated.\n" "BOOL $name$_IsValidValue(int32_t value);\n" "\n", "name", name_); @@ -118,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 @@ -135,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 30a13ddb..b63bc0de 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -44,6 +44,7 @@ namespace compiler { namespace objectivec { namespace { + void SetEnumVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { string type = EnumName(descriptor->enum_type()); @@ -58,25 +59,22 @@ 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); } } // namespace -EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : SingleFieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_); } 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())) { @@ -85,7 +83,12 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations( printer->Print( variables_, + "/// Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n" + "/// if the value was not defined by the enum at the time the code was generated.\n" "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n" + "/// Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n" + "/// it to be set to a value that was not defined by the enum at the time the code\n" + "/// was generated.\n" "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n" "\n"); } @@ -112,6 +115,7 @@ void EnumFieldGenerator::GenerateCFunctionImplementations( void EnumFieldGenerator::DetermineForwardDeclarations( set<string>* fwd_decls) const { + SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls); // If it is an enum defined in a different file, then we'll need a forward // declaration for it. When it is in our file, all the enums are output // before the message, so it will be declared before it is needed. @@ -123,19 +127,18 @@ void EnumFieldGenerator::DetermineForwardDeclarations( } RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_); variables_["array_storage_type"] = "GPBEnumArray"; } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} -void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n"); +void RepeatedEnumFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + variables_["array_comment"] = + "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; } } // namespace objectivec diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h index b629eae8..946faa81 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -41,16 +41,16 @@ namespace compiler { namespace objectivec { class EnumFieldGenerator : public SingleFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + 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; protected: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor); + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual ~EnumFieldGenerator(); private: @@ -58,13 +58,15 @@ class EnumFieldGenerator : public SingleFieldGenerator { }; class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); public: - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; + virtual void FinishInitialization(); protected: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedEnumFieldGenerator(); private: 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 cf5d8cfb..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> @@ -45,6 +47,7 @@ namespace compiler { namespace objectivec { namespace { + void SetCommonFieldVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { string camel_case_name = FieldName(descriptor); @@ -74,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"); @@ -98,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"] = ""; @@ -117,39 +111,40 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, } // namespace -FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { +FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options) { FieldGenerator* result = NULL; if (field->is_repeated()) { switch (GetObjectiveCType(field)) { case OBJECTIVECTYPE_MESSAGE: { if (field->is_map()) { - result = new MapFieldGenerator(field); + result = new MapFieldGenerator(field, options); } else { - result = new RepeatedMessageFieldGenerator(field); + result = new RepeatedMessageFieldGenerator(field, options); } break; } case OBJECTIVECTYPE_ENUM: - result = new RepeatedEnumFieldGenerator(field); + result = new RepeatedEnumFieldGenerator(field, options); break; default: - result = new RepeatedPrimitiveFieldGenerator(field); + result = new RepeatedPrimitiveFieldGenerator(field, options); break; } } else { switch (GetObjectiveCType(field)) { case OBJECTIVECTYPE_MESSAGE: { - result = new MessageFieldGenerator(field); + result = new MessageFieldGenerator(field, options); break; } case OBJECTIVECTYPE_ENUM: - result = new EnumFieldGenerator(field); + result = new EnumFieldGenerator(field, options); break; default: if (IsReferenceType(field)) { - result = new PrimitiveObjFieldGenerator(field); + result = new PrimitiveObjFieldGenerator(field, options); } else { - result = new PrimitiveFieldGenerator(field); + result = new PrimitiveFieldGenerator(field, options); } break; } @@ -158,8 +153,8 @@ FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { return result; } - -FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor) +FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor, + const Options& options) : descriptor_(descriptor) { SetCommonFieldVariables(descriptor, &variables_); } @@ -188,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) { @@ -252,9 +249,9 @@ void FieldGenerator::FinishInitialization(void) { } } -SingleFieldGenerator::SingleFieldGenerator( - const FieldDescriptor* descriptor) - : FieldGenerator(descriptor) { +SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(descriptor, options) { // Nothing } @@ -268,15 +265,15 @@ void SingleFieldGenerator::GenerateFieldStorageDeclaration( void SingleFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@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"); } - printer->Print( - variables_, - "@property(nonatomic, readwrite) $property_type$ $name$;\n" - "\n"); } void SingleFieldGenerator::GeneratePropertyImplementation( @@ -300,9 +297,17 @@ bool SingleFieldGenerator::WantsHasProperty(void) const { return false; } -ObjCObjFieldGenerator::ObjCObjFieldGenerator( - const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { +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) { variables_["property_storage_attribute"] = "strong"; if (IsRetainedName(variables_["name"])) { variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; @@ -324,36 +329,38 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( // conventions (init*, new*, etc.) printer->Print(variables_, "$comments$"); + printer->Print( + variables_, + "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); if (WantsHasProperty()) { printer->Print( variables_, - "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + "/// Test to see if @c $name$ has been set.\n" + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); } - printer->Print( - variables_, - "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_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"); } RepeatedFieldGenerator::RepeatedFieldGenerator( - const FieldDescriptor* descriptor) - : ObjCObjFieldGenerator(descriptor) { - // Repeated fields don't use the has index. - variables_["has_index"] = "GPBNoHasBit"; + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { + // Default to no comment and let the cases needing it fill it in. + variables_["array_comment"] = ""; } RepeatedFieldGenerator::~RepeatedFieldGenerator() {} void RepeatedFieldGenerator::FinishInitialization(void) { FieldGenerator::FinishInitialization(); - variables_["array_comment"] = - "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; + if (variables_.find("array_property_type") == variables_.end()) { + variables_["array_property_type"] = variable("array_storage_type"); + } } void RepeatedFieldGenerator::GenerateFieldStorageDeclaration( @@ -379,13 +386,14 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( variables_, "$comments$" "$array_comment$" - "@property(nonatomic, readwrite, strong, null_resettable) $array_storage_type$ *$name$$storage_attribute$;\n" - "@property(nonatomic, readonly) NSUInteger $name$_Count;\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$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_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -395,7 +403,12 @@ bool RepeatedFieldGenerator::WantsHasProperty(void) const { return false; } -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) +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), field_generators_( new scoped_ptr<FieldGenerator>[descriptor->field_count()]), @@ -403,10 +416,12 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { // Construct all the FieldGenerators. for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i))); + field_generators_[i].reset( + FieldGenerator::Make(descriptor->field(i), options)); } for (int i = 0; i < descriptor->extension_count(); i++) { - extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i))); + extension_generators_[i].reset( + FieldGenerator::Make(descriptor->extension(i), options)); } } @@ -422,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 130a52dd..a3a4b1b6 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -49,24 +49,37 @@ namespace objectivec { class FieldGenerator { public: - static FieldGenerator* Make(const FieldDescriptor* field); + static FieldGenerator* Make(const FieldDescriptor* field, + const Options& options); virtual ~FieldGenerator(); + // Exposed for subclasses to fill in. virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0; virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0; - virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0; - virtual void GenerateFieldDescription(io::Printer* printer) const; - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; - virtual void GenerateFieldNumberConstant(io::Printer* printer) const; + // Called by GenerateFieldDescription, exposed for classes that need custom + // generation. + // Exposed for subclasses to extend, base does nothing. virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; virtual void GenerateCFunctionImplementations(io::Printer* printer) const; + // Exposed for subclasses, should always call it on the parent class also. virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + // Used during generation, not intended to be extended by subclasses. + 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 { @@ -81,7 +94,7 @@ class FieldGenerator { string raw_field_name() const { return variable("raw_field_name"); } protected: - explicit FieldGenerator(const FieldDescriptor* descriptor); + FieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual void FinishInitialization(void); virtual bool WantsHasProperty(void) const = 0; @@ -102,8 +115,11 @@ class SingleFieldGenerator : public FieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: - explicit SingleFieldGenerator(const FieldDescriptor* descriptor); + SingleFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual bool WantsHasProperty(void) const; private: @@ -119,7 +135,8 @@ class ObjCObjFieldGenerator : public SingleFieldGenerator { virtual void GeneratePropertyDeclaration(io::Printer* printer) const; protected: - explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor); + ObjCObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator); @@ -134,8 +151,11 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: - explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor); + RepeatedFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual void FinishInitialization(void); virtual bool WantsHasProperty(void) const; @@ -146,14 +166,20 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor); + FieldGeneratorMap(const Descriptor* descriptor, const Options& options); ~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 184a84a3..ed4fc6a3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -45,22 +45,23 @@ 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 { -FileGenerator::FileGenerator(const FileDescriptor *file) +FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) : file_(file), root_class_name_(FileClassName(file)), - is_public_dep_(false) { + is_public_dep_(false), + options_(options) { for (int i = 0; i < file_->enum_type_count(); i++) { EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); enum_generators_.push_back(generator); } for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator *generator = - new MessageGenerator(root_class_name_, file_->message_type(i)); + new MessageGenerator(root_class_name_, file_->message_type(i), options_); message_generators_.push_back(generator); } for (int i = 0; i < file_->extension_count(); i++) { @@ -95,7 +96,7 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { // code is being compiled with. printer->Print( "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n" - "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n" + "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n" "#endif\n" "\n", "protoc_gen_objc_version", @@ -114,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"); @@ -150,13 +154,15 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { printer->Print( "#pragma mark - $root_class_name$\n" "\n" + "/// Exposes the extension registry for this file.\n" + "///\n" + "/// The base class provides:\n" + "/// @code\n" + "/// + (GPBExtensionRegistry *)extensionRegistry;\n" + "/// @endcode\n" + "/// which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" + "/// this file and all files that it depends on.\n" "@interface $root_class_name$ : GPBRootObject\n" - "\n" - "// The base class provides:\n" - "// + (GPBExtensionRegistry *)extensionRegistry;\n" - "// which is an GPBExtensionRegistry that includes all the extensions defined by\n" - "// this file and all files that it depends on.\n" - "\n" "@end\n" "\n", "root_class_name", root_class_name_); @@ -186,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"); } @@ -213,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( @@ -340,6 +351,8 @@ void FileGenerator::GenerateSource(io::Printer *printer) { printer->Print( "\n" + "#pragma clang diagnostic pop\n" + "\n" "// @@protoc_insertion_point(global_scope)\n"); } @@ -352,7 +365,8 @@ const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { public_import_names.insert(file_->public_dependency(i)->name()); } for (int i = 0; i < file_->dependency_count(); i++) { - FileGenerator *generator = new FileGenerator(file_->dependency(i)); + FileGenerator *generator = + new FileGenerator(file_->dependency(i), options_); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); generator->SetIsPublicDependency(public_import); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index 1bb4f0ea..4c0fcd3f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -55,7 +55,7 @@ class MessageGenerator; class FileGenerator { public: - explicit FileGenerator(const FileDescriptor* file); + FileGenerator(const FileDescriptor* file, const Options& options); ~FileGenerator(); void GenerateSource(io::Printer* printer); @@ -84,6 +84,8 @@ class FileGenerator { vector<ExtensionGenerator*> extension_generators_; bool is_public_dep_; + const Options options_; + const vector<FileGenerator*>& DependencyGenerators(); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index 375b4e0f..72e295de 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -49,21 +49,31 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, const string& parameter, OutputDirectory* output_directory, string* error) const { - // ObjC doesn't have any options at the moment, error if passed one. + // ----------------------------------------------------------------- + // Parse generator options. + + Options generation_options; + vector<pair<string, string> > options; ParseGeneratorParameter(parameter, &options); for (int i = 0; i < options.size(); i++) { - *error = "error:: Unknown generator option: " + options[i].first; - return false; + if (options[i].first == "expected_prefixes_path") { + generation_options.expected_prefixes_path = options[i].second; + } else { + *error = "error: Unknown generator option: " + options[i].first; + return false; + } } + // ----------------------------------------------------------------- + // Validate the objc prefix/package pairing. - if (!ValidateObjCClassPrefix(file, error)) { + if (!ValidateObjCClassPrefix(file, generation_options, error)) { // *error will have been filled in. return false; } - FileGenerator file_generator(file); + FileGenerator file_generator(file, generation_options); string filepath = FilePath(file); // Generate header. diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index b724d35c..196b39dd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -58,6 +58,14 @@ namespace protobuf { namespace compiler { namespace objectivec { +Options::Options() { + // Default is the value of the env for the package prefixes. + const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); + if (file_path) { + expected_prefixes_path = file_path; + } +} + namespace { hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) { @@ -116,9 +124,14 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { } values.push_back(current); + string result; + bool first_segment_forces_upper = false; for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { string value = *i; bool all_upper = (kUpperSegments.count(value) > 0); + if (all_upper && (result.length() == 0)) { + first_segment_forces_upper = true; + } for (int j = 0; j < value.length(); j++) { if (j == 0 || all_upper) { value[j] = ascii_toupper(value[j]); @@ -126,13 +139,11 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) { // Nothing, already in lower. } } - *i = value; - } - string result; - for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { - result += *i; + result += value; } - if ((result.length() != 0) && !first_capitalized) { + if ((result.length() != 0) && + !first_capitalized && + !first_segment_forces_upper) { result[0] = ascii_tolower(result[0]); } return result; @@ -209,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) { @@ -253,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"); @@ -723,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)) + "\""; } @@ -740,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"; @@ -763,16 +819,14 @@ string BuildCommentsString(const SourceLocation& location) { while (!lines.empty() && lines.back().empty()) { lines.pop_back(); } - string prefix("//"); + string prefix("///"); string suffix("\n"); string final_comments; for (int i = 0; i < lines.size(); i++) { - // We use $ for delimiters, so replace comments with dollars with - // html escaped version. - // None of the other compilers handle this (as of this writing) but we - // ran into it once, so just to be safe. + // HeaderDoc uses '\' and '@' for markers; escape them. + const string line = StringReplace(lines[i], "\\", "\\\\", true); final_comments += - prefix + StringReplace(lines[i], "$", "$", true) + suffix; + prefix + StringReplace(line, "@", "\\@", true) + suffix; } return final_comments; } @@ -883,33 +937,33 @@ bool Parser::ParseLoop() { StringPiece prefix(line, offset + 1, line.length() - offset - 1); TrimWhitespace(&package); TrimWhitespace(&prefix); - // Don't really worry about error checking the the package/prefix for + // Don't really worry about error checking the package/prefix for // being valid. Assume the file is validated when it is created/edited. (*prefix_map_)[package.ToString()] = prefix.ToString(); } return true; } -bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, - string* out_expect_file_path, +bool LoadExpectedPackagePrefixes(const Options &generation_options, + map<string, string>* prefix_map, string* out_error) { - const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); - if (file_path == NULL) { + if (generation_options.expected_prefixes_path.empty()) { return true; } int fd; do { - fd = open(file_path, O_RDONLY); + fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY); } while (fd < 0 && errno == EINTR); if (fd < 0) { *out_error = - string(file_path) + ":0:0: error: Unable to open." + strerror(errno); + string("error: Unable to open \"") + + generation_options.expected_prefixes_path + + "\", " + strerror(errno); return false; } io::FileInputStream file_stream(fd); file_stream.SetCloseOnDelete(true); - *out_expect_file_path = file_path; Parser parser(prefix_map); const void* buf; @@ -920,8 +974,9 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, } if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) { - *out_error = string(file_path) + ":" + SimpleItoa(parser.last_line()) + - ":0: error: " + parser.error_str(); + *out_error = + string("error: ") + generation_options.expected_prefixes_path + + " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str(); return false; } } @@ -930,48 +985,25 @@ bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map, } // namespace -bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { +bool ValidateObjCClassPrefix(const FileDescriptor* file, + const Options& generation_options, + string* out_error) { const string prefix = file->options().objc_class_prefix(); const string package = file->package(); // 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 warnings. - // First Check: Warning - if there is a prefix, ensure it is is a reasonable - // value according to Apple's rules. - if (prefix.length()) { - if (!ascii_isupper(prefix[0])) { - cerr << endl - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " it should start with a capital letter." << endl; - cerr.flush(); - } - if (prefix.length() < 3) { - cerr << endl - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " Apple recommends they should be at least 3 characters long." - << endl; - cerr.flush(); - } - } - // Load any expected package prefixes to validate against those. map<string, string> expected_package_prefixes; - string expect_file_path; - if (!LoadExpectedPackagePrefixes(&expected_package_prefixes, - &expect_file_path, out_error)) { + if (!LoadExpectedPackagePrefixes(generation_options, + &expected_package_prefixes, + out_error)) { return false; } - // If there are no expected prefixes, out of here. - if (expected_package_prefixes.size() == 0) { - return true; - } - - // Second Check: Error - See if there was an expected prefix for the package - // and report if it doesn't match. + // Check: Error - See if there was an expected prefix for the package and + // report if it doesn't match (wrong or missing). map<string, string>::iterator package_match = expected_package_prefixes.find(package); if (package_match != expected_package_prefixes.end()) { @@ -981,8 +1013,9 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { return true; } else { // ...it didn't match! - *out_error = "protoc:0: error: Expected 'option objc_class_prefix = \"" + - package_match->second + "\";' in '" + file->name() + "'"; + *out_error = "error: Expected 'option objc_class_prefix = \"" + + package_match->second + "\";' for package '" + package + + "' in '" + file->name() + "'"; if (prefix.length()) { *out_error += "; but found '" + prefix + "' instead"; } @@ -991,32 +1024,57 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) { } } - // Third Check: Error - If there was a prefix make sure it wasn't expected - // for a different package instead (overlap is allowed, but it has to be - // listed as an expected overlap). - if (prefix.length()) { - for (map<string, string>::iterator i = expected_package_prefixes.begin(); - i != expected_package_prefixes.end(); ++i) { - if (i->second == prefix) { - *out_error = - "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix + - "\";' in '" + file->name() + - "'; that prefix is already used for 'package " + i->first + - ";'. It can only be reused by listing it in the expected file (" + - expect_file_path + ")."; - return false; // Only report first usage of the prefix. - } + // If there was no prefix option, we're done at this point. + if (prefix.length() == 0) { + // No prefix, nothing left to check. + return true; + } + + // Check: Error - Make sure the prefix wasn't expected for a different + // package (overlap is allowed, but it has to be listed as an expected + // overlap). + for (map<string, string>::iterator i = expected_package_prefixes.begin(); + i != expected_package_prefixes.end(); ++i) { + if (i->second == prefix) { + *out_error = + "error: Found 'option objc_class_prefix = \"" + prefix + + "\";' in '" + file->name() + + "'; that prefix is already used for 'package " + i->first + + ";'. It can only be reused by listing it in the expected file (" + + generation_options.expected_prefixes_path + ")."; + return false; // Only report first usage of the prefix. } } - // Fourth Check: Warning - If there was a prefix, and it wasn't expected, - // issue a warning suggesting it gets added to the file. - if (prefix.length()) { + // Check: Warning - Make sure the prefix is is a reasonable value according + // to Apple's rules (the checks above implicitly whitelist anything that + // doesn't meet these rules). + if (!ascii_isupper(prefix[0])) { + cerr << endl + << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " it should start with a capital letter." << endl; + cerr.flush(); + } + if (prefix.length() < 3) { + // Apple reserves 2 character prefixes for themselves. They do use some + // 3 character prefixes, but they haven't updated the rules/docs. + cerr << endl + << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " Apple recommends they should be at least 3 characters long." + << endl; + cerr.flush(); + } + + // Check: Warning - If the given package/prefix pair wasn't expected, issue a + // warning issue a warning suggesting it gets added to the file. + if (!expected_package_prefixes.empty()) { cerr << endl - << "protoc:0: warning: Found 'option objc_class_prefix = \"" << prefix - << "\";' in '" << file->name() << "';" - << " should you add it to the expected prefixes file (" - << expect_file_path << ")?" << endl; + << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " consider adding it to the expected prefixes file (" + << generation_options.expected_prefixes_path << ")." << endl; cerr.flush(); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 072a2e57..3f56d94b 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -42,6 +42,15 @@ namespace protobuf { namespace compiler { namespace objectivec { +// Generator options (see objectivec_generator.cc for a description of each): +struct Options { + 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); @@ -64,7 +73,7 @@ string FilePath(const FileDescriptor* file); // Gets the name of the root class we'll generate in the file. This class // is not meant for external consumption, but instead contains helpers that -// the rest of the the classes need +// the rest of the classes need string FileClassName(const FileDescriptor* file); // These return the fully-qualified class name corresponding to the given @@ -124,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); @@ -137,18 +162,22 @@ 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); +// Builds a HeaderDoc style comment out of the comments in the .proto file. string BuildCommentsString(const SourceLocation& location); // Checks the prefix for a given file and outputs any warnings needed, if // there are flat out errors, then out_error is filled in and the result is // false. -bool ValidateObjCClassPrefix(const FileDescriptor* file, string *out_error); +bool ValidateObjCClassPrefix(const FileDescriptor* file, + const Options& generation_options, + string* out_error); // Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform -// the input into the the expected output. +// the input into the expected output. class LIBPROTOC_EXPORT TextFormatDecodeData { public: TextFormatDecodeData() {} diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index 2987f3db..ac5d8aea 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -84,13 +84,14 @@ const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { } // namespace -MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : RepeatedFieldGenerator(descriptor, options) { const FieldDescriptor* key_descriptor = descriptor->message_type()->FindFieldByName("key"); const FieldDescriptor* value_descriptor = descriptor->message_type()->FindFieldByName("value"); - value_field_generator_.reset(FieldGenerator::Make(value_descriptor)); + value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options)); // Pull over some variables_ from the value. variables_["field_type"] = value_field_generator_->variable("field_type"); @@ -117,46 +118,62 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) variables_["fieldflags"] = BuildFlagsString(field_flags); ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); - if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + const bool value_is_object_type = ((value_objc_type == OBJECTIVECTYPE_STRING) || (value_objc_type == OBJECTIVECTYPE_DATA) || - (value_objc_type == OBJECTIVECTYPE_MESSAGE))) { + (value_objc_type == OBJECTIVECTYPE_MESSAGE)); + if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + value_is_object_type) { variables_["array_storage_type"] = "NSMutableDictionary"; + variables_["array_property_type"] = + "NSMutableDictionary<NSString*, " + + value_field_generator_->variable("storage_type") + "*>"; } else { - string base_name = MapEntryTypeName(key_descriptor, true); - base_name += MapEntryTypeName(value_descriptor, false); - base_name += "Dictionary"; - variables_["array_storage_type"] = "GPB" + base_name; + string class_name("GPB"); + class_name += MapEntryTypeName(key_descriptor, true); + class_name += MapEntryTypeName(value_descriptor, false); + class_name += "Dictionary"; + variables_["array_storage_type"] = class_name; + if (value_is_object_type) { + variables_["array_property_type"] = + class_name + "<" + + 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"); - ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); - if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) || - (value_objc_type == OBJECTIVECTYPE_DATA) || - (value_objc_type == OBJECTIVECTYPE_STRING) || - (value_objc_type == OBJECTIVECTYPE_ENUM)) { + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) { variables_["array_comment"] = "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; - } else { - variables_["array_comment"] = ""; } } -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); + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + const string& value_storage_type = + value_field_generator_->variable("storage_type"); + fwd_decls->insert("@class " + value_storage_type); + } } + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index 173541f2..bc68a682 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -41,18 +41,21 @@ namespace compiler { namespace objectivec { class MapFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); public: virtual void FinishInitialization(void); - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: - explicit MapFieldGenerator(const FieldDescriptor* descriptor); + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); virtual ~MapFieldGenerator(); + virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + private: scoped_ptr<FieldGenerator> value_field_generator_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); }; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 32671d42..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 @@ -174,10 +175,11 @@ const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { } // namespace MessageGenerator::MessageGenerator(const string& root_classname, - const Descriptor* descriptor) + const Descriptor* descriptor, + const Options& options) : root_classname_(root_classname), descriptor_(descriptor), - field_generators_(descriptor), + field_generators_(descriptor, options), class_name_(ClassName(descriptor_)) { for (int i = 0; i < descriptor_->extension_count(); i++) { extension_generators_.push_back( @@ -196,7 +198,9 @@ MessageGenerator::MessageGenerator(const string& root_classname, for (int i = 0; i < descriptor_->nested_type_count(); i++) { MessageGenerator* generator = - new MessageGenerator(root_classname_, descriptor_->nested_type(i)); + new MessageGenerator(root_classname_, + descriptor_->nested_type(i), + options); nested_message_generators_.push_back(generator); } } @@ -230,11 +234,6 @@ void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) { if (!IsMapEntryMessage(descriptor_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* fieldDescriptor = descriptor_->field(i); - // If it is a the field is repeated, the type will be and *Array, and we - // don't need any forward decl. - if (fieldDescriptor->is_repeated()) { - continue; - } field_generators_.get(fieldDescriptor) .DetermineForwardDeclarations(fwd_decls); } @@ -322,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); @@ -406,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( @@ -458,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(), @@ -512,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_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h index 06b536ff..8565e76f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h @@ -54,7 +54,9 @@ class EnumGenerator; class MessageGenerator { public: - MessageGenerator(const string& root_classname, const Descriptor* descriptor); + MessageGenerator(const string& root_classname, + const Descriptor* descriptor, + const Options& options); ~MessageGenerator(); void GenerateStaticVariablesInitialization(io::Printer* printer); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc index f2ce4e5b..d6ccd6d1 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -58,8 +58,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } // namespace -MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) - : ObjCObjFieldGenerator(descriptor) { +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { SetMessageVariables(descriptor, &variables_); } @@ -67,6 +68,7 @@ MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator::DetermineForwardDeclarations( set<string>* fwd_decls) const { + ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls); // Class name is already in "storage_type". fwd_decls->insert("@class " + variable("storage_type")); } @@ -82,14 +84,24 @@ bool MessageFieldGenerator::WantsHasProperty(void) const { } RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetMessageVariables(descriptor, &variables_); variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} +void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( + set<string>* fwd_decls) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); +} + + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h index 708ea566..d2dba153 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h @@ -41,10 +41,12 @@ namespace compiler { namespace objectivec { class MessageFieldGenerator : public ObjCObjFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor); + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~MessageFieldGenerator(); virtual bool WantsHasProperty(void) const; @@ -56,12 +58,17 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator { }; class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedMessageFieldGenerator(); + public: + virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); }; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc index 3cb87482..44bafd7f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -104,6 +104,7 @@ void OneofGenerator::GeneratePublicCasePropertyDeclaration( void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { printer->Print( variables_, + "/// Clears whatever value was set for the oneof '$name$'.\n" "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); } @@ -119,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 c185b66d..d49350f4 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -74,7 +74,7 @@ const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "int32_t"; case OBJECTIVECTYPE_MESSAGE: - return NULL; + return NULL; // Messages go through objectivec_message_field.cc|h. } // Some compilers report reaching end of function even though all cases of @@ -107,7 +107,8 @@ const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "Enum"; case OBJECTIVECTYPE_MESSAGE: - return ""; // Want NSArray + // Want NSArray (but goes through objectivec_message_field.cc|h). + return ""; } // Some compilers report reaching end of function even though all cases of @@ -126,16 +127,42 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, } // namespace PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor* descriptor) - : SingleFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : SingleFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); } 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) - : ObjCObjFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : ObjCObjFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); variables_["property_storage_attribute"] = "copy"; } @@ -143,8 +170,8 @@ PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {} RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor* descriptor) - : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* descriptor, const Options& options) + : RepeatedFieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_); string base_name = PrimitiveArrayTypeName(descriptor); @@ -152,19 +179,13 @@ RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( variables_["array_storage_type"] = "GPB" + base_name + "Array"; } else { variables_["array_storage_type"] = "NSMutableArray"; + variables_["array_property_type"] = + "NSMutableArray<" + variables_["storage_type"] + "*>"; } } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} -void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) { - RepeatedFieldGenerator::FinishInitialization(); - if (IsPrimitiveType(descriptor_)) { - // No comment needed for primitive types. - variables_["array_comment"] = ""; - } -} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h index 9bb79343..69bb1fdd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -41,21 +41,30 @@ namespace compiler { namespace objectivec { class PrimitiveFieldGenerator : public SingleFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + 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); }; class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor); + PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~PrimitiveObjFieldGenerator(); private: @@ -63,12 +72,13 @@ class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { }; class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator { - friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, + const Options& options); protected: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); virtual ~RepeatedPrimitiveFieldGenerator(); - virtual void FinishInitialization(void); private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index a389a4fc..90ded4de 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -458,6 +458,61 @@ void Parser::SkipRestOfBlock() { // =================================================================== +bool Parser::ValidateEnum(const EnumDescriptorProto* proto) { + bool has_allow_alias = false; + bool allow_alias = false; + + for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) { + const UninterpretedOption option = proto->options().uninterpreted_option(i); + if (option.name_size() > 1) { + continue; + } + if (!option.name(0).is_extension() && + option.name(0).name_part() == "allow_alias") { + has_allow_alias = true; + if (option.identifier_value() == "true") { + allow_alias = true; + } + break; + } + } + + if (has_allow_alias && !allow_alias) { + string error = + "\"" + proto->name() + + "\" declares 'option allow_alias = false;' which has no effect. " + "Please remove the declaration."; + // This needlessly clutters declarations with nops. + AddError(error); + return false; + } + + set<int> used_values; + bool has_duplicates = false; + for (int i = 0; i < proto->value_size(); ++i) { + const EnumValueDescriptorProto enum_value = proto->value(i); + if (used_values.find(enum_value.number()) != used_values.end()) { + has_duplicates = true; + break; + } else { + used_values.insert(enum_value.number()); + } + } + if (allow_alias && !has_duplicates) { + string error = + "\"" + proto->name() + + "\" declares support for enum aliases but no enum values share field " + "numbers. Please remove the unnecessary 'option allow_alias = true;' " + "declaration."; + // Generate an error if an enum declares support for duplicate enum values + // and does not use it protect future authors. + AddError(error); + return false; + } + + return true; +} + bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { input_ = input; had_errors_ = false; @@ -489,9 +544,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { // Store the syntax into the file. if (file != NULL) file->set_syntax(syntax_identifier_); } else if (!stop_after_syntax_identifier_) { - GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. " - << "Please use 'syntax = \"proto2\";' or " - << "'syntax = \"proto3\";' to specify a syntax " + GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: " + << file->name() << ". Please use 'syntax = \"proto2\";' " + << "or 'syntax = \"proto3\";' to specify a syntax " << "version. (Defaulted to proto2 syntax.)"; syntax_identifier_ = "proto2"; } @@ -1627,6 +1682,9 @@ bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type, } DO(ParseEnumBlock(enum_type, enum_location, containing_file)); + + DO(ValidateEnum(enum_type)); + return true; } diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 3ba1e170..2c561c23 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -498,6 +498,8 @@ class LIBPROTOBUF_EXPORT Parser { } + bool ValidateEnum(const EnumDescriptorProto* proto); + // ================================================================= io::Tokenizer* input_; diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 0d729e0b..1d623dd9 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -1170,6 +1170,29 @@ TEST_F(ParseErrorTest, EnumValueOutOfRange) { "4:19: Integer out of range.\n"); } +TEST_F(ParseErrorTest, EnumAllowAliasFalse) { + ExpectHasErrors( + "enum Foo {\n" + " option allow_alias = false;\n" + " BAR = 1;\n" + " BAZ = 2;\n" + "}\n", + "5:0: \"Foo\" declares 'option allow_alias = false;' which has no effect. " + "Please remove the declaration.\n"); +} + +TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) { + ExpectHasErrors( + "enum Foo {\n" + " option allow_alias = true;\n" + " BAR = 1;\n" + " BAZ = 2;\n" + "}\n", + "5:0: \"Foo\" declares support for enum aliases but no enum values share " + "field numbers. Please remove the unnecessary 'option allow_alias = true;' " + "declaration.\n"); +} + TEST_F(ParseErrorTest, DefaultValueMissing) { ExpectHasErrors( "message TestMessage {\n" @@ -1839,6 +1862,8 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { "// Detached comment before TestMessage1.\n" "\n" "// Message comment.\n" + "//\n" + "// More detail in message comment.\n" "message TestMessage1 {\n" "\n" " // Detached comment before foo.\n" @@ -1890,11 +1915,6 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { pool_.BuildFileCollectingErrors(parsed_desc, &collector); ASSERT_TRUE(descriptor != NULL); - DebugStringOptions debug_string_options; - debug_string_options.include_comments = true; - const string debug_string = - descriptor->DebugStringWithOptions(debug_string_options); - // Ensure that each of the comments appears somewhere in the DebugString(). // We don't test the exact comment placement or formatting, because we do not // want to be too fragile here. @@ -1905,6 +1925,7 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { "Package comment.", "Detached comment before TestMessage1.", "Message comment.", + "More detail in message comment.", "Detached comment before foo.", "Field comment", "Detached comment before NestedMessage.", @@ -1919,11 +1940,28 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { "RPC comment", }; - for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) { - string::size_type found_pos = debug_string.find(expected_comments[i]); - EXPECT_TRUE(found_pos != string::npos) - << "\"" << expected_comments[i] << "\" not found."; + DebugStringOptions debug_string_options; + debug_string_options.include_comments = true; + + { + const string debug_string = + descriptor->DebugStringWithOptions(debug_string_options); + + for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) { + string::size_type found_pos = debug_string.find(expected_comments[i]); + EXPECT_TRUE(found_pos != string::npos) + << "\"" << expected_comments[i] << "\" not found."; + } + + // Result of DebugStringWithOptions should be parseable. + SetupParser(debug_string.c_str()); + FileDescriptorProto parsed; + parser_->Parse(input_.get(), &parsed); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_) + << "Failed to parse:\n" << debug_string; } + } TEST_F(ParseDescriptorDebugTest, TestMaps) { 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 0792d875..e9d50a1d 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/compiler/plugin.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/compiler/plugin.pb.h" +#include <google/protobuf/compiler/plugin.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -172,11 +173,11 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorRequest::kFileToGenerateFieldNumber; const int CodeGeneratorRequest::kParameterFieldNumber; const int CodeGeneratorRequest::kProtoFileFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 CodeGeneratorRequest::CodeGeneratorRequest() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -239,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()); } @@ -252,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 (;;) { @@ -411,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; @@ -447,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_); @@ -474,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); @@ -544,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) { @@ -609,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()); } @@ -656,11 +667,11 @@ CodeGeneratorRequest::proto_file() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorResponse_File::kNameFieldNumber; const int CodeGeneratorResponse_File::kInsertionPointFieldNumber; const int CodeGeneratorResponse_File::kContentFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 CodeGeneratorResponse_File::CodeGeneratorResponse_File() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -727,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()); @@ -746,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 (;;) { @@ -911,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) { @@ -948,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()) { @@ -981,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); @@ -1021,10 +1040,10 @@ void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) // ------------------------------------------------------------------- -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorResponse::kErrorFieldNumber; const int CodeGeneratorResponse::kFileFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 CodeGeneratorResponse::CodeGeneratorResponse() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1087,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()); } @@ -1099,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 (;;) { @@ -1218,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; @@ -1247,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))) { @@ -1273,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); @@ -1352,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()); } @@ -1405,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()); } @@ -1458,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()); } @@ -1515,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 ab79bdae..510202f0 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -27,7 +27,7 @@ #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/unknown_field_set.h> -#include "google/protobuf/descriptor.pb.h" +#include <google/protobuf/descriptor.pb.h> // @@protoc_insertion_point(includes) namespace google { @@ -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/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc index 9692f1bf..92c76fb0 100644 --- a/src/google/protobuf/compiler/ruby/ruby_generator.cc +++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc @@ -75,6 +75,10 @@ std::string StripDotProto(const std::string& proto_file) { return proto_file.substr(0, lastindex); } +std::string GetOutputFilename(const std::string& proto_file) { + return StripDotProto(proto_file) + ".rb"; +} + std::string LabelForField(const google::protobuf::FieldDescriptor* field) { switch (field->label()) { case FieldDescriptor::LABEL_OPTIONAL: return "optional"; @@ -331,8 +335,69 @@ void EndPackageModules( } } -void GenerateFile(const google::protobuf::FileDescriptor* file, - google::protobuf::io::Printer* printer) { +bool UsesTypeFromFile(const Descriptor* message, const FileDescriptor* file, + string* error) { + for (int i = 0; i < message->field_count(); i++) { + const FieldDescriptor* field = message->field(i); + if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + field->message_type()->file() == file) || + (field->type() == FieldDescriptor::TYPE_ENUM && + field->enum_type()->file() == file)) { + *error = "proto3 message field " + field->full_name() + " in file " + + file->name() + " has a dependency on a type from proto2 file " + + file->name() + + ". Ruby doesn't support proto2 yet, so we must fail."; + return true; + } + } + + for (int i = 0; i < message->nested_type_count(); i++) { + if (UsesTypeFromFile(message->nested_type(i), file, error)) { + return true; + } + } + + return false; +} + +// Ruby doesn't currently support proto2. This causes a failure even for proto3 +// files that import proto2. But in some cases, the proto2 file is only being +// imported to extend another proto2 message. The prime example is declaring +// custom options by extending FileOptions/FieldOptions/etc. +// +// If the proto3 messages don't have any proto2 submessages, it is safe to omit +// the dependency completely. Users won't be able to use any proto2 extensions, +// but they already couldn't because proto2 messages aren't supported. +// +// If/when we add proto2 support, we should remove this. +bool MaybeEmitDependency(const FileDescriptor* import, + const FileDescriptor* from, + io::Printer* printer, + string* error) { + if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) { + for (int i = 0; i < from->message_type_count(); i++) { + if (UsesTypeFromFile(from->message_type(i), import, error)) { + // Error text was already set by UsesTypeFromFile(). + return false; + } + } + + // Ok to omit this proto2 dependency -- so we won't print anything. + GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() + << "' from proto3 output file '" + << GetOutputFilename(from->name()) + << "' because we don't support proto2 and no proto2 " + "types from that file are being used."; + return true; + } else { + printer->Print( + "require '$name$'\n", "name", StripDotProto(import->name())); + return true; + } +} + +bool GenerateFile(const FileDescriptor* file, io::Printer* printer, + string* error) { printer->Print( "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" "# source: $filename$\n" @@ -343,9 +408,9 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, "require 'google/protobuf'\n\n"); for (int i = 0; i < file->dependency_count(); i++) { - const std::string& name = file->dependency(i)->name(); - printer->Print( - "require '$name$'\n", "name", StripDotProto(name)); + if (!MaybeEmitDependency(file->dependency(i), file, printer, error)) { + return false; + } } printer->Print( @@ -369,6 +434,7 @@ void GenerateFile(const google::protobuf::FileDescriptor* file, GenerateEnumAssignment("", file->enum_type(i), printer); } EndPackageModules(levels, printer); + return true; } bool Generator::Generate( @@ -384,15 +450,11 @@ bool Generator::Generate( return false; } - std::string filename = - StripDotProto(file->name()) + ".rb"; scoped_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(filename)); + generator_context->Open(GetOutputFilename(file->name()))); io::Printer printer(output.get(), '$'); - GenerateFile(file, &printer); - - return true; + return GenerateFile(file, &printer, error); } } // namespace ruby diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index 85429924..6e258664 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -47,6 +47,7 @@ #include <google/protobuf/message.h> #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -360,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 b40fe95a..56e11fa9 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -156,7 +156,7 @@ const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) { static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty"; -#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them. +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FieldDescriptor::kMaxNumber; const int FieldDescriptor::kFirstReservedNumber; const int FieldDescriptor::kLastReservedNumber; @@ -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); } @@ -560,7 +567,7 @@ class FileDescriptorTables { ~FileDescriptorTables(); // Empty table, used with placeholder files. - static const FileDescriptorTables kEmpty; + inline static const FileDescriptorTables& GetEmptyInstance(); // ----------------------------------------------------------------- // Finding items. @@ -665,7 +672,32 @@ FileDescriptorTables::FileDescriptorTables() FileDescriptorTables::~FileDescriptorTables() {} -const FileDescriptorTables FileDescriptorTables::kEmpty; +namespace { + +FileDescriptorTables* file_descriptor_tables_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_); + +void DeleteFileDescriptorTables() { + delete file_descriptor_tables_; + file_descriptor_tables_ = NULL; +} + +void InitFileDescriptorTables() { + file_descriptor_tables_ = new FileDescriptorTables(); + internal::OnShutdown(&DeleteFileDescriptorTables); +} + +inline void InitFileDescriptorTablesOnce() { + ::google::protobuf::GoogleOnceInit( + &file_descriptor_tables_once_init_, &InitFileDescriptorTables); +} + +} // anonymous namespace + +inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() { + InitFileDescriptorTablesOnce(); + return *file_descriptor_tables_; +} void DescriptorPool::Tables::AddCheckpoint() { checkpoints_.push_back(CheckPoint(this)); @@ -2050,6 +2082,7 @@ class SourceLocationCommentPrinter { } private: + bool have_source_loc_; SourceLocation source_loc_; DebugStringOptions options_; @@ -2740,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_; @@ -2951,7 +2987,8 @@ class DescriptorBuilder { const ServiceDescriptor* parent, MethodDescriptor* result); - void LogUnusedDependency(const FileDescriptor* result); + void LogUnusedDependency(const FileDescriptorProto& proto, + const FileDescriptor* result); // Must be run only after building. // @@ -3535,7 +3572,7 @@ FileDescriptor* DescriptorBuilder::NewPlaceholderFile( placeholder->package_ = &internal::GetEmptyString(); placeholder->pool_ = pool_; placeholder->options_ = &FileOptions::default_instance(); - placeholder->tables_ = &FileDescriptorTables::kEmpty; + placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance(); placeholder->source_code_info_ = &SourceCodeInfo::default_instance(); placeholder->is_placeholder_ = true; placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2; @@ -3807,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(); @@ -3996,7 +4037,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile( if (!unused_dependency_.empty()) { - LogUnusedDependency(result); + LogUnusedDependency(proto, result); } if (had_errors_) { @@ -4143,6 +4184,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, } } + void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, const Descriptor* parent, FieldDescriptor* result, @@ -4248,8 +4290,8 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, } else if (proto.default_value() == "nan") { result->default_value_float_ = numeric_limits<float>::quiet_NaN(); } else { - result->default_value_float_ = - io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + result->default_value_float_ = io::SafeDoubleToFloat( + io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos)); } break; case FieldDescriptor::CPPTYPE_DOUBLE: @@ -4421,6 +4463,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, AllocateOptions(proto.options(), result); } + AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result)); } @@ -5084,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) { @@ -5533,11 +5571,19 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions( // UnknownFieldSet and wait there until the message is parsed by something // that does know about the options. string buf; - options->AppendToString(&buf); - GOOGLE_CHECK(options->ParseFromString(buf)) + GOOGLE_CHECK(options->AppendPartialToString(&buf)) + << "Protocol message could not be serialized."; + GOOGLE_CHECK(options->ParsePartialFromString(buf)) << "Protocol message serialized itself in invalid fashion."; + if (!options->IsInitialized()) { + builder_->AddWarning( + options_to_interpret->element_name, *original_options, + DescriptorPool::ErrorCollector::OTHER, + "Options could not be fully parsed using the proto descriptors " + "compiled into this binary. Missing required fields: " + + options->InitializationErrorString()); + } } - return !failed; } @@ -6191,7 +6237,8 @@ void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value, } } -void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) { +void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto, + const FileDescriptor* result) { if (!unused_dependency_.empty()) { std::set<string> annotation_extensions; @@ -6217,9 +6264,9 @@ void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) { } // Log warnings for unused imported files. if (i == (*it)->extension_count()) { - GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name() - << "\" imports \"" << (*it)->name() - << "\" which is not used."; + string error_message = "Import " + (*it)->name() + " but not used."; + AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::OTHER, + error_message); } } } diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index e7e8c6af..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; @@ -1645,7 +1671,7 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range, const Descriptor::ReservedRange*) PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int) -PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions); +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions) PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) @@ -1690,7 +1716,7 @@ PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*) PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int) PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value, const EnumValueDescriptor*) -PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions); +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions) PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool) PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name) @@ -1705,14 +1731,14 @@ PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*) PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int) PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method, const MethodDescriptor*) -PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions); +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions) PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name) PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*) -PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions); +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool) @@ -1726,7 +1752,7 @@ PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int) PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int) PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int) PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int) -PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions); +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions) PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool) PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*) diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 9c817122..4d5c4d99 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/descriptor.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/descriptor.pb.h" +#include <google/protobuf/descriptor.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -92,6 +93,12 @@ const ::google::protobuf::internal::GeneratedMessageReflection* const ::google::protobuf::Descriptor* SourceCodeInfo_Location_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* SourceCodeInfo_Location_reflection_ = NULL; +const ::google::protobuf::Descriptor* GeneratedCodeInfo_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + GeneratedCodeInfo_reflection_ = NULL; +const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + GeneratedCodeInfo_Annotation_reflection_ = NULL; } // namespace @@ -312,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_), @@ -327,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_ = @@ -520,6 +526,39 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { sizeof(SourceCodeInfo_Location), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_), -1); + GeneratedCodeInfo_descriptor_ = file->message_type(18); + static const int GeneratedCodeInfo_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, annotation_), + }; + GeneratedCodeInfo_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + GeneratedCodeInfo_descriptor_, + GeneratedCodeInfo::default_instance_, + GeneratedCodeInfo_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _has_bits_[0]), + -1, + -1, + sizeof(GeneratedCodeInfo), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _internal_metadata_), + -1); + GeneratedCodeInfo_Annotation_descriptor_ = GeneratedCodeInfo_descriptor_->nested_type(0); + static const int GeneratedCodeInfo_Annotation_offsets_[4] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, path_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, source_file_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, begin_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, end_), + }; + GeneratedCodeInfo_Annotation_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + GeneratedCodeInfo_Annotation_descriptor_, + GeneratedCodeInfo_Annotation::default_instance_, + GeneratedCodeInfo_Annotation_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _has_bits_[0]), + -1, + -1, + sizeof(GeneratedCodeInfo_Annotation), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _internal_metadata_), + -1); } namespace { @@ -576,6 +615,10 @@ void protobuf_RegisterTypes(const ::std::string&) { SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + GeneratedCodeInfo_descriptor_, &GeneratedCodeInfo::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + GeneratedCodeInfo_Annotation_descriptor_, &GeneratedCodeInfo_Annotation::default_instance()); } } // namespace @@ -625,6 +668,10 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() { delete SourceCodeInfo_reflection_; delete SourceCodeInfo_Location::default_instance_; delete SourceCodeInfo_Location_reflection_; + delete GeneratedCodeInfo::default_instance_; + delete GeneratedCodeInfo_reflection_; + delete GeneratedCodeInfo_Annotation::default_instance_; + delete GeneratedCodeInfo_Annotation_reflection_; } void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { @@ -698,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\"\252\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" @@ -710,56 +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(\010\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" - "SPEED\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\002\"\346\001\n\016MessageOptions\022&\n\027messag" - "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" - "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031" - "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007" - " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + " \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\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g" - "oogle.protobuf.FieldOptions.CType:\006STRIN" - "G\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$.goog" - "le.protobuf.FieldOptions.JSType:\tJS_NORM" - "AL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecated\030\003 " - "\001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\"/\n\005CType\022\n\n\006STRING\020" - "\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JSType\022" - "\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_NUMB" - "ER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow" - "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" - "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." - "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\ndeprecated\030!" + "\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\"z\n\rMethodOptions\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\"\236\002\n\023UninterpretedOption\022" - ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp" - "retedOption.NamePart\022\030\n\020identifier_value" - "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne" - "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006" - " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_" - "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\016SourceCodeI" - "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf." - "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004" - "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead" - "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030" - "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t" - "BX\n\023com.google.protobufB\020DescriptorProto" - "sH\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf." - "Reflection", 5010); + "*\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(); @@ -784,6 +834,8 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart(); SourceCodeInfo::default_instance_ = new SourceCodeInfo(); SourceCodeInfo_Location::default_instance_ = new SourceCodeInfo_Location(); + GeneratedCodeInfo::default_instance_ = new GeneratedCodeInfo(); + GeneratedCodeInfo_Annotation::default_instance_ = new GeneratedCodeInfo_Annotation(); FileDescriptorSet::default_instance_->InitAsDefaultInstance(); FileDescriptorProto::default_instance_->InitAsDefaultInstance(); DescriptorProto::default_instance_->InitAsDefaultInstance(); @@ -806,6 +858,8 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance(); SourceCodeInfo::default_instance_->InitAsDefaultInstance(); SourceCodeInfo_Location::default_instance_->InitAsDefaultInstance(); + GeneratedCodeInfo::default_instance_->InitAsDefaultInstance(); + GeneratedCodeInfo_Annotation::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto); } @@ -828,9 +882,9 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FileDescriptorSet::kFileFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FileDescriptorSet::FileDescriptorSet() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -890,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()) { @@ -899,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 (;;) { @@ -980,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; @@ -1002,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()) { @@ -1022,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); @@ -1095,7 +1157,7 @@ FileDescriptorSet::file() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FileDescriptorProto::kNameFieldNumber; const int FileDescriptorProto::kPackageFieldNumber; const int FileDescriptorProto::kDependencyFieldNumber; @@ -1108,7 +1170,7 @@ const int FileDescriptorProto::kExtensionFieldNumber; const int FileDescriptorProto::kOptionsFieldNumber; const int FileDescriptorProto::kSourceCodeInfoFieldNumber; const int FileDescriptorProto::kSyntaxFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FileDescriptorProto::FileDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1181,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()); @@ -1215,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 (;;) { @@ -1650,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) { @@ -1762,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_); @@ -1810,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); @@ -1906,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()); } @@ -1959,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()); } @@ -2001,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) { @@ -2233,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; @@ -2276,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; @@ -2332,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()); } @@ -2349,10 +2425,10 @@ void FileDescriptorProto::clear_syntax() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int DescriptorProto_ExtensionRange::kStartFieldNumber; const int DescriptorProto_ExtensionRange::kEndFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2414,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,\ @@ -2435,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 (;;) { @@ -2536,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) { @@ -2566,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()) { @@ -2593,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); @@ -2632,10 +2724,10 @@ void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange // ------------------------------------------------------------------- -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int DescriptorProto_ReservedRange::kStartFieldNumber; const int DescriptorProto_ReservedRange::kEndFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 DescriptorProto_ReservedRange::DescriptorProto_ReservedRange() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2697,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,\ @@ -2718,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 (;;) { @@ -2819,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) { @@ -2849,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()) { @@ -2876,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); @@ -2915,7 +3023,7 @@ void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* // ------------------------------------------------------------------- -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int DescriptorProto::kNameFieldNumber; const int DescriptorProto::kFieldFieldNumber; const int DescriptorProto::kExtensionFieldNumber; @@ -2926,7 +3034,7 @@ const int DescriptorProto::kOneofDeclFieldNumber; const int DescriptorProto::kOptionsFieldNumber; const int DescriptorProto::kReservedRangeFieldNumber; const int DescriptorProto::kReservedNameFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 DescriptorProto::DescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2992,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()); @@ -3016,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 (;;) { @@ -3375,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) { @@ -3468,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_); @@ -3504,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); @@ -3702,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()); } @@ -3922,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; @@ -3997,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) { @@ -4056,7 +4175,7 @@ bool FieldDescriptorProto_Type_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE; const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT; const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64; @@ -4078,7 +4197,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; const int FieldDescriptorProto::Type_ARRAYSIZE; -#endif // _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_Label_descriptor_; @@ -4094,15 +4213,15 @@ bool FieldDescriptorProto_Label_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL; const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; const int FieldDescriptorProto::Label_ARRAYSIZE; -#endif // _MSC_VER -#ifndef _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FieldDescriptorProto::kNameFieldNumber; const int FieldDescriptorProto::kNumberFieldNumber; const int FieldDescriptorProto::kLabelFieldNumber; @@ -4113,7 +4232,7 @@ const int FieldDescriptorProto::kDefaultValueFieldNumber; const int FieldDescriptorProto::kOneofIndexFieldNumber; const int FieldDescriptorProto::kJsonNameFieldNumber; const int FieldDescriptorProto::kOptionsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FieldDescriptorProto::FieldDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -4191,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()); @@ -4225,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 (;;) { @@ -4606,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) { @@ -4692,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()) { @@ -4750,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); @@ -4840,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()); } @@ -4967,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()); } @@ -5020,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()); } @@ -5073,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()); } @@ -5150,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()); } @@ -5190,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; @@ -5210,9 +5343,9 @@ void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOption // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int OneofDescriptorProto::kNameFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 OneofDescriptorProto::OneofDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -5275,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()); } @@ -5286,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 (;;) { @@ -5375,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; @@ -5396,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()) { @@ -5421,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); @@ -5499,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()); } @@ -5516,11 +5658,11 @@ void OneofDescriptorProto::clear_name() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int EnumDescriptorProto::kNameFieldNumber; const int EnumDescriptorProto::kValueFieldNumber; const int EnumDescriptorProto::kOptionsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 EnumDescriptorProto::EnumDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -5586,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()); @@ -5603,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 (;;) { @@ -5748,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) { @@ -5786,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))) { @@ -5815,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); @@ -5899,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()); } @@ -5969,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; @@ -5989,11 +6141,11 @@ void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int EnumValueDescriptorProto::kNameFieldNumber; const int EnumValueDescriptorProto::kNumberFieldNumber; const int EnumValueDescriptorProto::kOptionsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 EnumValueDescriptorProto::EnumValueDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -6060,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()); @@ -6077,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 (;;) { @@ -6217,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) { @@ -6254,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()) { @@ -6285,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); @@ -6368,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()); } @@ -6432,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; @@ -6452,11 +6614,11 @@ void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumVal // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int ServiceDescriptorProto::kNameFieldNumber; const int ServiceDescriptorProto::kMethodFieldNumber; const int ServiceDescriptorProto::kOptionsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 ServiceDescriptorProto::ServiceDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -6522,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()); @@ -6539,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 (;;) { @@ -6684,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) { @@ -6722,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))) { @@ -6751,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); @@ -6835,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()); } @@ -6905,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; @@ -6925,14 +7097,14 @@ void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOp // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int MethodDescriptorProto::kNameFieldNumber; const int MethodDescriptorProto::kInputTypeFieldNumber; const int MethodDescriptorProto::kOutputTypeFieldNumber; const int MethodDescriptorProto::kOptionsFieldNumber; const int MethodDescriptorProto::kClientStreamingFieldNumber; const int MethodDescriptorProto::kServerStreamingFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 MethodDescriptorProto::MethodDescriptorProto() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -7004,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,\ @@ -7039,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 (;;) { @@ -7280,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) { @@ -7334,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()) { @@ -7376,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); @@ -7462,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()); } @@ -7515,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()); } @@ -7568,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()); } @@ -7608,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; @@ -7691,15 +7883,15 @@ bool FileOptions_OptimizeMode_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const FileOptions_OptimizeMode FileOptions::SPEED; const FileOptions_OptimizeMode FileOptions::CODE_SIZE; const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; const int FileOptions::OptimizeMode_ARRAYSIZE; -#endif // _MSC_VER -#ifndef _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FileOptions::kJavaPackageFieldNumber; const int FileOptions::kJavaOuterClassnameFieldNumber; const int FileOptions::kJavaMultipleFilesFieldNumber; @@ -7714,9 +7906,8 @@ 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 // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FileOptions::FileOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -7752,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_)); } @@ -7797,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,\ @@ -7819,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()); } @@ -7841,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 (;;) { @@ -8069,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; - 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; } @@ -8231,11 +8415,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), output); } - // optional bool javanano_use_deprecated_package = 38; - 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( @@ -8357,11 +8536,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), target); } - // optional bool javanano_use_deprecated_package = 38; - 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:: @@ -8382,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) { @@ -8433,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; @@ -8468,11 +8643,6 @@ int FileOptions::ByteSize() const { this->csharp_namespace()); } - // optional bool javanano_use_deprecated_package = 38; - if (has_javanano_use_deprecated_package()) { - total_size += 2 + 1; - } - } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -8496,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))) { @@ -8560,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()) { @@ -8571,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); @@ -8608,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_); @@ -8667,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()); } @@ -8720,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()); } @@ -8870,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()); } @@ -9043,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()); } @@ -9096,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()); } @@ -9109,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; -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(); @@ -9167,13 +9320,13 @@ FileOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int MessageOptions::kMessageSetWireFormatFieldNumber; const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber; const int MessageOptions::kDeprecatedFieldNumber; const int MessageOptions::kMapEntryFieldNumber; const int MessageOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 MessageOptions::MessageOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -9237,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,\ @@ -9260,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 (;;) { @@ -9454,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) { @@ -9500,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))) { @@ -9535,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); @@ -9725,14 +9894,14 @@ bool FieldOptions_CType_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const FieldOptions_CType FieldOptions::STRING; const FieldOptions_CType FieldOptions::CORD; const FieldOptions_CType FieldOptions::STRING_PIECE; const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; const int FieldOptions::CType_ARRAYSIZE; -#endif // _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() { protobuf_AssignDescriptorsOnce(); return FieldOptions_JSType_descriptor_; @@ -9748,15 +9917,15 @@ bool FieldOptions_JSType_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const FieldOptions_JSType FieldOptions::JS_NORMAL; const FieldOptions_JSType FieldOptions::JS_STRING; const FieldOptions_JSType FieldOptions::JS_NUMBER; const FieldOptions_JSType FieldOptions::JSType_MIN; const FieldOptions_JSType FieldOptions::JSType_MAX; const int FieldOptions::JSType_ARRAYSIZE; -#endif // _MSC_VER -#ifndef _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FieldOptions::kCtypeFieldNumber; const int FieldOptions::kPackedFieldNumber; const int FieldOptions::kJstypeFieldNumber; @@ -9764,7 +9933,7 @@ const int FieldOptions::kLazyFieldNumber; const int FieldOptions::kDeprecatedFieldNumber; const int FieldOptions::kWeakFieldNumber; const int FieldOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FieldOptions::FieldOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -9830,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,\ @@ -9856,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 (;;) { @@ -10114,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) { @@ -10172,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))) { @@ -10213,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); @@ -10440,11 +10625,11 @@ FieldOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int EnumOptions::kAllowAliasFieldNumber; const int EnumOptions::kDeprecatedFieldNumber; const int EnumOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 EnumOptions::EnumOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -10506,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,\ @@ -10529,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 (;;) { @@ -10673,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) { @@ -10709,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))) { @@ -10738,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); @@ -10863,10 +11064,10 @@ EnumOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int EnumValueOptions::kDeprecatedFieldNumber; const int EnumValueOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 EnumValueOptions::EnumValueOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -10927,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(); @@ -10938,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 (;;) { @@ -11057,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]; @@ -11086,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))) { @@ -11112,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); @@ -11212,10 +11421,10 @@ EnumValueOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int ServiceOptions::kDeprecatedFieldNumber; const int ServiceOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 ServiceOptions::ServiceOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -11276,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(); @@ -11287,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 (;;) { @@ -11406,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]; @@ -11435,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))) { @@ -11461,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); @@ -11561,10 +11778,10 @@ ServiceOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int MethodOptions::kDeprecatedFieldNumber; const int MethodOptions::kUninterpretedOptionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 MethodOptions::MethodOptions() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -11625,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(); @@ -11636,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 (;;) { @@ -11755,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]; @@ -11784,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))) { @@ -11810,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); @@ -11910,10 +12135,10 @@ MethodOptions::uninterpreted_option() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int UninterpretedOption_NamePart::kNamePartFieldNumber; const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 UninterpretedOption_NamePart::UninterpretedOption_NamePart() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -11977,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()); @@ -11991,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 (;;) { @@ -12105,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()) { @@ -12122,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. @@ -12148,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()) { @@ -12176,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); @@ -12216,7 +12450,7 @@ void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* ot // ------------------------------------------------------------------- -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int UninterpretedOption::kNameFieldNumber; const int UninterpretedOption::kIdentifierValueFieldNumber; const int UninterpretedOption::kPositiveIntValueFieldNumber; @@ -12224,7 +12458,7 @@ const int UninterpretedOption::kNegativeIntValueFieldNumber; const int UninterpretedOption::kDoubleValueFieldNumber; const int UninterpretedOption::kStringValueFieldNumber; const int UninterpretedOption::kAggregateValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 UninterpretedOption::UninterpretedOption() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -12294,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,\ @@ -12327,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 (;;) { @@ -12585,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) { @@ -12649,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))) { @@ -12692,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); @@ -12777,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()); } @@ -12888,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()); } @@ -13013,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()); } @@ -13066,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()); } @@ -13083,13 +13337,13 @@ void UninterpretedOption::clear_aggregate_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int SourceCodeInfo_Location::kPathFieldNumber; const int SourceCodeInfo_Location::kSpanFieldNumber; const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber; const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber; const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 SourceCodeInfo_Location::SourceCodeInfo_Location() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -13154,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()); @@ -13173,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 (;;) { @@ -13423,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) { @@ -13494,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_); @@ -13526,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); @@ -13568,9 +13830,9 @@ void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) { // ------------------------------------------------------------------- -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int SourceCodeInfo::kLocationFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 SourceCodeInfo::SourceCodeInfo() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -13630,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()) { @@ -13639,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 (;;) { @@ -13720,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; @@ -13742,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()) { @@ -13762,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); @@ -13900,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()); } @@ -13953,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()); } @@ -13995,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) { @@ -14056,6 +14329,837 @@ SourceCodeInfo::location() const { #endif // PROTOBUF_INLINE_NOT_IN_HEADERS +// =================================================================== + +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +const int GeneratedCodeInfo_Annotation::kPathFieldNumber; +const int GeneratedCodeInfo_Annotation::kSourceFileFieldNumber; +const int GeneratedCodeInfo_Annotation::kBeginFieldNumber; +const int GeneratedCodeInfo_Annotation::kEndFieldNumber; +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 + +GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo.Annotation) +} + +void GeneratedCodeInfo_Annotation::InitAsDefaultInstance() { +} + +GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation) +} + +void GeneratedCodeInfo_Annotation::SharedCtor() { + ::google::protobuf::internal::GetEmptyString(); + _cached_size_ = 0; + source_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + begin_ = 0; + end_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() { + // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation) + SharedDtor(); +} + +void GeneratedCodeInfo_Annotation::SharedDtor() { + source_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (this != default_instance_) { + } +} + +void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation::descriptor() { + protobuf_AssignDescriptorsOnce(); + return GeneratedCodeInfo_Annotation_descriptor_; +} + +const GeneratedCodeInfo_Annotation& GeneratedCodeInfo_Annotation::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + return *default_instance_; +} + +GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::default_instance_ = NULL; + +GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::New(::google::protobuf::Arena* arena) const { + GeneratedCodeInfo_Annotation* n = new GeneratedCodeInfo_Annotation; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +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,\ + ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ +} while (0) + + if (_has_bits_[0 / 32] & 14u) { + ZR_(begin_, end_); + if (has_source_file()) { + source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + } + } + +#undef ZR_HELPER_ +#undef ZR_ + + path_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } +} + +bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo.Annotation) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated int32 path = 1 [packed = true]; + case 1: { + if (tag == 10) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, this->mutable_path()))); + } else if (tag == 8) { + DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + 1, 10, input, this->mutable_path()))); + } else { + goto handle_unusual; + } + if (input->ExpectTag(18)) goto parse_source_file; + break; + } + + // optional string source_file = 2; + case 2: { + if (tag == 18) { + parse_source_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_source_file())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->source_file().data(), this->source_file().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.GeneratedCodeInfo.Annotation.source_file"); + } else { + goto handle_unusual; + } + if (input->ExpectTag(24)) goto parse_begin; + break; + } + + // optional int32 begin = 3; + case 3: { + if (tag == 24) { + parse_begin: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &begin_))); + set_has_begin(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(32)) goto parse_end; + break; + } + + // optional int32 end = 4; + case 4: { + if (tag == 32) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + set_has_end(); + } else { + goto handle_unusual; + } + if (input->ExpectAtEnd()) goto success; + break; + } + + default: { + handle_unusual: + if (tag == 0 || + ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo.Annotation) + return true; +failure: + // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo.Annotation) + return false; +#undef DO_ +} + +void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo.Annotation) + // repeated int32 path = 1 [packed = true]; + if (this->path_size() > 0) { + ::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(_path_cached_byte_size_); + } + for (int i = 0; i < this->path_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag( + this->path(i), output); + } + + // optional string source_file = 2; + if (has_source_file()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->source_file().data(), this->source_file().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.GeneratedCodeInfo.Annotation.source_file"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 2, this->source_file(), output); + } + + // optional int32 begin = 3; + if (has_begin()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->begin(), output); + } + + // optional int32 end = 4; + if (has_end()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->end(), output); + } + + if (_internal_metadata_.have_unknown_fields()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation) +} + +::google::protobuf::uint8* GeneratedCodeInfo_Annotation::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation) + // repeated int32 path = 1 [packed = true]; + if (this->path_size() > 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( + 1, + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, + target); + target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( + _path_cached_byte_size_, target); + } + for (int i = 0; i < this->path_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteInt32NoTagToArray(this->path(i), target); + } + + // optional string source_file = 2; + if (has_source_file()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->source_file().data(), this->source_file().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.GeneratedCodeInfo.Annotation.source_file"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->source_file(), target); + } + + // optional int32 begin = 3; + if (has_begin()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->begin(), target); + } + + // optional int32 end = 4; + if (has_end()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->end(), target); + } + + if (_internal_metadata_.have_unknown_fields()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation) + return target; +} + +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) { + // optional string source_file = 2; + if (has_source_file()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->source_file()); + } + + // optional int32 begin = 3; + if (has_begin()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->begin()); + } + + // optional int32 end = 4; + if (has_end()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->end()); + } + + } + // repeated int32 path = 1 [packed = true]; + { + int data_size = 0; + for (int i = 0; i < this->path_size(); i++) { + data_size += ::google::protobuf::internal::WireFormatLite:: + Int32Size(this->path(i)); + } + if (data_size > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _path_cached_byte_size_ = data_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + total_size += data_size; + } + + if (_internal_metadata_.have_unknown_fields()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +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))) { + if (from.has_source_file()) { + set_has_source_file(); + source_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_file_); + } + if (from.has_begin()) { + set_begin(from.begin()); + } + if (from.has_end()) { + set_end(from.end()); + } + } + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } +} + +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); +} + +bool GeneratedCodeInfo_Annotation::IsInitialized() const { + + return true; +} + +void GeneratedCodeInfo_Annotation::Swap(GeneratedCodeInfo_Annotation* other) { + if (other == this) return; + InternalSwap(other); +} +void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) { + path_.UnsafeArenaSwap(&other->path_); + source_file_.Swap(&other->source_file_); + std::swap(begin_, other->begin_); + std::swap(end_, other->end_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = GeneratedCodeInfo_Annotation_descriptor_; + metadata.reflection = GeneratedCodeInfo_Annotation_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +const int GeneratedCodeInfo::kAnnotationFieldNumber; +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 + +GeneratedCodeInfo::GeneratedCodeInfo() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo) +} + +void GeneratedCodeInfo::InitAsDefaultInstance() { +} + +GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo) +} + +void GeneratedCodeInfo::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +GeneratedCodeInfo::~GeneratedCodeInfo() { + // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo) + SharedDtor(); +} + +void GeneratedCodeInfo::SharedDtor() { + if (this != default_instance_) { + } +} + +void GeneratedCodeInfo::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* GeneratedCodeInfo::descriptor() { + protobuf_AssignDescriptorsOnce(); + return GeneratedCodeInfo_descriptor_; +} + +const GeneratedCodeInfo& GeneratedCodeInfo::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + return *default_instance_; +} + +GeneratedCodeInfo* GeneratedCodeInfo::default_instance_ = NULL; + +GeneratedCodeInfo* GeneratedCodeInfo::New(::google::protobuf::Arena* arena) const { + GeneratedCodeInfo* n = new GeneratedCodeInfo; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +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()) { + mutable_unknown_fields()->Clear(); + } +} + +bool GeneratedCodeInfo::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; + case 1: { + if (tag == 10) { + DO_(input->IncrementRecursionDepth()); + parse_loop_annotation: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( + input, add_annotation())); + } else { + goto handle_unusual; + } + if (input->ExpectTag(10)) goto parse_loop_annotation; + input->UnsafeDecrementRecursionDepth(); + if (input->ExpectAtEnd()) goto success; + break; + } + + default: { + handle_unusual: + if (tag == 0 || + ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo) + return true; +failure: + // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo) + return false; +#undef DO_ +} + +void GeneratedCodeInfo::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo) + // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; + for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 1, this->annotation(i), output); + } + + if (_internal_metadata_.have_unknown_fields()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo) +} + +::google::protobuf::uint8* GeneratedCodeInfo::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo) + // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; + for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 1, this->annotation(i), target); + } + + if (_internal_metadata_.have_unknown_fields()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo) + return target; +} + +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; + total_size += 1 * this->annotation_size(); + for (int i = 0; i < this->annotation_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->annotation(i)); + } + + if (_internal_metadata_.have_unknown_fields()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +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()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } +} + +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); +} + +bool GeneratedCodeInfo::IsInitialized() const { + + return true; +} + +void GeneratedCodeInfo::Swap(GeneratedCodeInfo* other) { + if (other == this) return; + InternalSwap(other); +} +void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) { + annotation_.UnsafeArenaSwap(&other->annotation_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata GeneratedCodeInfo::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = GeneratedCodeInfo_descriptor_; + metadata.reflection = GeneratedCodeInfo_reflection_; + return metadata; +} + +#if PROTOBUF_INLINE_NOT_IN_HEADERS +// GeneratedCodeInfo_Annotation + +// repeated int32 path = 1 [packed = true]; +int GeneratedCodeInfo_Annotation::path_size() const { + return path_.size(); +} +void GeneratedCodeInfo_Annotation::clear_path() { + path_.Clear(); +} + ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path) + return path_.Get(index); +} + void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) { + path_.Set(index, value); + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path) +} + void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) { + path_.Add(value); + // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path) +} + const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +GeneratedCodeInfo_Annotation::path() const { + // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path) + return path_; +} + ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +GeneratedCodeInfo_Annotation::mutable_path() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path) + return &path_; +} + +// optional string source_file = 2; +bool GeneratedCodeInfo_Annotation::has_source_file() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +void GeneratedCodeInfo_Annotation::set_has_source_file() { + _has_bits_[0] |= 0x00000002u; +} +void GeneratedCodeInfo_Annotation::clear_has_source_file() { + _has_bits_[0] &= ~0x00000002u; +} +void GeneratedCodeInfo_Annotation::clear_source_file() { + source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_source_file(); +} + const ::std::string& GeneratedCodeInfo_Annotation::source_file() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file) + return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} + void GeneratedCodeInfo_Annotation::set_source_file(const char* value) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} + void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} + ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() { + set_has_source_file(); + // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.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()); +} + void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) { + if (source_file != NULL) { + set_has_source_file(); + } else { + clear_has_source_file(); + } + source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} + +// optional int32 begin = 3; +bool GeneratedCodeInfo_Annotation::has_begin() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +void GeneratedCodeInfo_Annotation::set_has_begin() { + _has_bits_[0] |= 0x00000004u; +} +void GeneratedCodeInfo_Annotation::clear_has_begin() { + _has_bits_[0] &= ~0x00000004u; +} +void GeneratedCodeInfo_Annotation::clear_begin() { + begin_ = 0; + clear_has_begin(); +} + ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin) + return begin_; +} + void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) { + set_has_begin(); + begin_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin) +} + +// optional int32 end = 4; +bool GeneratedCodeInfo_Annotation::has_end() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +void GeneratedCodeInfo_Annotation::set_has_end() { + _has_bits_[0] |= 0x00000008u; +} +void GeneratedCodeInfo_Annotation::clear_has_end() { + _has_bits_[0] &= ~0x00000008u; +} +void GeneratedCodeInfo_Annotation::clear_end() { + end_ = 0; + clear_has_end(); +} + ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end) + return end_; +} + void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end) +} + +// ------------------------------------------------------------------- + +// GeneratedCodeInfo + +// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; +int GeneratedCodeInfo::annotation_size() const { + return annotation_.size(); +} +void GeneratedCodeInfo::clear_annotation() { + annotation_.Clear(); +} +const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Get(index); +} +::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Mutable(index); +} +::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() { + // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Add(); +} +::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >* +GeneratedCodeInfo::mutable_annotation() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation) + return &annotation_; +} +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >& +GeneratedCodeInfo::annotation() const { + // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_; +} + +#endif // PROTOBUF_INLINE_NOT_IN_HEADERS + // @@protoc_insertion_point(namespace_scope) } // namespace protobuf diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 60255162..92a0a3a7 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -50,6 +50,8 @@ class FieldOptions; class FileDescriptorProto; class FileDescriptorSet; class FileOptions; +class GeneratedCodeInfo; +class GeneratedCodeInfo_Annotation; class MessageOptions; class MethodDescriptorProto; class MethodOptions; @@ -991,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); } @@ -1031,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); } @@ -1866,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); } @@ -2015,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; - bool has_javanano_use_deprecated_package() const; - void clear_javanano_use_deprecated_package(); - static const int kJavananoUseDeprecatedPackageFieldNumber = 38; - bool javanano_use_deprecated_package() const; - void set_javanano_use_deprecated_package(bool value); - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int uninterpreted_option_size() const; void clear_uninterpreted_option(); @@ -2065,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_; @@ -2081,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(); @@ -2296,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); } @@ -2321,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); } @@ -3390,6 +3412,228 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { void InitAsDefaultInstance(); static SourceCodeInfo* default_instance_; }; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message { + public: + GeneratedCodeInfo_Annotation(); + virtual ~GeneratedCodeInfo_Annotation(); + + GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from); + + inline GeneratedCodeInfo_Annotation& operator=(const GeneratedCodeInfo_Annotation& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields(); + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields(); + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const GeneratedCodeInfo_Annotation& default_instance(); + + void Swap(GeneratedCodeInfo_Annotation* other); + + // implements Message ---------------------------------------------- + + inline GeneratedCodeInfo_Annotation* New() const { return New(NULL); } + + GeneratedCodeInfo_Annotation* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const GeneratedCodeInfo_Annotation& from); + void MergeFrom(const GeneratedCodeInfo_Annotation& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(GeneratedCodeInfo_Annotation* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated int32 path = 1 [packed = true]; + int path_size() const; + void clear_path(); + static const int kPathFieldNumber = 1; + ::google::protobuf::int32 path(int index) const; + void set_path(int index, ::google::protobuf::int32 value); + void add_path(::google::protobuf::int32 value); + const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + path() const; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_path(); + + // optional string source_file = 2; + bool has_source_file() const; + void clear_source_file(); + static const int kSourceFileFieldNumber = 2; + const ::std::string& source_file() const; + void set_source_file(const ::std::string& value); + void set_source_file(const char* value); + void set_source_file(const char* value, size_t size); + ::std::string* mutable_source_file(); + ::std::string* release_source_file(); + void set_allocated_source_file(::std::string* source_file); + + // optional int32 begin = 3; + bool has_begin() const; + void clear_begin(); + static const int kBeginFieldNumber = 3; + ::google::protobuf::int32 begin() const; + void set_begin(::google::protobuf::int32 value); + + // optional int32 end = 4; + bool has_end() const; + void clear_end(); + static const int kEndFieldNumber = 4; + ::google::protobuf::int32 end() const; + void set_end(::google::protobuf::int32 value); + + // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation) + private: + inline void set_has_source_file(); + inline void clear_has_source_file(); + inline void set_has_begin(); + inline void clear_has_begin(); + inline void set_has_end(); + inline void clear_has_end(); + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + ::google::protobuf::uint32 _has_bits_[1]; + mutable int _cached_size_; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_; + mutable int _path_cached_byte_size_; + ::google::protobuf::internal::ArenaStringPtr source_file_; + ::google::protobuf::int32 begin_; + ::google::protobuf::int32 end_; + 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(); + + void InitAsDefaultInstance(); + static GeneratedCodeInfo_Annotation* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message { + public: + GeneratedCodeInfo(); + virtual ~GeneratedCodeInfo(); + + GeneratedCodeInfo(const GeneratedCodeInfo& from); + + inline GeneratedCodeInfo& operator=(const GeneratedCodeInfo& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields(); + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields(); + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const GeneratedCodeInfo& default_instance(); + + void Swap(GeneratedCodeInfo* other); + + // implements Message ---------------------------------------------- + + inline GeneratedCodeInfo* New() const { return New(NULL); } + + GeneratedCodeInfo* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const GeneratedCodeInfo& from); + void MergeFrom(const GeneratedCodeInfo& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(GeneratedCodeInfo* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef GeneratedCodeInfo_Annotation Annotation; + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; + int annotation_size() const; + void clear_annotation(); + static const int kAnnotationFieldNumber = 1; + const ::google::protobuf::GeneratedCodeInfo_Annotation& annotation(int index) const; + ::google::protobuf::GeneratedCodeInfo_Annotation* mutable_annotation(int index); + ::google::protobuf::GeneratedCodeInfo_Annotation* add_annotation(); + ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >* + mutable_annotation(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >& + annotation() const; + + // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + ::google::protobuf::uint32 _has_bits_[1]; + mutable int _cached_size_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation > annotation_; + 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(); + + void InitAsDefaultInstance(); + static GeneratedCodeInfo* default_instance_; +}; // =================================================================== @@ -3472,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()); } @@ -3525,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()); } @@ -3567,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) { @@ -3799,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; @@ -3842,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; @@ -3898,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()); } @@ -4059,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()); } @@ -4279,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; @@ -4354,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) { @@ -4423,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()); } @@ -4550,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()); } @@ -4603,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()); } @@ -4656,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()); } @@ -4733,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()); } @@ -4773,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; @@ -4833,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()); } @@ -4890,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()); } @@ -4960,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; @@ -5020,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()); } @@ -5084,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; @@ -5144,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()); } @@ -5214,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; @@ -5274,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()); } @@ -5327,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()); } @@ -5380,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()); } @@ -5420,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; @@ -5528,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()); } @@ -5581,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()); } @@ -5731,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()); } @@ -5904,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()); } @@ -5957,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()); } @@ -5970,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; -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(); @@ -6634,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()); } @@ -6745,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()); } @@ -6870,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()); } @@ -6923,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()); } @@ -7040,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()); } @@ -7093,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()); } @@ -7135,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) { @@ -7194,6 +7452,176 @@ SourceCodeInfo::location() const { return location_; } +// ------------------------------------------------------------------- + +// GeneratedCodeInfo_Annotation + +// repeated int32 path = 1 [packed = true]; +inline int GeneratedCodeInfo_Annotation::path_size() const { + return path_.size(); +} +inline void GeneratedCodeInfo_Annotation::clear_path() { + path_.Clear(); +} +inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path) + return path_.Get(index); +} +inline void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) { + path_.Set(index, value); + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path) +} +inline void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) { + path_.Add(value); + // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path) +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +GeneratedCodeInfo_Annotation::path() const { + // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path) + return path_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +GeneratedCodeInfo_Annotation::mutable_path() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path) + return &path_; +} + +// optional string source_file = 2; +inline bool GeneratedCodeInfo_Annotation::has_source_file() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void GeneratedCodeInfo_Annotation::set_has_source_file() { + _has_bits_[0] |= 0x00000002u; +} +inline void GeneratedCodeInfo_Annotation::clear_has_source_file() { + _has_bits_[0] &= ~0x00000002u; +} +inline void GeneratedCodeInfo_Annotation::clear_source_file() { + source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_source_file(); +} +inline const ::std::string& GeneratedCodeInfo_Annotation::source_file() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file) + return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} +inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} +inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) { + set_has_source_file(); + source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} +inline ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() { + set_has_source_file(); + // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.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()); +} +inline void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) { + if (source_file != NULL) { + set_has_source_file(); + } else { + clear_has_source_file(); + } + source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file) +} + +// optional int32 begin = 3; +inline bool GeneratedCodeInfo_Annotation::has_begin() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void GeneratedCodeInfo_Annotation::set_has_begin() { + _has_bits_[0] |= 0x00000004u; +} +inline void GeneratedCodeInfo_Annotation::clear_has_begin() { + _has_bits_[0] &= ~0x00000004u; +} +inline void GeneratedCodeInfo_Annotation::clear_begin() { + begin_ = 0; + clear_has_begin(); +} +inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin) + return begin_; +} +inline void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) { + set_has_begin(); + begin_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin) +} + +// optional int32 end = 4; +inline bool GeneratedCodeInfo_Annotation::has_end() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void GeneratedCodeInfo_Annotation::set_has_end() { + _has_bits_[0] |= 0x00000008u; +} +inline void GeneratedCodeInfo_Annotation::clear_has_end() { + _has_bits_[0] &= ~0x00000008u; +} +inline void GeneratedCodeInfo_Annotation::clear_end() { + end_ = 0; + clear_has_end(); +} +inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end) + return end_; +} +inline void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end) +} + +// ------------------------------------------------------------------- + +// GeneratedCodeInfo + +// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; +inline int GeneratedCodeInfo::annotation_size() const { + return annotation_.size(); +} +inline void GeneratedCodeInfo::clear_annotation() { + annotation_.Clear(); +} +inline const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Get(index); +} +inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Mutable(index); +} +inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() { + // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_.Add(); +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >* +GeneratedCodeInfo::mutable_annotation() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation) + return &annotation_; +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >& +GeneratedCodeInfo::annotation() const { + // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation) + return annotation_; +} + #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- @@ -7237,6 +7665,10 @@ SourceCodeInfo::location() const { // ------------------------------------------------------------------- +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index c59a6022..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; - // 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 { @@ -777,3 +775,29 @@ message SourceCodeInfo { repeated string leading_detached_comments = 6; } } + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed=true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + } +} diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index ccd0650d..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> @@ -178,6 +179,61 @@ void AddEmptyEnum(FileDescriptorProto* file, const string& name) { AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1); } +class MockErrorCollector : public DescriptorPool::ErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + string text_; + string warning_text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const string& filename, + const string& element_name, const Message* descriptor, + ErrorLocation location, const string& message) { + const char* location_name = NULL; + switch (location) { + case NAME : location_name = "NAME" ; break; + case NUMBER : location_name = "NUMBER" ; break; + case TYPE : location_name = "TYPE" ; break; + case EXTENDEE : location_name = "EXTENDEE" ; break; + case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; + case OPTION_NAME : location_name = "OPTION_NAME" ; break; + case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; + case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; + case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; + case OTHER : location_name = "OTHER" ; break; + } + + strings::SubstituteAndAppend( + &text_, "$0: $1: $2: $3\n", + filename, element_name, location_name, message); + } + + // implements ErrorCollector --------------------------------------- + void AddWarning(const string& filename, const string& element_name, + const Message* descriptor, ErrorLocation location, + const string& message) { + const char* location_name = NULL; + switch (location) { + case NAME : location_name = "NAME" ; break; + case NUMBER : location_name = "NUMBER" ; break; + case TYPE : location_name = "TYPE" ; break; + case EXTENDEE : location_name = "EXTENDEE" ; break; + case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; + case OPTION_NAME : location_name = "OPTION_NAME" ; break; + case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; + case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; + case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; + case OTHER : location_name = "OTHER" ; break; + } + + strings::SubstituteAndAppend( + &warning_text_, "$0: $1: $2: $3\n", + filename, element_name, location_name, message); + } +}; + // =================================================================== // Test simple files. @@ -3120,77 +3176,95 @@ TEST(CustomOptions, UnusedImportWarning) { ->file()->CopyTo(&file_proto); ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); - pool.AddUnusedImportTrackFile("custom_options_import.proto"); ASSERT_TRUE(TextFormat::ParseFromString( "name: \"custom_options_import.proto\" " "package: \"protobuf_unittest\" " "dependency: \"google/protobuf/unittest_custom_options.proto\" ", &file_proto)); - pool.BuildFile(file_proto); -} -// =================================================================== + MockErrorCollector error_collector; + EXPECT_TRUE(pool.BuildFileCollectingErrors(file_proto, &error_collector)); + EXPECT_EQ("", error_collector.warning_text_); +} -// The tests below trigger every unique call to AddError() in descriptor.cc, -// in the order in which they appear in that file. I'm using TextFormat here -// to specify the input descriptors because building them using code would -// be too bulky. +// Verifies that proto files can correctly be parsed, even if the +// custom options defined in the file are incompatible with those +// compiled in the binary. See http://b/19276250. +TEST(CustomOptions, OptionsWithRequiredEnums) { + DescriptorPool pool; -class MockErrorCollector : public DescriptorPool::ErrorCollector { - public: - MockErrorCollector() {} - ~MockErrorCollector() {} + FileDescriptorProto file_proto; + MessageOptions::descriptor()->file()->CopyTo(&file_proto); + ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); - string text_; - string warning_text_; + // Create a new file descriptor proto containing a subset of the + // messages defined in google/protobuf/unittest_custom_options.proto. + file_proto.Clear(); + file_proto.set_name("unittest_custom_options.proto"); + file_proto.set_package("protobuf_unittest"); + file_proto.add_dependency("google/protobuf/descriptor.proto"); - // implements ErrorCollector --------------------------------------- - void AddError(const string& filename, - const string& element_name, const Message* descriptor, - ErrorLocation location, const string& message) { - const char* location_name = NULL; - switch (location) { - case NAME : location_name = "NAME" ; break; - case NUMBER : location_name = "NUMBER" ; break; - case TYPE : location_name = "TYPE" ; break; - case EXTENDEE : location_name = "EXTENDEE" ; break; - case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; - case OPTION_NAME : location_name = "OPTION_NAME" ; break; - case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; - case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; - case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; - case OTHER : location_name = "OTHER" ; break; - } + // Add the "required_enum_opt" extension. + FieldDescriptorProto* extension = file_proto.add_extension(); + protobuf_unittest::OldOptionType::descriptor()->file() + ->FindExtensionByName("required_enum_opt")->CopyTo(extension); + + // Add a test message that uses the "required_enum_opt" option. + DescriptorProto* test_message_type = file_proto.add_message_type(); + protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor() + ->CopyTo(test_message_type); + + // Instruct the extension to use NewOptionType instead of + // OldOptionType, and add the descriptor of NewOptionType. + extension->set_type_name(".protobuf_unittest.NewOptionType"); + DescriptorProto* new_option_type = file_proto.add_message_type(); + protobuf_unittest::NewOptionType::descriptor() + ->CopyTo(new_option_type); + + // Replace the value of the "required_enum_opt" option used in the + // test message with an enum value that only exists in NewOptionType. + ASSERT_TRUE(TextFormat::ParseFromString( + "uninterpreted_option { " + " name { " + " name_part: 'required_enum_opt' " + " is_extension: true " + " } " + " aggregate_value: 'value: NEW_VALUE' " + "}", + test_message_type->mutable_options())); - strings::SubstituteAndAppend( - &text_, "$0: $1: $2: $3\n", - filename, element_name, location_name, message); - } + // Add the file descriptor to the pool. + ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); - // implements ErrorCollector --------------------------------------- - void AddWarning(const string& filename, const string& element_name, - const Message* descriptor, ErrorLocation location, - const string& message) { - const char* location_name = NULL; - switch (location) { - case NAME : location_name = "NAME" ; break; - case NUMBER : location_name = "NUMBER" ; break; - case TYPE : location_name = "TYPE" ; break; - case EXTENDEE : location_name = "EXTENDEE" ; break; - case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break; - case OPTION_NAME : location_name = "OPTION_NAME" ; break; - case OPTION_VALUE : location_name = "OPTION_VALUE" ; break; - case INPUT_TYPE : location_name = "INPUT_TYPE" ; break; - case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break; - case OTHER : location_name = "OTHER" ; break; - } + // Find the test message. + const Descriptor* test_message = pool.FindMessageTypeByName( + "protobuf_unittest.TestMessageWithRequiredEnumOption"); + ASSERT_TRUE(test_message != NULL); + + const MessageOptions& options = test_message->options(); + // Extract the "required_enum_opt" option. Since the binary does not + // know that the extension was updated, this will still return an + // OldOptionType message. + ASSERT_TRUE( + options.HasExtension(protobuf_unittest::required_enum_opt)); + const protobuf_unittest::OldOptionType& old_enum_opt = + options.GetExtension(protobuf_unittest::required_enum_opt); + + // Confirm that the required enum field is missing. + EXPECT_FALSE(old_enum_opt.IsInitialized()); + EXPECT_FALSE(old_enum_opt.has_value()); + + string buf; + // Verify that the required enum field does show up when the option + // is re-parsed as a NewOptionType message; + protobuf_unittest::NewOptionType new_enum_opt; + EXPECT_TRUE(old_enum_opt.AppendPartialToString(&buf)); + EXPECT_TRUE(new_enum_opt.ParseFromString(buf)); + EXPECT_EQ(protobuf_unittest::NewOptionType::NEW_VALUE, new_enum_opt.value()); +} - strings::SubstituteAndAppend( - &warning_text_, "$0: $1: $2: $3\n", - filename, element_name, location_name, message); - } -}; +// =================================================================== class ValidationErrorTest : public testing::Test { protected: @@ -5123,7 +5197,6 @@ TEST_F(ValidationErrorTest, AllowEnumAlias) { } TEST_F(ValidationErrorTest, UnusedImportWarning) { - pool_.AddUnusedImportTrackFile("bar.proto"); BuildFile( "name: \"bar.proto\" " @@ -5155,7 +5228,7 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) { // } // pool_.AddUnusedImportTrackFile("forward.proto"); - BuildFile( + BuildFileWithWarnings( "name: \"forward.proto\"" "dependency: \"base.proto\"" "dependency: \"bar.proto\"" @@ -5165,7 +5238,8 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) { "message_type {" " name: \"Forward\"" " field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }" - "}"); + "}", + "forward.proto: bar.proto: OTHER: Import bar.proto but not used.\n"); } namespace { @@ -5666,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 2e22ccb1..e3639346 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/duration.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/duration.pb.h" +#include <google/protobuf/duration.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -82,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(); @@ -111,10 +113,10 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Duration::kSecondsFieldNumber; const int Duration::kNanosFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Duration::Duration() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -177,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,\ @@ -194,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 (;;) { @@ -286,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; @@ -309,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()); @@ -331,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 7f172aa6..96c1796d 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -27,15 +27,17 @@ // 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"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "DurationProto"; -option java_package = "com.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; +option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; // A Duration represents a signed, fixed-length span of time represented @@ -79,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 72a8483f..9e83bd29 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -69,8 +69,8 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif -#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/descriptor.h> @@ -253,12 +253,6 @@ class DynamicMessage : public Message { DynamicMessage(const TypeInfo* type_info); ~DynamicMessage(); -#ifndef _MSC_VER - void operator delete(void *p) { - ::operator delete(p); // non-sized deallocation - } -#endif - // Called on the prototype after construction to initialize message fields. void CrossLinkPrototypes(); @@ -273,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); @@ -425,7 +429,7 @@ DynamicMessage::~DynamicMessage() { } // We need to manually run the destructors for repeated fields and strings, - // just as we ran their constructors in the the DynamicMessage constructor. + // just as we ran their constructors in the DynamicMessage constructor. // We also need to manually delete oneof fields if it is set and is string // or message. // Additionally, if any singular embedded messages have been allocated, we @@ -448,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; @@ -710,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; } @@ -754,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 50cbd9a8..dcf84263 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/empty.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/empty.pb.h" +#include <google/protobuf/empty.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -79,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\005EmptyBM\n\023com.google.protobufB\n" - "EmptyProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf." - "WellKnownTypesb\006proto3", 142); + "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(); @@ -108,8 +110,8 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER -#endif // !_MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Empty::Empty() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -117,6 +119,14 @@ Empty::Empty() // @@protoc_insertion_point(constructor:google.protobuf.Empty) } +Empty::Empty(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty) +} + void Empty::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -140,10 +150,20 @@ Empty::~Empty() { } void Empty::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void Empty::ArenaDtor(void* object) { + Empty* _this = reinterpret_cast< Empty* >(object); + (void)_this; +} +void Empty::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void Empty::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -162,19 +182,16 @@ const Empty& Empty::default_instance() { Empty* Empty::default_instance_ = NULL; Empty* Empty::New(::google::protobuf::Arena* arena) const { - Empty* n = new Empty; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<Empty>(arena); } 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 (;;) { @@ -212,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(); @@ -221,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); @@ -255,6 +279,18 @@ bool Empty::IsInitialized() const { void Empty::Swap(Empty* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + Empty temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void Empty::UnsafeArenaSwap(Empty* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void Empty::InternalSwap(Empty* other) { diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index 20876bea..868009fc 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -53,9 +53,14 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const Empty& default_instance(); + void UnsafeArenaSwap(Empty* other); void Swap(Empty* other); // implements Message ---------------------------------------------- @@ -82,6 +87,11 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(Empty* other); + protected: + explicit Empty(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -101,6 +111,9 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto(); diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto index 9dddc6c5..37f4cd10 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -27,16 +27,19 @@ // 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"; package google.protobuf; -option java_multiple_files = true; -option java_outer_classname = "EmptyProto"; +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; option java_generate_equals_and_hash = true; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; // A generic empty message that you can re-use to avoid defining duplicated // empty messages in your APIs. A typical example is to use it as the request diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index d8f4ee91..c49ebceb 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/field_mask.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/field_mask.pb.h" +#include <google/protobuf/field_mask.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -110,9 +111,9 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FieldMask::kPathsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FieldMask::FieldMask() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -174,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 (;;) { @@ -261,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; @@ -277,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); @@ -360,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 8b21c692..6af6dbe8 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -27,16 +27,17 @@ // 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"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "FieldMaskProto"; -option java_package = "com.google.protobuf"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldMaskProto"; +option java_multiple_files = true; option objc_class_prefix = "GPB"; +option java_generate_equals_and_hash = true; // `FieldMask` represents a set of symbolic field paths, for example: // @@ -69,7 +70,7 @@ option objc_class_prefix = "GPB"; // z: 8 // // The result will not contain specific values for fields x,y and z -// (there value will be set to the default, and omitted in proto text +// (their value will be set to the default, and omitted in proto text // output): // // @@ -87,7 +88,7 @@ option objc_class_prefix = "GPB"; // 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 @@ -161,6 +162,32 @@ option objc_class_prefix = "GPB"; // 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 4bcd354f..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) { @@ -629,6 +629,24 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) had_error_ = false; } +CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output, + bool do_eager_refresh) + : output_(output), + buffer_(NULL), + buffer_size_(0), + total_bytes_(0), + had_error_(false), + aliasing_enabled_(false) { + if (do_eager_refresh) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); + // The Refresh() may have failed. If the client doesn't write any data, + // though, don't consider this an error. If the client does write data, then + // another Refresh() will be attempted and it will set the error once again. + had_error_ = false; + } +} + CodedOutputStream::~CodedOutputStream() { Trim(); } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 361c406b..c81a33ac 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -109,6 +109,7 @@ #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ +#include <assert.h> #include <string> #include <utility> #ifdef _MSC_VER @@ -116,7 +117,7 @@ #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) #define PROTOBUF_LITTLE_ENDIAN 1 #endif - #if _MSC_VER >= 1300 + #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER) // If MSVC has "/RTCc" set, it will complain about truncating casts at // runtime. This file contains some intentional truncating casts. #pragma runtime_checks("c", off) @@ -665,6 +666,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { public: // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. explicit CodedOutputStream(ZeroCopyOutputStream* output); + CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh); // Destroy the CodedOutputStream and position the underlying // ZeroCopyOutputStream immediately after the last byte written. @@ -1035,7 +1037,7 @@ inline const uint8* CodedInputStream::ExpectTagFromArray( inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, int* size) { *data = buffer_; - *size = buffer_end_ - buffer_; + *size = static_cast<int>(buffer_end_ - buffer_); } inline bool CodedInputStream::ExpectAtEnd() { @@ -1134,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); @@ -1231,7 +1233,7 @@ inline MessageFactory* CodedInputStream::GetExtensionFactory() { } inline int CodedInputStream::BufferSize() const { - return buffer_end_ - buffer_; + return static_cast<int>(buffer_end_ - buffer_); } inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) @@ -1284,9 +1286,9 @@ inline bool CodedInputStream::IsFlat() const { } // namespace protobuf -#if defined(_MSC_VER) && _MSC_VER >= 1300 +#if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER) #pragma runtime_checks("c", restore) -#endif // _MSC_VER +#endif // _MSC_VER && !defined(__INTEL_COMPILER) } // namespace google #endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ 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.cc b/src/google/protobuf/io/gzip_stream.cc index 1be6c863..9c621b6a 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -241,9 +241,7 @@ void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream, GzipOutputStream::~GzipOutputStream() { Close(); - if (input_buffer_ != NULL) { - operator delete(input_buffer_); - } + operator delete(input_buffer_); } // private 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/strtod.cc b/src/google/protobuf/io/strtod.cc index 579de9aa..a90bb9a3 100644 --- a/src/google/protobuf/io/strtod.cc +++ b/src/google/protobuf/io/strtod.cc @@ -32,6 +32,7 @@ #include <cstdio> #include <cstring> +#include <limits> #include <string> #include <google/protobuf/stubs/logging.h> @@ -109,6 +110,16 @@ double NoLocaleStrtod(const char* text, char** original_endptr) { return result; } +float SafeDoubleToFloat(double value) { + if (value > std::numeric_limits<float>::max()) { + return std::numeric_limits<float>::infinity(); + } else if (value < -std::numeric_limits<float>::max()) { + return -std::numeric_limits<float>::infinity(); + } else { + return static_cast<float>(value); + } +} + } // namespace io } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h index c2efc8d3..f56e41c8 100644 --- a/src/google/protobuf/io/strtod.h +++ b/src/google/protobuf/io/strtod.h @@ -43,6 +43,11 @@ namespace io { // uses a dot as the decimal separator. double NoLocaleStrtod(const char* str, char** endptr); +// Casts a double value to a float value. If the value is outside of the +// representable range of float, it will be converted to positive or negative +// infinity. +float SafeDoubleToFloat(double value); + } // namespace io } // namespace protobuf diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 7ccd633d..b3550dfb 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -375,7 +375,7 @@ void Tokenizer::ConsumeString(char delimiter) { // Possibly followed by two more octal digits, but these will // just be consumed by the main loop anyway so we don't need // to do so explicitly here. - } else if (TryConsume('x') || TryConsume('X')) { + } else if (TryConsume('x')) { if (!TryConsumeOne<HexDigit>()) { AddError("Expected hex digits for escape sequence."); } @@ -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 6526056a..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)); @@ -875,6 +869,8 @@ ErrorCase kErrorCases[] = { // String errors. { "'\\l' foo", true, "0:2: Invalid escape sequence in string literal.\n" }, + { "'\\X' foo", true, + "0:2: Invalid escape sequence in string literal.\n" }, { "'\\x' foo", true, "0:3: Expected hex digits for escape sequence.\n" }, { "'foo", false, 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 686e63f2..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,6 +157,7 @@ StringOutputStream::~StringOutputStream() { } bool StringOutputStream::Next(void** data, int* size) { + GOOGLE_CHECK(target_ != NULL); int old_size = target_->size(); // Grow the string. @@ -176,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; @@ -188,14 +189,44 @@ bool StringOutputStream::Next(void** data, int* size) { void StringOutputStream::BackUp(int count) { GOOGLE_CHECK_GE(count, 0); + GOOGLE_CHECK(target_ != NULL); GOOGLE_CHECK_LE(count, target_->size()); target_->resize(target_->size() - count); } int64 StringOutputStream::ByteCount() const { + GOOGLE_CHECK(target_ != NULL); return target_->size(); } +void StringOutputStream::SetString(string* target) { + target_ = target; +} + +// =================================================================== + +LazyStringOutputStream::LazyStringOutputStream( + ResultCallback<string*>* callback) + : StringOutputStream(NULL), + callback_(GOOGLE_CHECK_NOTNULL(callback)), + string_is_set_(false) { +} + +LazyStringOutputStream::~LazyStringOutputStream() { +} + +bool LazyStringOutputStream::Next(void** data, int* size) { + if (!string_is_set_) { + SetString(callback_->Run()); + string_is_set_ = true; + } + return StringOutputStream::Next(data, size); +} + +int64 LazyStringOutputStream::ByteCount() const { + return string_is_set_ ? StringOutputStream::ByteCount() : 0; +} + // =================================================================== CopyingInputStream::~CopyingInputStream() {} @@ -204,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 a598ef2e..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> @@ -148,6 +149,9 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { void BackUp(int count); int64 ByteCount() const; + protected: + void SetString(string* target); + private: static const int kMinimumSize = 16; @@ -156,6 +160,27 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream); }; +// LazyStringOutputStream is a StringOutputStream with lazy acquisition of +// the output string from a callback. The string is owned externally, and not +// deleted in the stream destructor. +class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream { + public: + // Callback should be permanent (non-self-deleting). Ownership is transferred + // to the LazyStringOutputStream. + explicit LazyStringOutputStream(ResultCallback<string*>* callback); + ~LazyStringOutputStream(); + + // implements ZeroCopyOutputStream, overriding StringOutputStream ----------- + bool Next(void** data, int* size); + int64 ByteCount() const; + + private: + const google::protobuf::scoped_ptr<ResultCallback<string*> > callback_; + bool string_is_set_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream); +}; + // Note: There is no StringInputStream. Instead, just create an // ArrayInputStream as follows: // ArrayInputStream input(str.data(), str.size()); 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 72a1b1a3..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 @@ -155,7 +163,7 @@ class LIBPROTOBUF_EXPORT MapKey { "MapKey::GetUInt32Value"); return val_.uint32_value_; } - int32 GetBoolValue() const { + bool GetBoolValue() const { TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapKey::GetBoolValue"); return val_.bool_value_; @@ -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,12 +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."; - return false; } GOOGLE_LOG(FATAL) << "Can't get here."; return false; @@ -197,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; @@ -215,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; } } @@ -275,7 +313,7 @@ class LIBPROTOBUF_EXPORT MapValueRef { "MapValueRef::SetInt32Value"); *reinterpret_cast<int32*>(data_) = value; } - void SetUInt32Value(uint64 value) { + void SetUInt32Value(uint32 value) { TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapValueRef::SetUInt32Value"); *reinterpret_cast<uint32*>(data_) = value; @@ -458,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: @@ -474,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> - explicit 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. @@ -546,10 +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) { - new (static_cast<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> @@ -584,92 +654,855 @@ class Map { private: typedef void DestructorSkippable_; - Arena* arena_; + Arena* const arena_; template <typename X> friend class MapAllocator; }; - public: - typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator; + // 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 hash_map<Key, value_type*, hash<Key>, equal_to<Key>, - Allocator>::const_iterator InnerIt; + 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> { - typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>, - Allocator>::iterator InnerIt; + 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, @@ -691,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 { @@ -721,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> @@ -740,34 +1585,31 @@ class Map { } } - // Erase + // Erase and clear size_type erase(const key_type& key) { - typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>, - Allocator>::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_); - } - } - void clear() { - for (iterator it = begin(); it != end(); ++it) { - if (arena_ == NULL) delete it.it_->second; + while (first != last) { + first = erase(first); } - elements_.clear(); } + void clear() { erase(begin(), end()); } // Assign Map& operator=(const Map& other) { @@ -778,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) { @@ -812,9 +1661,15 @@ class Map { } Arena* arena_; - Allocator allocator_; - hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> 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_; @@ -835,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: @@ -847,12 +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."; - return 0; } GOOGLE_LOG(FATAL) << "Can't get here."; return 0; @@ -860,27 +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."; - return true; - } - 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_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h index 77b5336f..66dedde5 100644 --- a/src/google/protobuf/map_lite_test_util.h +++ b/src/google/protobuf/map_lite_test_util.h @@ -47,7 +47,7 @@ class MapLiteTestUtil { // Set every field in the message to a default value. static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message); - // Modify all the map fields of the messsage (which should already have been + // Modify all the map fields of the message (which should already have been // initialized with SetMapFields()). static void ModifyMapFields(protobuf_unittest::TestMapLite* message); 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/map_test_util.h b/src/google/protobuf/map_test_util.h index 107a639d..deaf0f4f 100644 --- a/src/google/protobuf/map_test_util.h +++ b/src/google/protobuf/map_test_util.h @@ -49,7 +49,7 @@ class MapTestUtil { // Set every field in the message to a default value. static void SetMapFieldsInitialized(unittest::TestMap* message); - // Modify all the map fields of the messsage (which should already have been + // Modify all the map fields of the message (which should already have been // initialized with SetMapFields()). static void ModifyMapFields(unittest::TestMap* message); diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h index 7e8757ed..b3ba4e06 100644 --- a/src/google/protobuf/map_test_util_impl.h +++ b/src/google/protobuf/map_test_util_impl.h @@ -64,7 +64,7 @@ class MapTestUtilImpl { template <typename MapMessage> static void SetMapFieldsInitialized(MapMessage* message); - // Modify all the map fields of the messsage (which should already have been + // Modify all the map fields of the message (which should already have been // initialized with SetMapFields()). template <typename EnumType, EnumType enum_value, typename MapMessage> static void ModifyMapFields(MapMessage* message); 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.h b/src/google/protobuf/message.h index 7c27afd9..a4d9277e 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -739,9 +739,9 @@ class LIBPROTOBUF_EXPORT Reflection { // specifyed by 'field' passing ownership to the message. // TODO(tmarek): Make virtual after all subclasses have been // updated. - virtual void AddAllocatedMessage(Message* message, - const FieldDescriptor* field, - Message* new_entry) const {} + virtual void AddAllocatedMessage(Message* /* message */, + const FieldDescriptor* /*field */, + Message* /* new_entry */) const {} // Get a RepeatedFieldRef object that can be used to read the underlying @@ -947,27 +947,27 @@ class LIBPROTOBUF_EXPORT Reflection { // TODO(jieluo) - make the map APIs pure virtual after updating // all the subclasses. // Returns true if key is in map. Returns false if key is not in map field. - virtual bool ContainsMapKey(const Message& message, - const FieldDescriptor* field, - const MapKey& key) const { + virtual bool ContainsMapKey(const Message& /* message*/, + const FieldDescriptor* /* field */, + const MapKey& /* key */) const { return false; } // If key is in map field: Saves the value pointer to val and returns // false. If key in not in map field: Insert the key into map, saves // value pointer to val and retuns true. - virtual bool InsertOrLookupMapValue(Message* message, - const FieldDescriptor* field, - const MapKey& key, - MapValueRef* val) const { + virtual bool InsertOrLookupMapValue(Message* /* message */, + const FieldDescriptor* /* field */, + const MapKey& /* key */, + MapValueRef* /* val */) const { return false; } // Delete and returns true if key is in the map field. Returns false // otherwise. - virtual bool DeleteMapValue(Message* message, - const FieldDescriptor* field, - const MapKey& key) const { + virtual bool DeleteMapValue(Message* /* mesage */, + const FieldDescriptor* /* field */, + const MapKey& /* key */) const { return false; } @@ -987,15 +987,15 @@ class LIBPROTOBUF_EXPORT Reflection { // Get the number of <key, value> pair of a map field. The result may be // different from FieldSize which can have duplicate keys. - virtual int MapSize(const Message& message, - const FieldDescriptor* field) const { + virtual int MapSize(const Message& /* message */, + const FieldDescriptor* /* field */) const { return 0; } // Help method for MapIterator. friend class MapIterator; virtual internal::MapFieldBase* MapData( - Message* message, const FieldDescriptor* field) const { + Message* /* message */, const FieldDescriptor* /* field */) const { return NULL; } 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 5530fefe..1961bc48 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -208,10 +208,19 @@ class RepeatedField { // sizeof(*this) int SpaceUsedExcludingSelf() const; - // Remove the element referenced by position. + // Removes the element referenced by position. + // + // Returns an iterator to the element immediately following the removed + // element. + // + // Invalidates all iterators at or after the removed element, including end(). iterator erase(const_iterator position); - // Remove the elements in the range [first, last). + // Removes the elements in the range [first, last). + // + // Returns an iterator to the element immediately following the removed range. + // + // Invalidates all iterators at or after the removed range, including end(). iterator erase(const_iterator first, const_iterator last); // Get the Arena on which this RepeatedField stores its elements. @@ -235,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 @@ -263,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> @@ -565,7 +590,7 @@ class GenericTypeHandler { template <typename GenericType> GenericType* GenericTypeHandler<GenericType>::NewFromPrototype( - const GenericType* prototype, ::google::protobuf::Arena* arena) { + const GenericType* /* prototype */, ::google::protobuf::Arena* arena) { return New(arena); } template <typename GenericType> @@ -601,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. @@ -618,7 +650,7 @@ void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, // Message specialization bodies defined in message.cc. This split is necessary // to allow proto2-lite (which includes this header) to be independent of // Message. -DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message); +DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message) #undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES @@ -665,7 +697,7 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase { static inline ::google::protobuf::Arena* GetArena(string*) { return NULL; } - static inline void* GetMaybeArenaPointer(string* value) { + static inline void* GetMaybeArenaPointer(string* /* value */) { return NULL; } static inline void Delete(string* value, Arena* arena) { @@ -683,7 +715,7 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase { class StringTypeHandler : public StringTypeHandlerBase { public: static int SpaceUsed(const string& value) { - return sizeof(value) + StringSpaceUsedExcludingSelf(value); + return static_cast<int>(sizeof(value)) + StringSpaceUsedExcludingSelf(value); } }; @@ -827,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 @@ -885,10 +926,19 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // so will trigger a GOOGLE_DCHECK-failure. Element* ReleaseCleared(); - // Remove the element referenced by position. + // Removes the element referenced by position. + // + // Returns an iterator to the element immediately following the removed + // element. + // + // Invalidates all iterators at or after the removed element, including end(). iterator erase(const_iterator position); // Removes the elements in the range [first, last). + // + // Returns an iterator to the element immediately following the removed range. + // + // Invalidates all iterators at or after the removed range, including end(). iterator erase(const_iterator first, const_iterator last); // Gets the arena on which this RepeatedPtrField stores its elements. @@ -974,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> @@ -1222,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)) @@ -1256,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> @@ -2362,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, @@ -2396,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 c8397639..c67cd102 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/source_context.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/source_context.pb.h" +#include <google/protobuf/source_context.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -110,9 +111,9 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int SourceContext::kFileNameFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 SourceContext::SourceContext() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -176,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 (;;) { @@ -261,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; @@ -277,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) { @@ -297,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); @@ -364,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/source_context.proto b/src/google/protobuf/source_context.proto index e9a27d65..d76252ca 100644 --- a/src/google/protobuf/source_context.proto +++ b/src/google/protobuf/source_context.proto @@ -27,15 +27,16 @@ // 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"; package google.protobuf; -option java_multiple_files = true; -option java_outer_classname = "SourceContextProto"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; option java_generate_equals_and_hash = true; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; // `SourceContext` represents information about the source of a diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index d5f89122..11ccabbf 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/struct.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/struct.pb.h" +#include <google/protobuf/struct.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -165,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(); @@ -212,9 +215,9 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Struct::kFieldsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Struct::Struct() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -279,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 (;;) { @@ -382,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; @@ -404,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); @@ -480,14 +491,14 @@ Struct::mutable_fields() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Value::kNullValueFieldNumber; const int Value::kNumberValueFieldNumber; const int Value::kStringValueFieldNumber; const int Value::kBoolValueFieldNumber; const int Value::kStructValueFieldNumber; const int Value::kListValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Value::Value() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -559,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 @@ -593,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 (;;) { @@ -810,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()) { @@ -861,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: { @@ -906,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); @@ -1062,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()); @@ -1140,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_; @@ -1187,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_; @@ -1218,9 +1241,9 @@ Value::KindCase Value::kind_case() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int ListValue::kValuesFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 ListValue::ListValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1281,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 (;;) { @@ -1358,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; @@ -1375,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 b3e9e699..beeba811 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.proto @@ -27,15 +27,17 @@ // 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"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "StructProto"; -option java_package = "com.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; +option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; @@ -48,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/atomicops.h b/src/google/protobuf/stubs/atomicops.h index 5fa31b0a..9b3d1e6b 100644 --- a/src/google/protobuf/stubs/atomicops.h +++ b/src/google/protobuf/stubs/atomicops.h @@ -76,7 +76,7 @@ typedef int32 Atomic32; #ifdef GOOGLE_PROTOBUF_ARCH_64_BIT // We need to be able to go between Atomic64 and AtomicWord implicitly. This // means Atomic64 and AtomicWord should be the same type on 64-bit. -#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) || defined(GOOGLE_PROTOBUF_ARCH_SPARC) +#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) // NaCl's intptr_t is not actually 64-bits on 64-bit! // http://code.google.com/p/nativeclient/issues/detail?id=1162 // sparcv9's pointer type is 32bits @@ -192,7 +192,7 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); // AIX #elif defined(GOOGLE_PROTOBUF_OS_AIX) -#include <google/protobuf/stubs/atomicops_internals_aix.h> +#include <google/protobuf/stubs/atomicops_internals_power.h> // Apple. #elif defined(GOOGLE_PROTOBUF_OS_APPLE) @@ -210,8 +210,12 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); #include <google/protobuf/stubs/atomicops_internals_arm_qnx.h> #elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64) #include <google/protobuf/stubs/atomicops_internals_mips_gcc.h> +#elif defined(GOOGLE_PROTOBUF_ARCH_POWER) +#include <google/protobuf/stubs/atomicops_internals_power.h> #elif defined(__native_client__) #include <google/protobuf/stubs/atomicops_internals_pnacl.h> +#elif defined(GOOGLE_PROTOBUF_ARCH_PPC) +#include <google/protobuf/stubs/atomicops_internals_ppc_gcc.h> #elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)) #include <google/protobuf/stubs/atomicops_internals_generic_gcc.h> #elif defined(__clang__) diff --git a/src/google/protobuf/stubs/atomicops_internals_aix.h b/src/google/protobuf/stubs/atomicops_internals_power.h index b8a42f21..b8a42f21 100644 --- a/src/google/protobuf/stubs/atomicops_internals_aix.h +++ b/src/google/protobuf/stubs/atomicops_internals_power.h diff --git a/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h new file mode 100644 index 00000000..8231a578 --- /dev/null +++ b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: ogabbay@advaoptical.com (Oded Gabbay) +// Cleaned up by: bsilver16384@gmail.com (Brian Silverman) +// +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ + +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[prev],0,%[ptr] \n\t" + "cmpw 0,%[prev],%[old_value] \n\t" + "bne- 1f \n\t" + "stwcx. %[new_value],0,%[ptr] \n\t" + "bne- 0b \n\t" + "1: \n\t" + : [prev] "=&r"(prev), "+m"(*ptr) + : [ptr] "r"(ptr), [old_value] "r"(old_value), [new_value] "r"(new_value) + : "cc", "memory"); + + return prev; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, + Atomic32 new_value) { + Atomic32 old; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[old],0,%[ptr] \n\t" + "stwcx. %[new_value],0,%[ptr] \n\t" + "bne- 0b \n\t" + : [old] "=&r"(old), "+m"(*ptr) + : [ptr] "r"(ptr), [new_value] "r"(new_value) + : "cc", "memory"); + + return old; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + Atomic32 temp; + + __asm__ __volatile__( + "0: \n\t" + "lwarx %[temp],0,%[ptr] \n\t" + "add %[temp],%[increment],%[temp] \n\t" + "stwcx. %[temp],0,%[ptr] \n\t" + "bne- 0b \n\t" + : [temp] "=&r"(temp) + : [increment] "r"(increment), [ptr] "r"(ptr) + : "cc", "memory"); + + return temp; +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + MemoryBarrier(); + Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment); + MemoryBarrier(); + return res; +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, Atomic32 new_value) { + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + MemoryBarrier(); + return res; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, Atomic32 new_value) { + MemoryBarrier(); + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + return res; +} + +inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) { + *ptr = value; +} + +inline void MemoryBarrier() { __asm__ __volatile__("sync" : : : "memory"); } + +inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) { return *ptr; } + +inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#undef ATOMICOPS_COMPILER_BARRIER + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_ diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h index 6da530d3..87271c5e 100644 --- a/src/google/protobuf/stubs/callback.h +++ b/src/google/protobuf/stubs/callback.h @@ -78,6 +78,18 @@ class LIBPROTOBUF_EXPORT Closure { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure); }; +template<typename R> +class ResultCallback { + public: + ResultCallback() {} + virtual ~ResultCallback() {} + + virtual R Run() = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback); +}; + template<typename R, typename A1> class LIBPROTOBUF_EXPORT ResultCallback1 { public: @@ -240,6 +252,50 @@ class MethodClosure2 : public Closure { Arg2 arg2_; }; +template<typename R> +class FunctionResultCallback_0_0 : public ResultCallback<R> { + public: + typedef R (*FunctionType)(); + + FunctionResultCallback_0_0(FunctionType function, bool self_deleting) + : function_(function), self_deleting_(self_deleting) {} + ~FunctionResultCallback_0_0() {} + + R Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + R result = function_(); + if (needs_delete) delete this; + return result; + } + + private: + FunctionType function_; + bool self_deleting_; +}; + +template<typename R, typename P1> +class FunctionResultCallback_1_0 : public ResultCallback<R> { + public: + typedef R (*FunctionType)(P1); + + FunctionResultCallback_1_0(FunctionType function, bool self_deleting, + P1 p1) + : function_(function), self_deleting_(self_deleting), p1_(p1) {} + ~FunctionResultCallback_1_0() {} + + R Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + R result = function_(p1_); + if (needs_delete) delete this; + return result; + } + + private: + FunctionType function_; + bool self_deleting_; + P1 p1_; +}; + template<typename R, typename Arg1> class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> { public: @@ -408,6 +464,33 @@ inline Closure* NewPermanentCallback( object, method, false, arg1, arg2); } +// See ResultCallback +template<typename R> +inline ResultCallback<R>* NewCallback(R (*function)()) { + return new internal::FunctionResultCallback_0_0<R>(function, true); +} + +// See ResultCallback +template<typename R> +inline ResultCallback<R>* NewPermanentCallback(R (*function)()) { + return new internal::FunctionResultCallback_0_0<R>(function, false); +} + +// See ResultCallback +template<typename R, typename P1> +inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) { + return new internal::FunctionResultCallback_1_0<R, P1>( + function, true, p1); +} + +// See ResultCallback +template<typename R, typename P1> +inline ResultCallback<R>* NewPermanentCallback( + R (*function)(P1), P1 p1) { + return new internal::FunctionResultCallback_1_0<R, P1>( + function, false, p1); +} + // See ResultCallback1 template<typename R, typename A1> inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) { 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/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h index 9e0344d8..4ba4b348 100644 --- a/src/google/protobuf/stubs/platform_macros.h +++ b/src/google/protobuf/stubs/platform_macros.h @@ -65,14 +65,17 @@ #define GOOGLE_PROTOBUF_ARCH_32_BIT 1 #elif defined(sparc) #define GOOGLE_PROTOBUF_ARCH_SPARC 1 -#ifdef SOLARIS_64BIT_ENABLED +#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__) #define GOOGLE_PROTOBUF_ARCH_64_BIT 1 #else #define GOOGLE_PROTOBUF_ARCH_32_BIT 1 #endif -#elif defined(_POWER) +#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__) #define GOOGLE_PROTOBUF_ARCH_POWER 1 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1 +#elif defined(__PPC__) +#define GOOGLE_PROTOBUF_ARCH_PPC 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 #elif defined(__GNUC__) # if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)) // We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h @@ -97,6 +100,8 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR #if TARGET_OS_IPHONE #define GOOGLE_PROTOBUF_OS_IPHONE #endif +#elif defined(__EMSCRIPTEN__) +#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN #elif defined(__native_client__) #define GOOGLE_PROTOBUF_OS_NACL #elif defined(sun) diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h index b35a3afe..1036dff1 100644 --- a/src/google/protobuf/stubs/port.h +++ b/src/google/protobuf/stubs/port.h @@ -53,7 +53,7 @@ #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) #define PROTOBUF_LITTLE_ENDIAN 1 #endif - #if defined(_MSC_VER) && _MSC_VER >= 1300 + #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER) // If MSVC has "/RTCc" set, it will complain about truncating casts at // runtime. This file contains some intentional truncating casts. #pragma runtime_checks("c", off) diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h index a9d2b374..29f869ad 100644 --- a/src/google/protobuf/stubs/statusor.h +++ b/src/google/protobuf/stubs/statusor.h @@ -224,14 +224,14 @@ 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.value_) { + : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { } template<typename T> template<typename U> inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { status_ = other.status_; - value_ = other.value_; + if (status_.ok()) value_ = other.value_; return *this; } 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/stringpiece_unittest.cc b/src/google/protobuf/stubs/stringpiece_unittest.cc index 43737a57..a52d81f8 100644 --- a/src/google/protobuf/stubs/stringpiece_unittest.cc +++ b/src/google/protobuf/stubs/stringpiece_unittest.cc @@ -746,23 +746,6 @@ TEST(StringPiece, Comparisons2) { EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz")); } -TEST(StringPiece, HashFunction) { - hash_set<StringPiece> set; - - set.insert(StringPiece("hello")); - EXPECT_EQ(1, set.size()); - - // Insert a StringPiece of the same value again and should NOT increment - // size of the set. - set.insert(StringPiece("hello")); - EXPECT_EQ(1, set.size()); - - // Insert a StringPiece with different value and check that size of the set - // has been increment by one. - set.insert(StringPiece("world")); - EXPECT_EQ(2, set.size()); -} - TEST(ComparisonOpsTest, StringCompareNotAmbiguous) { EXPECT_EQ("hello", string("hello")); EXPECT_LT("hello", string("world")); 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.cc b/src/google/protobuf/stubs/strutil.cc index 8442f2ce..7ba92e8f 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -524,27 +524,81 @@ int CEscapeInternal(const char* src, int src_len, char* dest, return used; } -int CEscapeString(const char* src, int src_len, char* dest, int dest_len) { - return CEscapeInternal(src, src_len, dest, dest_len, false, false); +// Calculates the length of the C-style escaped version of 'src'. +// Assumes that non-printable characters are escaped using octal sequences, and +// that UTF-8 bytes are not handled specially. +static inline size_t CEscapedLength(StringPiece src) { + static char c_escaped_len[256] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", ' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + }; + + size_t escaped_len = 0; + for (int i = 0; i < src.size(); ++i) { + unsigned char c = static_cast<unsigned char>(src[i]); + escaped_len += c_escaped_len[c]; + } + return escaped_len; } // ---------------------------------------------------------------------- -// CEscape() -// CHexEscape() -// Copies 'src' to result, escaping dangerous characters using -// C-style escape sequences. This is very useful for preparing query -// flags. 'src' and 'dest' should not overlap. The 'Hex' version -// hexadecimal rather than octal sequences. -// -// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. +// Escapes 'src' using C-style escape sequences, and appends the escaped string +// to 'dest'. This version is faster than calling CEscapeInternal as it computes +// the required space using a lookup table, and also does not do any special +// handling for Hex or UTF-8 characters. // ---------------------------------------------------------------------- +void CEscapeAndAppend(StringPiece src, string* dest) { + size_t escaped_len = CEscapedLength(src); + if (escaped_len == src.size()) { + dest->append(src.data(), src.size()); + return; + } + + size_t cur_dest_len = dest->size(); + dest->resize(cur_dest_len + escaped_len); + char* append_ptr = &(*dest)[cur_dest_len]; + + for (int i = 0; i < src.size(); ++i) { + unsigned char c = static_cast<unsigned char>(src[i]); + switch (c) { + case '\n': *append_ptr++ = '\\'; *append_ptr++ = 'n'; break; + case '\r': *append_ptr++ = '\\'; *append_ptr++ = 'r'; break; + case '\t': *append_ptr++ = '\\'; *append_ptr++ = 't'; break; + case '\"': *append_ptr++ = '\\'; *append_ptr++ = '\"'; break; + case '\'': *append_ptr++ = '\\'; *append_ptr++ = '\''; break; + case '\\': *append_ptr++ = '\\'; *append_ptr++ = '\\'; break; + default: + if (!isprint(c)) { + *append_ptr++ = '\\'; + *append_ptr++ = '0' + c / 64; + *append_ptr++ = '0' + (c % 64) / 8; + *append_ptr++ = '0' + c % 8; + } else { + *append_ptr++ = c; + } + break; + } + } +} + string CEscape(const string& src) { - const int dest_length = src.size() * 4 + 1; // Maximum possible expansion - scoped_array<char> dest(new char[dest_length]); - const int len = CEscapeInternal(src.data(), src.size(), - dest.get(), dest_length, false, false); - GOOGLE_DCHECK_GE(len, 0); - return string(dest.get(), len); + string dest; + CEscapeAndAppend(src, &dest); + return dest; } namespace strings { diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index b22066b6..8bdd6110 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -314,26 +314,20 @@ LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest, LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src); // ---------------------------------------------------------------------- -// CEscapeString() -// Copies 'src' to 'dest', escaping dangerous characters using -// C-style escape sequences. This is very useful for preparing query -// flags. 'src' and 'dest' should not overlap. -// Returns the number of bytes written to 'dest' (not including the \0) -// or -1 if there was insufficient space. +// CEscape() +// Escapes 'src' using C-style escape sequences and returns the resulting +// string. // -// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. +// Escaped chars: \n, \r, \t, ", ', \, and !isprint(). // ---------------------------------------------------------------------- -LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len, - char* dest, int dest_len); +LIBPROTOBUF_EXPORT string CEscape(const string& src); // ---------------------------------------------------------------------- -// CEscape() -// More convenient form of CEscapeString: returns result as a "string". -// This version is slower than CEscapeString() because it does more -// allocation. However, it is much more convenient to use in -// non-speed-critical code like logging messages etc. +// CEscapeAndAppend() +// Escapes 'src' using C-style escape sequences, and appends the escaped +// string to 'dest'. // ---------------------------------------------------------------------- -LIBPROTOBUF_EXPORT string CEscape(const string& src); +LIBPROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, string* dest); namespace strings { // Like CEscape() but does not escape bytes with the upper bit set. @@ -654,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_; } @@ -853,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/test_util.h b/src/google/protobuf/test_util.h index d449c009..1c13a1a7 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -65,7 +65,7 @@ class TestUtil { static void SetOneof2(unittest::TestOneof2* message); // Use the repeated versions of the set_*() accessors to modify all the - // repeated fields of the messsage (which should already have been + // repeated fields of the message (which should already have been // initialized with Set*Fields()). Set*Fields() itself only tests // the add_*() accessors. static void ModifyRepeatedFields(unittest::TestAllTypes* message); diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h index f250c937..47a2269d 100644 --- a/src/google/protobuf/test_util_lite.h +++ b/src/google/protobuf/test_util_lite.h @@ -52,7 +52,7 @@ class TestUtilLite { static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message); // Use the repeated versions of the set_*() accessors to modify all the - // repeated fields of the messsage (which should already have been + // repeated fields of the message (which should already have been // initialized with Set*Fields()). Set*Fields() itself only tests // the add_*() accessors. static void ModifyRepeatedFields(unittest::TestAllTypesLite* message); diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 38b9069b..c0dfd53f 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -46,6 +46,7 @@ #include <google/protobuf/dynamic_message.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/wire_format_lite.h> +#include <google/protobuf/io/strtod.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -90,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; } @@ -100,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. @@ -116,6 +121,7 @@ string Message::Utf8DebugString() const { TextFormat::Printer printer; printer.SetUseUtf8StringEscaping(true); + printer.SetExpandAny(true); printer.PrintToString(*this, &debug_string); @@ -380,6 +386,7 @@ class TextFormat::Parser::ParserImpl { string full_type_name, prefix; DO(ConsumeAnyTypeUrl(&full_type_name, &prefix)); DO(Consume("]")); + TryConsume(":"); // ':' is optional between message labels and values. string serialized_value; DO(ConsumeAnyValue(full_type_name, message->GetDescriptor()->file()->pool(), @@ -389,7 +396,6 @@ class TextFormat::Parser::ParserImpl { string(prefix + full_type_name)); reflection->SetString(message, any_value_field, serialized_value); return true; - // Fall through. } if (TryConsume("[")) { // Extension. @@ -656,7 +662,7 @@ class TextFormat::Parser::ParserImpl { case FieldDescriptor::CPPTYPE_FLOAT: { double value; DO(ConsumeDouble(&value)); - SET_FIELD(Float, static_cast<float>(value)); + SET_FIELD(Float, io::SafeDoubleToFloat(value)); break; } @@ -1152,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'. @@ -1180,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; @@ -1357,7 +1363,10 @@ string TextFormat::FieldValuePrinter::PrintDouble(double val) const { return SimpleDtoa(val); } string TextFormat::FieldValuePrinter::PrintString(const string& val) const { - return StrCat("\"", CEscape(val), "\""); + string printed("\""); + CEscapeAndAppend(val, &printed); + printed.push_back('\"'); + return printed; } string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const { return PrintString(val); @@ -1423,7 +1432,8 @@ TextFormat::Printer::Printer() use_short_repeated_primitives_(false), hide_unknown_fields_(false), print_message_fields_in_index_order_(false), - expand_any_(false) { + expand_any_(false), + truncate_string_field_longer_than_(0LL) { SetUseUtf8StringEscaping(false); } @@ -1775,11 +1785,19 @@ void TextFormat::Printer::PrintFieldValue( ? reflection->GetRepeatedStringReference( message, field, index, &scratch) : reflection->GetStringReference(message, field, &scratch); + const string* value_to_print = &value; + 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) { - generator.Print(printer->PrintString(value)); + generator.Print(printer->PrintString(*value_to_print)); } else { GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES); - generator.Print(printer->PrintBytes(value)); + generator.Print(printer->PrintBytes(*value_to_print)); } break; } @@ -1926,14 +1944,10 @@ void TextFormat::Printer::PrintUnknownFields( } else { // This field is not parseable as a Message. // So it is probably just a plain string. - generator.Print(": \""); - generator.Print(CEscape(value)); - generator.Print("\""); - if (single_line_mode_) { - generator.Print(" "); - } else { - generator.Print("\n"); - } + string printed(": \""); + CEscapeAndAppend(value, &printed); + printed.append(single_line_mode_ ? "\" " : "\"\n"); + generator.Print(printed); } break; } diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 6717aecd..ef3d4a8f 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -219,6 +219,18 @@ class LIBPROTOBUF_EXPORT TextFormat { expand_any_ = expand; } + // If non-zero, we truncate all string fields that are longer than this + // threshold. This is useful when the proto message has very long strings, + // e.g., dump of encoded image file. + // + // NOTE(hfgong): Setting a non-zero value breaks round-trip safe + // property of TextFormat::Printer. That is, from the printed message, we + // cannot fully recover the original string field any more. + void SetTruncateStringFieldLongerThan( + const int64 truncate_string_field_longer_than) { + truncate_string_field_longer_than_ = truncate_string_field_longer_than; + } + // Register a custom field-specific FieldValuePrinter for fields // with a particular FieldDescriptor. // Returns "true" if the registration succeeded, or "false", if there is @@ -286,6 +298,8 @@ class LIBPROTOBUF_EXPORT TextFormat { bool expand_any_; + int64 truncate_string_field_longer_than_; + google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_; typedef map<const FieldDescriptor*, const FieldValuePrinter*> CustomPrinterMap; 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 2ee0ec29..7cdf5093 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/timestamp.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/timestamp.pb.h" +#include <google/protobuf/timestamp.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -82,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(\005BQ\n\023com.google.protobufB\016" - "TimestampProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Proto" - "buf.WellKnownTypesb\006proto3", 186); + "\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(); @@ -111,10 +113,10 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Timestamp::kSecondsFieldNumber; const int Timestamp::kNanosFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Timestamp::Timestamp() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -122,6 +124,14 @@ Timestamp::Timestamp() // @@protoc_insertion_point(constructor:google.protobuf.Timestamp) } +Timestamp::Timestamp(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp) +} + void Timestamp::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -147,10 +157,20 @@ Timestamp::~Timestamp() { } void Timestamp::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void Timestamp::ArenaDtor(void* object) { + Timestamp* _this = reinterpret_cast< Timestamp* >(object); + (void)_this; +} +void Timestamp::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void Timestamp::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -169,16 +189,21 @@ const Timestamp& Timestamp::default_instance() { Timestamp* Timestamp::default_instance_ = NULL; Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const { - Timestamp* n = new Timestamp; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<Timestamp>(arena); } 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,\ @@ -194,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 (;;) { @@ -286,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; @@ -309,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()); @@ -331,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); @@ -349,6 +381,18 @@ bool Timestamp::IsInitialized() const { void Timestamp::Swap(Timestamp* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + Timestamp temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void Timestamp::UnsafeArenaSwap(Timestamp* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void Timestamp::InternalSwap(Timestamp* other) { diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index 85fc1242..7bf62597 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -53,9 +53,14 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const Timestamp& default_instance(); + void UnsafeArenaSwap(Timestamp* other); void Swap(Timestamp* other); // implements Message ---------------------------------------------- @@ -82,6 +87,11 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(Timestamp* other); + protected: + explicit Timestamp(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -113,6 +123,9 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::int64 seconds_; ::google::protobuf::int32 nanos_; diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index 06b60e6f..7992a858 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -27,15 +27,18 @@ // 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"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "TimestampProto"; -option java_package = "com.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; +option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; // A Timestamp represents a point in time independent of any time zone @@ -92,6 +95,7 @@ option objc_class_prefix = "GPB"; // nanos = int((now - seconds) * 10**9) // timestamp = Timestamp(seconds=seconds, nanos=nanos) // +// message Timestamp { // Represents seconds of UTC time since Unix epoch diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 8f993561..759cab27 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/type.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/type.pb.h" +#include <google/protobuf/type.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -70,7 +71,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _is_default_instance_)); Field_descriptor_ = file->message_type(1); - static const int Field_offsets_[9] = { + static const int Field_offsets_[10] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, kind_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, cardinality_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, number_), @@ -80,6 +81,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, packed_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, json_name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, default_value_), }; Field_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -203,37 +205,37 @@ void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() { "\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc" "e_context\030\005 \001(\0132\036.google.protobuf.Source" "Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu" - "f.Syntax\"\276\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl" + "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl" "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001" "(\0162\".google.protobuf.Field.Cardinality\022\016" "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url" "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 " "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O" - "ption\022\021\n\tjson_name\030\n \001(\t\"\310\002\n\004Kind\022\020\n\014TYP" - "E_UNKNOWN\020\000\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLO" - "AT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n" - "\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_" - "FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020" - "\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nT" - "YPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENU" - "M\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020" - "\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013C" - "ardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022\030\n\024C" - "ARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY_REQ" - "UIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\316\001\n\004En" - "um\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132\032.go" - "ogle.protobuf.EnumValue\022(\n\007options\030\003 \003(\013" - "2\027.google.protobuf.Option\0226\n\016source_cont" - "ext\030\004 \001(\0132\036.google.protobuf.SourceContex" - "t\022\'\n\006syntax\030\005 \001(\0162\027.google.protobuf.Synt" - "ax\"S\n\tEnumValue\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030" - "\002 \001(\005\022(\n\007options\030\003 \003(\0132\027.google.protobuf" - ".Option\";\n\006Option\022\014\n\004name\030\001 \001(\t\022#\n\005value" - "\030\002 \001(\0132\024.google.protobuf.Any*.\n\006Syntax\022\021" - "\n\rSYNTAX_PROTO2\020\000\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023" - "com.google.protobufB\tTypeProtoP\001\240\001\001\242\002\003GP" - "B\252\002\036Google.Protobuf.WellKnownTypesb\006prot" - "o3", 1522); + "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu" + "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY" + "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6" + "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014" + "TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE" + "_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n" + "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY" + "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE" + "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020" + "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR" + "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION" + "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN" + "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022" + "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu" + "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu" + "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl" + "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016" + "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014" + "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030" + "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option" + "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p" + "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000" + "\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023com.google.protob" + "ufB\tTypeProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protob" + "uf.WellKnownTypesb\006proto3", 1545); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/type.proto", &protobuf_RegisterTypes); Type::default_instance_ = new Type(); @@ -282,14 +284,14 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Type::kNameFieldNumber; const int Type::kFieldsFieldNumber; const int Type::kOneofsFieldNumber; const int Type::kOptionsFieldNumber; const int Type::kSourceContextFieldNumber; const int Type::kSyntaxFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Type::Type() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -357,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; @@ -368,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 (;;) { @@ -601,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; @@ -653,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_); @@ -682,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); @@ -754,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()); } @@ -826,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) { @@ -902,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; @@ -967,7 +980,7 @@ bool Field_Kind_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const Field_Kind Field::TYPE_UNKNOWN; const Field_Kind Field::TYPE_DOUBLE; const Field_Kind Field::TYPE_FLOAT; @@ -990,7 +1003,7 @@ const Field_Kind Field::TYPE_SINT64; const Field_Kind Field::Kind_MIN; const Field_Kind Field::Kind_MAX; const int Field::Kind_ARRAYSIZE; -#endif // _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor() { protobuf_AssignDescriptorsOnce(); return Field_Cardinality_descriptor_; @@ -1007,7 +1020,7 @@ bool Field_Cardinality_IsValid(int value) { } } -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const Field_Cardinality Field::CARDINALITY_UNKNOWN; const Field_Cardinality Field::CARDINALITY_OPTIONAL; const Field_Cardinality Field::CARDINALITY_REQUIRED; @@ -1015,8 +1028,8 @@ const Field_Cardinality Field::CARDINALITY_REPEATED; const Field_Cardinality Field::Cardinality_MIN; const Field_Cardinality Field::Cardinality_MAX; const int Field::Cardinality_ARRAYSIZE; -#endif // _MSC_VER -#ifndef _MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Field::kKindFieldNumber; const int Field::kCardinalityFieldNumber; const int Field::kNumberFieldNumber; @@ -1026,7 +1039,8 @@ const int Field::kOneofIndexFieldNumber; const int Field::kPackedFieldNumber; const int Field::kOptionsFieldNumber; const int Field::kJsonNameFieldNumber; -#endif // !_MSC_VER +const int Field::kDefaultValueFieldNumber; +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Field::Field() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1058,6 +1072,7 @@ void Field::SharedCtor() { oneof_index_ = 0; packed_ = false; json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } Field::~Field() { @@ -1069,6 +1084,7 @@ void Field::SharedDtor() { name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (this != default_instance_) { } } @@ -1099,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,\ @@ -1113,6 +1138,7 @@ void Field::Clear() { type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); packed_ = false; json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); #undef ZR_HELPER_ #undef ZR_ @@ -1122,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 (;;) { @@ -1270,6 +1296,23 @@ bool Field::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(90)) goto parse_default_value; + break; + } + + // optional string default_value = 11; + case 11: { + if (tag == 90) { + parse_default_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_default_value())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Field.default_value")); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1361,6 +1404,16 @@ void Field::SerializeWithCachedSizes( 10, this->json_name(), output); } + // optional string default_value = 11; + if (this->default_value().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Field.default_value"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 11, this->default_value(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Field) } @@ -1434,11 +1487,23 @@ void Field::SerializeWithCachedSizes( 10, this->json_name(), target); } + // optional string default_value = 11; + if (this->default_value().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Field.default_value"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 11, this->default_value(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field) return target; } 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; @@ -1493,6 +1558,13 @@ int Field::ByteSize() const { this->json_name()); } + // optional string default_value = 11; + if (this->default_value().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->default_value()); + } + // repeated .google.protobuf.Option options = 9; total_size += 1 * this->options_size(); for (int i = 0; i < this->options_size(); i++) { @@ -1508,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) { @@ -1549,15 +1625,21 @@ void Field::MergeFrom(const Field& from) { json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_); } + if (from.default_value().size() > 0) { + + default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_); + } } 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); @@ -1582,6 +1664,7 @@ void Field::InternalSwap(Field* other) { std::swap(packed_, other->packed_); options_.UnsafeArenaSwap(&other->options_); json_name_.Swap(&other->json_name_); + default_value_.Swap(&other->default_value_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -1669,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()); } @@ -1712,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()); } @@ -1813,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()); } @@ -1826,17 +1912,61 @@ void Field::clear_json_name() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name) } +// optional string default_value = 11; +void Field::clear_default_value() { + default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + const ::std::string& Field::default_value() const { + // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value) + return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Field::set_default_value(const ::std::string& value) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value) +} + void Field::set_default_value(const char* value) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value) +} + void Field::set_default_value(const char* value, size_t size) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value) +} + ::std::string* Field::mutable_default_value() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Field.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()); +} + void Field::set_allocated_default_value(::std::string* default_value) { + if (default_value != NULL) { + + } else { + + } + default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value) +} + #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Enum::kNameFieldNumber; const int Enum::kEnumvalueFieldNumber; const int Enum::kOptionsFieldNumber; const int Enum::kSourceContextFieldNumber; const int Enum::kSyntaxFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Enum::Enum() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1904,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; @@ -1914,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 (;;) { @@ -2107,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; @@ -2152,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_); @@ -2180,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); @@ -2251,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()); } @@ -2345,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; @@ -2379,11 +2519,11 @@ void Enum::clear_syntax() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int EnumValue::kNameFieldNumber; const int EnumValue::kNumberFieldNumber; const int EnumValue::kOptionsFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 EnumValue::EnumValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2448,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(); @@ -2455,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 (;;) { @@ -2590,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; @@ -2621,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) { @@ -2645,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); @@ -2714,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()); } @@ -2775,10 +2924,10 @@ EnumValue::options() const { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Option::kNameFieldNumber; const int Option::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Option::Option() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2845,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; @@ -2852,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 (;;) { @@ -2958,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; @@ -2981,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) { @@ -3004,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); @@ -3072,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()); } @@ -3106,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 deda9213..4255fa8c 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -28,8 +28,8 @@ #include <google/protobuf/extension_set.h> #include <google/protobuf/generated_enum_reflection.h> #include <google/protobuf/unknown_field_set.h> -#include "google/protobuf/any.pb.h" -#include "google/protobuf/source_context.pb.h" +#include <google/protobuf/any.pb.h> +#include <google/protobuf/source_context.pb.h> // @@protoc_insertion_point(includes) namespace google { @@ -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); } @@ -471,6 +494,17 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { ::std::string* release_json_name(); void set_allocated_json_name(::std::string* json_name); + // optional string default_value = 11; + void clear_default_value(); + static const int kDefaultValueFieldNumber = 11; + const ::std::string& default_value() const; + void set_default_value(const ::std::string& value); + void set_default_value(const char* value); + void set_default_value(const char* value, size_t size); + ::std::string* mutable_default_value(); + ::std::string* release_default_value(); + void set_allocated_default_value(::std::string* default_value); + // @@protoc_insertion_point(class_scope:google.protobuf.Field) private: @@ -484,6 +518,7 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { ::google::protobuf::internal::ArenaStringPtr type_url_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; ::google::protobuf::internal::ArenaStringPtr json_name_; + ::google::protobuf::internal::ArenaStringPtr default_value_; bool packed_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); @@ -853,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()); } @@ -925,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) { @@ -1001,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; @@ -1107,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()); } @@ -1150,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()); } @@ -1251,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()); } @@ -1264,6 +1305,50 @@ inline void Field::set_allocated_json_name(::std::string* json_name) { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name) } +// optional string default_value = 11; +inline void Field::clear_default_value() { + default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& Field::default_value() const { + // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value) + return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Field::set_default_value(const ::std::string& value) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value) +} +inline void Field::set_default_value(const char* value) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value) +} +inline void Field::set_default_value(const char* value, size_t size) { + + default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value) +} +inline ::std::string* Field::mutable_default_value() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Field.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()); +} +inline void Field::set_allocated_default_value(::std::string* default_value) { + if (default_value != NULL) { + + } else { + + } + default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value) +} + // ------------------------------------------------------------------- // Enum @@ -1298,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()); } @@ -1392,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; @@ -1456,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()); } @@ -1547,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()); } @@ -1581,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/type.proto b/src/google/protobuf/type.proto index 4df95762..1c9cf53d 100644 --- a/src/google/protobuf/type.proto +++ b/src/google/protobuf/type.proto @@ -27,6 +27,7 @@ // 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"; package google.protobuf; @@ -34,22 +35,22 @@ package google.protobuf; import "google/protobuf/any.proto"; import "google/protobuf/source_context.proto"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "TypeProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; -// A light-weight descriptor for a proto message type. +// A protocol buffer message type. message Type { // The fully qualified message name. string name = 1; // The list of fields. repeated Field fields = 2; - // The list of oneof definitions. - repeated string oneofs = 3; // The list of oneofs declared in this Type - // The proto options. + // The list of types appearing in `oneof` definitions in this type. + repeated string oneofs = 3; + // The protocol buffer options. repeated Option options = 4; // The source context. SourceContext source_context = 5; @@ -57,9 +58,9 @@ message Type { Syntax syntax = 6; } -// Field represents a single field of a message type. +// A single field of a message type. message Field { - // Kind represents a basic field type. + // Basic field types. enum Kind { // Field type unknown. TYPE_UNKNOWN = 0; @@ -81,7 +82,7 @@ message Field { TYPE_BOOL = 8; // Field type string. TYPE_STRING = 9; - // Field type group (deprecated proto2 type) + // Field type group. Proto2 syntax only, and deprecated. TYPE_GROUP = 10; // Field type message. TYPE_MESSAGE = 11; @@ -101,38 +102,40 @@ message Field { TYPE_SINT64 = 18; }; - // Cardinality represents whether a field is optional, required, or - // repeated. + // Whether a field is optional, required, or repeated. enum Cardinality { - // The field cardinality is unknown. Typically an error condition. + // For fields with unknown cardinality. CARDINALITY_UNKNOWN = 0; // For optional fields. CARDINALITY_OPTIONAL = 1; - // For required fields. Not used for proto3. + // For required fields. Proto2 syntax only. CARDINALITY_REQUIRED = 2; // For repeated fields. CARDINALITY_REPEATED = 3; }; - // The field kind. + // The field type. Kind kind = 1; - // The field cardinality, i.e. optional/required/repeated. + // The field cardinality. Cardinality cardinality = 2; - // The proto field number. + // The field number. int32 number = 3; // The field name. string name = 4; - // The type URL (without the scheme) when the type is MESSAGE or ENUM, - // such as `type.googleapis.com/google.protobuf.Empty`. + // The field type URL, without the scheme, for message or enumeration + // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. string type_url = 6; - // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping. + // The index of the field type in `Type.oneofs`, for message or enumeration + // types. The first type has index 1; zero means the type is not in the list. int32 oneof_index = 7; // Whether to use alternative packed wire representation. bool packed = 8; - // The proto options. + // The protocol buffer options. repeated Option options = 9; - // The JSON name for this field. + // The field JSON name. string json_name = 10; + // The string value of the default value of this field. Proto2 syntax only. + string default_value = 11; } // Enum type definition. @@ -141,7 +144,7 @@ message Enum { string name = 1; // Enum value definitions. repeated EnumValue enumvalue = 2; - // Proto options for the enum type. + // Protocol buffer options. repeated Option options = 3; // The source context. SourceContext source_context = 4; @@ -155,22 +158,23 @@ message EnumValue { string name = 1; // Enum value number. int32 number = 2; - // Proto options for the enum value. + // Protocol buffer options. repeated Option options = 3; } -// Proto option attached to messages/fields/enums etc. +// A protocol buffer option, which can be attached to a message, field, +// enumeration, etc. message Option { - // Proto option name. + // The option's name. For example, `"java_package"`. string name = 1; - // Proto option value. + // The option's value. For example, `"com.google.protobuf"`. Any value = 2; } -// Syntax specifies the syntax in which a service element was defined. +// The syntax in which a protocol buffer element is defined. enum Syntax { - // Syntax "proto2" + // Syntax `proto2`. SYNTAX_PROTO2 = 0; - // Syntax "proto3" + // Syntax `proto3`. SYNTAX_PROTO3 = 1; } 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_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto index d4d6e869..4cc0e362 100644 --- a/src/google/protobuf/unittest_custom_options.proto +++ b/src/google/protobuf/unittest_custom_options.proto @@ -392,3 +392,30 @@ message NestedOptionType { optional int32 nested_extension = 7912573 [(field_opt2) = 1005]; } } + +// Custom message option that has a required enum field. +// WARNING: this is strongly discouraged! +message OldOptionType { + enum TestEnum { + OLD_VALUE = 0; + } + required TestEnum value = 1; +} + +// Updated version of the custom option above. +message NewOptionType { + enum TestEnum { + OLD_VALUE = 0; + NEW_VALUE = 1; + } + required TestEnum value = 1; +} + +extend google.protobuf.MessageOptions { + optional OldOptionType required_enum_opt = 106161807; +} + +// Test message using the "required_enum_opt" option defined above. +message TestMessageWithRequiredEnumOption { + option (required_enum_opt) = { value: OLD_VALUE }; +} 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/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto index 2cb7775c..c9075244 100644 --- a/src/google/protobuf/unittest_well_known_types.proto +++ b/src/google/protobuf/unittest_well_known_types.proto @@ -39,6 +39,8 @@ message TestWellKnownTypes { google.protobuf.BoolValue bool_field = 16; google.protobuf.StringValue string_field = 17; google.protobuf.BytesValue bytes_field = 18; + // Part of struct, but useful to be able to test separately + google.protobuf.Value value_field = 19; } // A repeated field for each well-known type. 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 ee676265..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::WithinFracionOrMargin. +// 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 748c7d11..6fd631d8 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -34,9 +34,14 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/descriptor.h> -#include <gtest/gtest.h> #include <google/protobuf/stubs/mathutil.h> - +// This gtest header is put after mathutil.h intentionally. We have to do +// this because mathutil.h includes mathlimits.h which requires cmath not +// being included to compile on some versions of gcc: +// https://github.com/google/protobuf/blob/818c5eee08840355d70d2f3bdf1a2f17986a5e70/src/google/protobuf/stubs/mathlimits.h#L48 +// 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 29ca9c1e..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, "."); @@ -103,7 +179,7 @@ class FieldMaskTree { // Add a field path into the tree. In a FieldMask, each field path matches // the specified field and also all its sub-fields. If the field path to // add is a sub-path of an existing field path in the tree (i.e., a leaf - // node), it means the tree already matchesthe the given path so nothing will + // node), it means the tree already matches the given path so nothing will // be added to the tree. If the path matches an existing non-leaf node in the // tree, that non-leaf node will be turned into a leaf node with all its // children removed because the path matches all the node's children. 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 ea360798..72c0aca6 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -35,8 +35,8 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/util/internal/utility.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/mathutil.h> #include <google/protobuf/stubs/mathlimits.h> +#include <google/protobuf/stubs/mathutil.h> namespace google { namespace protobuf { @@ -47,6 +47,7 @@ using google::protobuf::EnumDescriptor; using google::protobuf::EnumValueDescriptor; ; ; +; using util::error::Code; using util::Status; using util::StatusOr; @@ -57,13 +58,8 @@ inline Status InvalidArgument(StringPiece value_str) { return Status(util::error::INVALID_ARGUMENT, value_str); } -// For general conversion between -// int32, int64, uint32, uint64, double and float -// except conversion between double and float. template <typename To, typename From> -StatusOr<To> NumberConvertAndCheck(From before) { - if (::google::protobuf::internal::is_same<From, To>::value) return before; - To after = static_cast<To>(before); +StatusOr<To> ValidateNumberConversion(To after, From before) { if (after == before && MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) { return after; @@ -76,6 +72,27 @@ StatusOr<To> NumberConvertAndCheck(From before) { } } +// For general conversion between +// int32, int64, uint32, uint64, double and float +// except conversion between double and float. +template <typename To, typename From> +StatusOr<To> NumberConvertAndCheck(From before) { + if (::google::protobuf::internal::is_same<From, To>::value) return before; + + To after = static_cast<To>(before); + return ValidateNumberConversion(after, before); +} + +// For conversion to integer types (int32, int64, uint32, uint64) from floating +// point types (double, float) only. +template <typename To, typename From> +StatusOr<To> FloatingPointToIntConvertAndCheck(From before) { + if (::google::protobuf::internal::is_same<From, To>::value) return before; + + To after = static_cast<To>(before); + return ValidateNumberConversion(after, before); +} + // For conversion between double and float only. template <typename To, typename From> StatusOr<To> FloatingPointConvertAndCheck(From before) { @@ -96,30 +113,50 @@ StatusOr<To> FloatingPointConvertAndCheck(From before) { } // namespace StatusOr<int32> DataPiece::ToInt32() const { - if (type_ == TYPE_STRING) { - return StringToNumber<int32>(safe_strto32); - } + if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32); + + if (type_ == TYPE_DOUBLE) + return FloatingPointToIntConvertAndCheck<int32, double>(double_); + + if (type_ == TYPE_FLOAT) + return FloatingPointToIntConvertAndCheck<int32, float>(float_); + return GenericConvert<int32>(); } StatusOr<uint32> DataPiece::ToUint32() const { - if (type_ == TYPE_STRING) { - return StringToNumber<uint32>(safe_strtou32); - } + if (type_ == TYPE_STRING) return StringToNumber<uint32>(safe_strtou32); + + if (type_ == TYPE_DOUBLE) + return FloatingPointToIntConvertAndCheck<uint32, double>(double_); + + if (type_ == TYPE_FLOAT) + return FloatingPointToIntConvertAndCheck<uint32, float>(float_); + return GenericConvert<uint32>(); } StatusOr<int64> DataPiece::ToInt64() const { - if (type_ == TYPE_STRING) { - return StringToNumber<int64>(safe_strto64); - } + if (type_ == TYPE_STRING) return StringToNumber<int64>(safe_strto64); + + if (type_ == TYPE_DOUBLE) + return FloatingPointToIntConvertAndCheck<int64, double>(double_); + + if (type_ == TYPE_FLOAT) + return FloatingPointToIntConvertAndCheck<int64, float>(float_); + return GenericConvert<int64>(); } StatusOr<uint64> DataPiece::ToUint64() const { - if (type_ == TYPE_STRING) { - return StringToNumber<uint64>(safe_strtou64); - } + if (type_ == TYPE_STRING) return StringToNumber<uint64>(safe_strtou64); + + if (type_ == TYPE_DOUBLE) + return FloatingPointToIntConvertAndCheck<uint64, double>(double_); + + if (type_ == TYPE_FLOAT) + return FloatingPointToIntConvertAndCheck<uint64, float>(float_); + return GenericConvert<uint64>(); } @@ -212,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 { @@ -277,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 2ab3fa88..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_; @@ -98,7 +101,8 @@ class LIBPROTOBUF_EXPORT DataPiece { static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); } - virtual ~DataPiece() {} + virtual ~DataPiece() { + } // Accessors Type type() const { return type_; } @@ -164,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 { @@ -202,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 97b248ff..21d7a2e4 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -33,6 +33,7 @@ #include <google/protobuf/stubs/hash.h> #include <google/protobuf/util/internal/constants.h> +#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/stubs/map_util.h> namespace google { @@ -42,15 +43,28 @@ using util::Status; using util::StatusOr; namespace converter { +namespace { +// Helper function to convert string value to given data type by calling the +// passed converter function on the DataPiece created from "value" argument. +// If value is empty or if conversion fails, the default_value is returned. +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, true).*converter_fn)(); + return result.ok() ? result.ValueOrDie() : default_value; +} +} // namespace + DefaultValueObjectWriter::DefaultValueObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, ObjectWriter* ow) : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), type_(type), - disable_normalize_(false), current_(NULL), root_(NULL), + field_scrub_callback_(NULL), ow_(ow) {} DefaultValueObjectWriter::~DefaultValueObjectWriter() { @@ -140,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; } @@ -150,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; } @@ -165,23 +179,25 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( return this; } -DefaultValueObjectWriter* -DefaultValueObjectWriter::DisableCaseNormalizationForNextKey() { - disable_normalize_ = true; - 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), - disable_normalize_(false), 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) { @@ -198,10 +214,6 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( } void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { - if (disable_normalize_) { - ow->DisableCaseNormalizationForNextKey(); - } - if (kind_ == PRIMITIVE) { ObjectWriter::RenderDataPieceTo(data_, name_, ow); return; @@ -289,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 @@ -324,6 +349,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( } } } + if (!is_map && field.cardinality() == google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { @@ -336,11 +362,11 @@ void DefaultValueObjectWriter::Node::PopulateChildren( // If the child field is of primitive type, sets its data to the default // value of its type. - google::protobuf::scoped_ptr<Node> child( - new Node(field.json_name(), field_type, kind, - kind == PRIMITIVE ? CreateDefaultDataPieceForField(field) - : DataPiece::NullData(), - true)); + google::protobuf::scoped_ptr<Node> child(new Node( + field.json_name(), field_type, kind, + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) + : DataPiece::NullData(), + true, path, field_scrub_callback_)); new_children.push_back(child.release()); } // Adds all leftover nodes in children_ to the beginning of new_child. @@ -363,41 +389,69 @@ 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(), true); + + const google::protobuf::Enum* enum_type = + typeinfo->GetEnumByTypeUrl(field.type_url()); + if (!enum_type) { + GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url() + << "'"; + return DataPiece::NullData(); + } + // We treat the first value as the default if none is specified. + return enum_type->enumvalue_size() > 0 + ? DataPiece(enum_type->enumvalue(0).name(), true) + : DataPiece::NullData(); +} + DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( - const google::protobuf::Field& field) { + const google::protobuf::Field& field, const TypeInfo* typeinfo) { switch (field.kind()) { case google::protobuf::Field_Kind_TYPE_DOUBLE: { - return DataPiece(static_cast<double>(0)); + return DataPiece(ConvertTo<double>( + field.default_value(), &DataPiece::ToDouble, static_cast<double>(0))); } case google::protobuf::Field_Kind_TYPE_FLOAT: { - return DataPiece(static_cast<float>(0)); + return DataPiece(ConvertTo<float>( + field.default_value(), &DataPiece::ToFloat, static_cast<float>(0))); } case google::protobuf::Field_Kind_TYPE_INT64: case google::protobuf::Field_Kind_TYPE_SINT64: case google::protobuf::Field_Kind_TYPE_SFIXED64: { - return DataPiece(static_cast<int64>(0)); + return DataPiece(ConvertTo<int64>( + field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0))); } case google::protobuf::Field_Kind_TYPE_UINT64: case google::protobuf::Field_Kind_TYPE_FIXED64: { - return DataPiece(static_cast<uint64>(0)); + return DataPiece(ConvertTo<uint64>( + field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0))); } case google::protobuf::Field_Kind_TYPE_INT32: case google::protobuf::Field_Kind_TYPE_SINT32: case google::protobuf::Field_Kind_TYPE_SFIXED32: { - return DataPiece(static_cast<int32>(0)); + return DataPiece(ConvertTo<int32>( + field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0))); } case google::protobuf::Field_Kind_TYPE_BOOL: { - return DataPiece(false); + return DataPiece( + ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false)); } case google::protobuf::Field_Kind_TYPE_STRING: { - return DataPiece(string()); + return DataPiece(field.default_value(), true); } case google::protobuf::Field_Kind_TYPE_BYTES: { - return DataPiece("", false); + return DataPiece(field.default_value(), false, true); } case google::protobuf::Field_Kind_TYPE_UINT32: case google::protobuf::Field_Kind_TYPE_FIXED32: { - return DataPiece(static_cast<uint32>(0)); + return DataPiece(ConvertTo<uint32>( + field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0))); + } + case google::protobuf::Field_Kind_TYPE_ENUM: { + return FindEnumDefault(field, typeinfo); } default: { return DataPiece::NullData(); } } @@ -406,9 +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)); - root_->set_disable_normalize(GetAndResetDisableNormalize()); + false, path, field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; @@ -422,13 +476,14 @@ 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()); } child->set_is_placeholder(false); - child->set_disable_normalize(GetAndResetDisableNormalize()); if (child->kind() == OBJECT && child->number_of_children() == 0) { child->PopulateChildren(typeinfo_); } @@ -452,23 +507,23 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( StringPiece name) { if (current_ == NULL) { - root_.reset( - new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false)); - root_->set_disable_normalize(GetAndResetDisableNormalize()); + vector<string> path; + root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), + false, path, field_scrub_callback_.get())); current_ = root_.get(); return this; } MaybePopulateChildrenOfAny(current_); Node* child = current_->FindChild(name); if (child == NULL || child->kind() != LIST) { - GOOGLE_LOG(WARNING) << "Cannot find field '" << name << "'."; 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()); } child->set_is_placeholder(false); - child->set_disable_normalize(GetAndResetDisableNormalize()); stack_.push(current_); current_ = child; @@ -520,13 +575,14 @@ 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 { child->set_data(data); } - child->set_disable_normalize(GetAndResetDisableNormalize()); } } // namespace converter diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index bcb526e8..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,7 +118,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { virtual DefaultValueObjectWriter* RenderNull(StringPiece name); - virtual DefaultValueObjectWriter* DisableCaseNormalizationForNextKey(); + // 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 { @@ -113,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]; @@ -139,21 +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; } - void set_disable_normalize(bool disable_normalize) { - disable_normalize_ = disable_normalize; - } - - bool is_any() { return is_any_; } + bool is_any() const { return is_any_; } void set_is_any(bool is_any) { is_any_ = is_any; } @@ -176,8 +197,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { const google::protobuf::Type* type_; // The kind of this node. NodeKind kind_; - // Whether to disable case normalization of the name. - bool disable_normalize_; // Whether this is a node for "Any". bool is_any_; // The data of this node when it is a leaf node. @@ -189,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 @@ -201,16 +229,17 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Creates a DataPiece containing the default value of the type of the field. static DataPiece CreateDefaultDataPieceForField( - const google::protobuf::Field& field); - - // Returns disable_normalize_ and reset it to false. - bool GetAndResetDisableNormalize() { - return disable_normalize_ ? (disable_normalize_ = false, true) : false; - } + const google::protobuf::Field& field, const TypeInfo* typeinfo); // Adds or replaces the data_ of a primitive child node. void RenderDataPiece(StringPiece name, const DataPiece& data); + // Returns the default enum value as a DataPiece, or the first enum value if + // there is no default. For proto3, where we cannot specify an explicit + // default, a zero value will always be returned. + static DataPiece FindEnumDefault(const google::protobuf::Field& field, + const TypeInfo* typeinfo); + // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. const TypeInfo* typeinfo_; @@ -221,8 +250,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Holds copies of strings passed to RenderString. vector<string*> string_values_; - // Whether to disable case normalization of the next node. - bool disable_normalize_; // The current Node. Owned by its parents. Node* current_; // The root Node. @@ -230,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/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc index 237d0722..8254c0fa 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc @@ -43,21 +43,19 @@ namespace testing { using google::protobuf::testing::DefaultValueTest; -// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are -// in the marshalling_test.cc and translator_integration_test.cc. -class DefaultValueObjectWriterTest +// Base class for setting up required state for running default values tests on +// different descriptors. +class BaseDefaultValueObjectWriterTest : public ::testing::TestWithParam<testing::TypeInfoSource> { protected: - DefaultValueObjectWriterTest() + explicit BaseDefaultValueObjectWriterTest(const Descriptor* descriptor) : helper_(GetParam()), mock_(), expects_(&mock_) { - helper_.ResetTypeInfo(DefaultValueTest::descriptor()); + helper_.ResetTypeInfo(descriptor); testing_.reset(helper_.NewDefaultValueWriter( - string(kTypeServiceBaseUrl) + "/" + - DefaultValueTest::descriptor()->full_name(), - &mock_)); + string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(), &mock_)); } - virtual ~DefaultValueObjectWriterTest() {} + virtual ~BaseDefaultValueObjectWriterTest() {} TypeInfoTestHelper helper_; MockObjectWriter mock_; @@ -65,6 +63,15 @@ class DefaultValueObjectWriterTest google::protobuf::scoped_ptr<DefaultValueObjectWriter> testing_; }; +// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are +// in the marshalling_test.cc and translator_integration_test.cc. +class DefaultValueObjectWriterTest : public BaseDefaultValueObjectWriterTest { + protected: + DefaultValueObjectWriterTest() + : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {} + virtual ~DefaultValueObjectWriterTest() {} +}; + INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, DefaultValueObjectWriterTest, ::testing::Values( @@ -74,6 +81,8 @@ TEST_P(DefaultValueObjectWriterTest, Empty) { // Set expectation expects_.StartObject("") ->RenderDouble("doubleValue", 0.0) + ->StartList("repeatedDouble") + ->EndList() ->RenderFloat("floatValue", 0.0) ->RenderInt64("int64Value", 0) ->RenderUint64("uint64Value", 0) @@ -82,6 +91,7 @@ TEST_P(DefaultValueObjectWriterTest, Empty) { ->RenderBool("boolValue", false) ->RenderString("stringValue", "") ->RenderBytes("bytesValue", "") + ->RenderString("enumValue", "ENUM_FIRST") ->EndObject(); // Actual testing @@ -92,6 +102,8 @@ TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) { // Set expectation expects_.StartObject("") ->RenderDouble("doubleValue", 1.0) + ->StartList("repeatedDouble") + ->EndList() ->RenderFloat("floatValue", 0.0) ->RenderInt64("int64Value", 0) ->RenderUint64("uint64Value", 0) @@ -99,6 +111,7 @@ TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) { ->RenderUint32("uint32Value", 0) ->RenderBool("boolValue", false) ->RenderString("stringValue", "") + ->RenderString("enumValue", "ENUM_FIRST") ->EndObject(); // Actual testing @@ -109,6 +122,8 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { // Set expectation expects_.StartObject("") ->RenderDouble("doubleValue", 1.0) + ->StartList("repeatedDouble") + ->EndList() ->RenderFloat("floatValue", 0.0) ->RenderInt64("int64Value", 0) ->RenderUint64("uint64Value", 0) @@ -120,6 +135,7 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { ->StartObject("unknownObject") ->RenderString("unknown", "def") ->EndObject() + ->RenderString("enumValue", "ENUM_FIRST") ->EndObject(); // Actual testing @@ -132,6 +148,7 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { ->EndObject(); } + } // namespace testing } // namespace converter } // namespace util diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h index 2699684d..3f063936 100644 --- a/src/google/protobuf/util/internal/error_listener.h +++ b/src/google/protobuf/util/internal/error_listener.h @@ -31,11 +31,13 @@ #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__ +#include <algorithm> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif #include <string> +#include <vector> #include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc index 36dc8ef9..24bd554e 100644 --- a/src/google/protobuf/util/internal/json_escaping.cc +++ b/src/google/protobuf/util/internal/json_escaping.cc @@ -186,7 +186,7 @@ bool ReadCodePoint(StringPiece str, int index, uint32 *cp, int* num_left, int *num_read) { if (*num_left == 0) { // Last read was complete. Start reading a new unicode code point. - *cp = str[index++]; + *cp = static_cast<uint8>(str[index++]); *num_read = 1; // The length of the code point is determined from reading the first byte. // @@ -235,7 +235,7 @@ bool ReadCodePoint(StringPiece str, int index, *num_read = 0; } while (*num_left > 0 && index < str.size()) { - uint32 ch = str[index++]; + uint32 ch = static_cast<uint8>(str[index++]); --(*num_left); ++(*num_read); *cp = (*cp << 6) | (ch & 0x3f); 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 dcd60601..b87b06ac 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -47,8 +47,7 @@ class JsonObjectWriterTest : public ::testing::Test { JsonObjectWriterTest() : str_stream_(new StringOutputStream(&output_)), out_stream_(new CodedOutputStream(str_stream_)), - ow_(NULL) { - } + ow_(NULL) {} virtual ~JsonObjectWriterTest() { delete ow_; @@ -59,41 +58,39 @@ class JsonObjectWriterTest : public ::testing::Test { string output_; StringOutputStream* const str_stream_; CodedOutputStream* const out_stream_; - ObjectWriter* ow_; + JsonObjectWriter* ow_; }; TEST_F(JsonObjectWriterTest, EmptyRootObject) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->EndObject(); + ow_->StartObject("")->EndObject(); EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartObject("empty") - ->EndObject() - ->EndObject(); + ->RenderString("test", "value") + ->StartObject("empty") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyRootList) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("") - ->EndList(); + ow_->StartList("")->EndList(); EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartList("empty") - ->EndList() - ->EndObject(); + ->RenderString("test", "value") + ->StartList("empty") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", output_.substr(0, out_stream_->ByteCount())); } @@ -101,10 +98,10 @@ TEST_F(JsonObjectWriterTest, EmptyList) { TEST_F(JsonObjectWriterTest, ObjectInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartObject("nested") - ->RenderString("field", "value") - ->EndObject() - ->EndObject(); + ->StartObject("nested") + ->RenderString("field", "value") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", output_.substr(0, out_stream_->ByteCount())); } @@ -112,10 +109,10 @@ TEST_F(JsonObjectWriterTest, ObjectInObject) { TEST_F(JsonObjectWriterTest, ListInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartList("nested") - ->RenderString("", "value") - ->EndList() - ->EndObject(); + ->StartList("nested") + ->RenderString("", "value") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"nested\":[\"value\"]}", output_.substr(0, out_stream_->ByteCount())); } @@ -123,10 +120,10 @@ TEST_F(JsonObjectWriterTest, ListInObject) { TEST_F(JsonObjectWriterTest, ObjectInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartObject("") - ->RenderString("field", "value") - ->EndObject() - ->EndList(); + ->StartObject("") + ->RenderString("field", "value") + ->EndObject() + ->EndList(); EXPECT_EQ("[{\"field\":\"value\"}]", output_.substr(0, out_stream_->ByteCount())); } @@ -134,10 +131,10 @@ TEST_F(JsonObjectWriterTest, ObjectInList) { TEST_F(JsonObjectWriterTest, ListInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartList("") - ->RenderString("", "value") - ->EndList() - ->EndList(); + ->StartList("") + ->RenderString("", "value") + ->EndList() + ->EndList(); EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount())); } @@ -156,14 +153,18 @@ TEST_F(JsonObjectWriterTest, RenderPrimitives) { ->EndObject(); EXPECT_EQ( "{\"bool\":true," - "\"double\":" + ValueAsString<double>(1.7976931348623157e+308) + "," - "\"float\":" + ValueAsString<float>(3.4028235e+38) + "," - "\"int\":-2147483648," - "\"long\":\"-9223372036854775808\"," - "\"bytes\":\"YWJyYWNhZGFicmE=\"," - "\"string\":\"string\"," - "\"emptybytes\":\"\"," - "\"emptystring\":\"\"}", + "\"double\":" + + ValueAsString<double>(std::numeric_limits<double>::max()) + + "," + "\"float\":" + + ValueAsString<float>(std::numeric_limits<float>::max()) + + "," + "\"int\":-2147483648," + "\"long\":\"-9223372036854775808\"," + "\"bytes\":\"YWJyYWNhZGFicmE=\"," + "\"string\":\"string\"," + "\"emptybytes\":\"\"," + "\"emptystring\":\"\"}", output_.substr(0, out_stream_->ByteCount())); } @@ -181,81 +182,83 @@ TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { TEST_F(JsonObjectWriterTest, PrettyPrintList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("items") - ->RenderString("", "item1") - ->RenderString("", "item2") - ->RenderString("", "item3") - ->EndList() - ->StartList("empty") - ->EndList() - ->EndObject(); - EXPECT_EQ("{\n" - " \"items\": [\n" - " \"item1\",\n" - " \"item2\",\n" - " \"item3\"\n" - " ],\n" - " \"empty\": []\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("items") + ->RenderString("", "item1") + ->RenderString("", "item2") + ->RenderString("", "item3") + ->EndList() + ->StartList("empty") + ->EndList() + ->EndObject(); + EXPECT_EQ( + "{\n" + " \"items\": [\n" + " \"item1\",\n" + " \"item2\",\n" + " \"item3\"\n" + " ],\n" + " \"empty\": []\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintObject) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartObject("items") - ->RenderString("key1", "item1") - ->RenderString("key2", "item2") - ->RenderString("key3", "item3") - ->EndObject() - ->StartObject("empty") - ->EndObject() - ->EndObject(); - EXPECT_EQ("{\n" - " \"items\": {\n" - " \"key1\": \"item1\",\n" - " \"key2\": \"item2\",\n" - " \"key3\": \"item3\"\n" - " },\n" - " \"empty\": {}\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartObject("items") + ->RenderString("key1", "item1") + ->RenderString("key2", "item2") + ->RenderString("key3", "item3") + ->EndObject() + ->StartObject("empty") + ->EndObject() + ->EndObject(); + EXPECT_EQ( + "{\n" + " \"items\": {\n" + " \"key1\": \"item1\",\n" + " \"key2\": \"item2\",\n" + " \"key3\": \"item3\"\n" + " },\n" + " \"empty\": {}\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("list") - ->StartObject("") - ->EndObject() - ->EndList() - ->EndObject(); - EXPECT_EQ("{\n" - " \"list\": [\n" - " {}\n" - " ]\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("list") + ->StartObject("") + ->EndObject() + ->EndList() + ->EndObject(); + EXPECT_EQ( + "{\n" + " \"list\": [\n" + " {}\n" + " ]\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->RenderBool("bool", true) - ->RenderInt32("int", 42) - ->EndObject(); - EXPECT_EQ("{\n" - " \"bool\": true,\n" - " \"int\": 42\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->RenderBool("bool", true) + ->RenderInt32("int", 42) + ->EndObject(); + EXPECT_EQ( + "{\n" + " \"bool\": true,\n" + " \"int\": 42\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderString("string", "'<>&\\\"\r\n") - ->EndObject(); + ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", output_.substr(0, out_stream_->ByteCount())); } @@ -263,13 +266,13 @@ TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { TEST_F(JsonObjectWriterTest, Stringification) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN()) - ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN()) - ->RenderDouble("double_pos", std::numeric_limits<double>::infinity()) - ->RenderFloat("float_pos", std::numeric_limits<float>::infinity()) - ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity()) - ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity()) - ->EndObject(); + ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN()) + ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN()) + ->RenderDouble("double_pos", std::numeric_limits<double>::infinity()) + ->RenderFloat("float_pos", std::numeric_limits<float>::infinity()) + ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity()) + ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity()) + ->EndObject(); EXPECT_EQ( "{\"double_nan\":\"NaN\"," "\"float_nan\":\"NaN\"," @@ -280,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 a7ef7fe2..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. @@ -157,10 +158,10 @@ util::Status JsonStreamParser::FinishParse() { char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' '); p_ = json_ = StringPiece(coerced, leftover_.size()); } else { + p_ = json_ = leftover_; if (!internal::IsStructurallyValidUTF8(leftover_)) { return ReportFailure("Encountered non UTF-8 code points."); } - p_ = json_ = leftover_; } // Parse the remainder in finishing mode, which reports errors for things like @@ -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 c833ed1f..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 = "\"\""; @@ -348,21 +375,65 @@ TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { for (int i = 0; i <= json.length(); ++i) { DoErrorTest(json, i, "Encountered non UTF-8 code points."); } + 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) { @@ -628,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"; @@ -636,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) { @@ -643,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 20bd3627..9f07363d 100644 --- a/src/google/protobuf/util/internal/object_writer.h +++ b/src/google/protobuf/util/internal/object_writer.h @@ -101,19 +101,31 @@ class LIBPROTOBUF_EXPORT ObjectWriter { // Renders a Null value. virtual ObjectWriter* RenderNull(StringPiece name) = 0; - // Disables case normalization. Any RenderTYPE call after calling this - // function will output the name field as-is. No normalization is attempted on - // it. This setting is reset immediately after the next RenderTYPE is called. - virtual ObjectWriter* DisableCaseNormalizationForNextKey() { return this; } - // Renders a DataPiece object to a 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 new file mode 100644 index 00000000..36b79410 --- /dev/null +++ b/src/google/protobuf/util/internal/proto_writer.cc @@ -0,0 +1,762 @@ +// 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/util/internal/proto_writer.h> + +#include <functional> +#include <stack> + +#include <google/protobuf/stubs/once.h> +#include <google/protobuf/stubs/time.h> +#include <google/protobuf/wire_format_lite.h> +#include <google/protobuf/util/internal/field_mask_utility.h> +#include <google/protobuf/util/internal/object_location_tracker.h> +#include <google/protobuf/util/internal/constants.h> +#include <google/protobuf/util/internal/utility.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/map_util.h> +#include <google/protobuf/stubs/statusor.h> + + +namespace google { +namespace protobuf { +namespace util { +namespace converter { + +using google::protobuf::internal::WireFormatLite; +using google::protobuf::io::CodedOutputStream; +using util::error::INVALID_ARGUMENT; +using util::Status; +using util::StatusOr; + + +ProtoWriter::ProtoWriter(TypeResolver* type_resolver, + const google::protobuf::Type& type, + strings::ByteSink* output, ErrorListener* listener) + : master_type_(type), + typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), + own_typeinfo_(true), + done_(false), + element_(NULL), + size_insert_(), + output_(output), + buffer_(), + adapter_(&buffer_), + stream_(new CodedOutputStream(&adapter_)), + listener_(listener), + invalid_depth_(0), + tracker_(new ObjectLocationTracker()) {} + +ProtoWriter::ProtoWriter(const TypeInfo* typeinfo, + const google::protobuf::Type& type, + strings::ByteSink* output, ErrorListener* listener) + : master_type_(type), + typeinfo_(typeinfo), + own_typeinfo_(false), + done_(false), + element_(NULL), + size_insert_(), + output_(output), + buffer_(), + adapter_(&buffer_), + stream_(new CodedOutputStream(&adapter_)), + listener_(listener), + invalid_depth_(0), + tracker_(new ObjectLocationTracker()) {} + +ProtoWriter::~ProtoWriter() { + if (own_typeinfo_) { + delete typeinfo_; + } + if (element_ == NULL) return; + // Cleanup explicitly in order to avoid destructor stack overflow when input + // is deeply nested. + // Cast to BaseElement to avoid doing additional checks (like missing fields) + // during pop(). + google::protobuf::scoped_ptr<BaseElement> element( + static_cast<BaseElement*>(element_.get())->pop<BaseElement>()); + while (element != NULL) { + element.reset(element->pop<BaseElement>()); + } +} + +namespace { + +// Writes an INT32 field, including tag to the stream. +inline Status WriteInt32(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int32> i32 = data.ToInt32(); + if (i32.ok()) { + WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream); + } + return i32.status(); +} + +// writes an SFIXED32 field, including tag, to the stream. +inline Status WriteSFixed32(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int32> i32 = data.ToInt32(); + if (i32.ok()) { + WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream); + } + return i32.status(); +} + +// Writes an SINT32 field, including tag, to the stream. +inline Status WriteSInt32(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int32> i32 = data.ToInt32(); + if (i32.ok()) { + WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream); + } + return i32.status(); +} + +// Writes a FIXED32 field, including tag, to the stream. +inline Status WriteFixed32(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<uint32> u32 = data.ToUint32(); + if (u32.ok()) { + WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream); + } + return u32.status(); +} + +// Writes a UINT32 field, including tag, to the stream. +inline Status WriteUInt32(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<uint32> u32 = data.ToUint32(); + if (u32.ok()) { + WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream); + } + return u32.status(); +} + +// Writes an INT64 field, including tag, to the stream. +inline Status WriteInt64(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int64> i64 = data.ToInt64(); + if (i64.ok()) { + WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream); + } + return i64.status(); +} + +// Writes an SFIXED64 field, including tag, to the stream. +inline Status WriteSFixed64(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int64> i64 = data.ToInt64(); + if (i64.ok()) { + WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream); + } + return i64.status(); +} + +// Writes an SINT64 field, including tag, to the stream. +inline Status WriteSInt64(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<int64> i64 = data.ToInt64(); + if (i64.ok()) { + WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream); + } + return i64.status(); +} + +// Writes a FIXED64 field, including tag, to the stream. +inline Status WriteFixed64(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<uint64> u64 = data.ToUint64(); + if (u64.ok()) { + WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream); + } + return u64.status(); +} + +// Writes a UINT64 field, including tag, to the stream. +inline Status WriteUInt64(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<uint64> u64 = data.ToUint64(); + if (u64.ok()) { + WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream); + } + return u64.status(); +} + +// Writes a DOUBLE field, including tag, to the stream. +inline Status WriteDouble(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<double> d = data.ToDouble(); + if (d.ok()) { + WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream); + } + return d.status(); +} + +// Writes a FLOAT field, including tag, to the stream. +inline Status WriteFloat(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<float> f = data.ToFloat(); + if (f.ok()) { + WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream); + } + return f.status(); +} + +// Writes a BOOL field, including tag, to the stream. +inline Status WriteBool(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<bool> b = data.ToBool(); + if (b.ok()) { + WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream); + } + return b.status(); +} + +// Writes a BYTES field, including tag, to the stream. +inline Status WriteBytes(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<string> c = data.ToBytes(); + if (c.ok()) { + WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream); + } + return c.status(); +} + +// Writes a STRING field, including tag, to the stream. +inline Status WriteString(int field_number, const DataPiece& data, + CodedOutputStream* stream) { + StatusOr<string> s = data.ToString(); + if (s.ok()) { + WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream); + } + return s.status(); +} + +// Writes an ENUM field, including tag, to the stream. +inline Status WriteEnum(int field_number, const DataPiece& data, + const google::protobuf::Enum* enum_type, + CodedOutputStream* stream) { + StatusOr<int> e = data.ToEnum(enum_type); + if (e.ok()) { + WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); + } + return e.status(); +} + +// Given a google::protobuf::Type, returns the set of all required fields. +std::set<const google::protobuf::Field*> GetRequiredFields( + const google::protobuf::Type& type) { + std::set<const google::protobuf::Field*> required; + for (int i = 0; i < type.fields_size(); i++) { + const google::protobuf::Field& field = type.fields(i); + if (field.cardinality() == + google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { + required.insert(&field); + } + } + return required; +} + +} // namespace + +ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo, + const google::protobuf::Type& type, + ProtoWriter* enclosing) + : BaseElement(NULL), + ow_(enclosing), + parent_field_(NULL), + typeinfo_(typeinfo), + type_(type), + required_fields_(GetRequiredFields(type)), + size_index_(-1), + array_index_(-1) {} + +ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent, + const google::protobuf::Field* field, + const google::protobuf::Type& type, + bool is_list) + : BaseElement(parent), + ow_(this->parent()->ow_), + parent_field_(field), + typeinfo_(this->parent()->typeinfo_), + type_(type), + size_index_( + !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE + ? ow_->size_insert_.size() + : -1), + array_index_(is_list ? 0 : -1) { + if (!is_list) { + if (ow_->IsRepeated(*field)) { + // Update array_index_ if it is an explicit list. + if (this->parent()->array_index_ >= 0) this->parent()->array_index_++; + } else { + this->parent()->RegisterField(field); + } + + if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { + required_fields_ = GetRequiredFields(type_); + int start_pos = ow_->stream_->ByteCount(); + // length of serialized message is the final buffer position minus + // starting buffer position, plus length adjustments for size fields + // of any nested messages. We start with -start_pos here, so we only + // need to add the final buffer position to it at the end. + SizeInfo info = {start_pos, -start_pos}; + ow_->size_insert_.push_back(info); + } + } +} + +ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() { + // Calls the registered error listener for any required field(s) not yet + // seen. + for (set<const google::protobuf::Field*>::iterator it = + required_fields_.begin(); + it != required_fields_.end(); ++it) { + ow_->MissingField((*it)->name()); + } + // Computes the total number of proto bytes used by a message, also adjusts + // the size of all parent messages by the length of this size field. + // If size_index_ < 0, this is not a message, so no size field is added. + if (size_index_ >= 0) { + // Add the final buffer position to compute the total length of this + // serialized message. The stored value (before this addition) already + // contains the total length of the size fields of all nested messages + // minus the initial buffer position. + ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount(); + // Calculate the length required to serialize the size field of the + // message, and propagate this additional size information upward to + // all enclosing messages. + int size = ow_->size_insert_[size_index_].size; + int length = CodedOutputStream::VarintSize32(size); + for (ProtoElement* e = parent(); e != NULL; e = e->parent()) { + // Only nested messages have size field, lists do not have size field. + if (e->size_index_ >= 0) { + ow_->size_insert_[e->size_index_].size += length; + } + } + } + return BaseElement::pop<ProtoElement>(); +} + +void ProtoWriter::ProtoElement::RegisterField( + const google::protobuf::Field* field) { + if (!required_fields_.empty() && + field->cardinality() == + google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { + required_fields_.erase(field); + } +} + +string ProtoWriter::ProtoElement::ToString() const { + if (parent() == NULL) return ""; + string loc = parent()->ToString(); + if (!ow_->IsRepeated(*parent_field_) || + parent()->parent_field_ != parent_field_) { + string name = parent_field_->name(); + int i = 0; + while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i; + if (i > 0 && i == name.size()) { // safe field name + if (loc.empty()) { + loc = name; + } else { + StrAppend(&loc, ".", name); + } + } else { + StrAppend(&loc, "[\"", CEscape(name), "\"]"); + } + } + if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) { + StrAppend(&loc, "[", array_index_ - 1, "]"); + } + return loc.empty() ? "." : loc; +} + +bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) { + return ContainsKey(oneof_indices_, index); +} + +void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) { + InsertIfNotPresent(&oneof_indices_, index); +} + +void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) { + listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); +} + +void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) { + listener_->InvalidValue(location(), type_name, value); +} + +void ProtoWriter::MissingField(StringPiece missing_name) { + listener_->MissingField(location(), missing_name); +} + +ProtoWriter* ProtoWriter::StartObject(StringPiece name) { + // Starting the root message. Create the root ProtoElement and return. + if (element_ == NULL) { + if (!name.empty()) { + InvalidName(name, "Root element should not be named."); + } + element_.reset(new ProtoElement(typeinfo_, master_type_, this)); + return this; + } + + const google::protobuf::Field* field = NULL; + field = BeginNamed(name, false); + if (field == NULL) return this; + + // Check to see if this field is a oneof and that no oneof in that group has + // already been set. + if (!ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + + const google::protobuf::Type* type = LookupType(field); + if (type == NULL) { + ++invalid_depth_; + InvalidName(name, + StrCat("Missing descriptor for field: ", field->type_url())); + return this; + } + + return StartObjectField(*field, *type); +} + +ProtoWriter* ProtoWriter::EndObject() { + if (invalid_depth_ > 0) { + --invalid_depth_; + return this; + } + + if (element_ != NULL) { + element_.reset(element_->pop()); + } + + + // If ending the root element, + // then serialize the full message with calculated sizes. + if (element_ == NULL) { + WriteRootMessage(); + } + return this; +} + +ProtoWriter* ProtoWriter::StartList(StringPiece name) { + const google::protobuf::Field* field = BeginNamed(name, true); + if (field == NULL) return this; + + if (!ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + + const google::protobuf::Type* type = LookupType(field); + if (type == NULL) { + ++invalid_depth_; + InvalidName(name, + StrCat("Missing descriptor for field: ", field->type_url())); + return this; + } + + return StartListField(*field, *type); +} + +ProtoWriter* ProtoWriter::EndList() { + if (invalid_depth_ > 0) { + --invalid_depth_; + } else if (element_ != NULL) { + element_.reset(element_->pop()); + } + return this; +} + +ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, + const DataPiece& data) { + Status status; + if (invalid_depth_ > 0) return this; + + const google::protobuf::Field* field = Lookup(name); + if (field == NULL) return this; + + if (!ValidOneof(*field, name)) return this; + + const google::protobuf::Type* type = LookupType(field); + if (type == NULL) { + InvalidName(name, + StrCat("Missing descriptor for field: ", field->type_url())); + 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)); + + 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()) { + case google::protobuf::Field_Kind_TYPE_INT32: { + status = WriteInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SFIXED32: { + status = WriteSFixed32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SINT32: { + status = WriteSInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FIXED32: { + status = WriteFixed32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_UINT32: { + status = WriteUInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_INT64: { + status = WriteInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SFIXED64: { + status = WriteSFixed64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SINT64: { + status = WriteSInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FIXED64: { + status = WriteFixed64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_UINT64: { + status = WriteUInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_DOUBLE: { + status = WriteDouble(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FLOAT: { + status = WriteFloat(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_BOOL: { + status = WriteBool(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_BYTES: { + status = WriteBytes(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_STRING: { + 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()), + stream_.get()); + break; + } + default: // TYPE_GROUP or TYPE_MESSAGE + status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); + } + + if (!status.ok()) { + InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), + status.error_message()); + } + + element_.reset(element()->pop()); + return this; +} + +const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, + bool is_list) { + if (invalid_depth_ > 0) { + ++invalid_depth_; + return NULL; + } + const google::protobuf::Field* field = Lookup(name); + if (field == NULL) { + ++invalid_depth_; + // InvalidName() already called in Lookup(). + return NULL; + } + if (is_list && !IsRepeated(*field)) { + ++invalid_depth_; + InvalidName(name, "Proto field is not repeating, cannot start list."); + return NULL; + } + return field; +} + +const google::protobuf::Field* ProtoWriter::Lookup( + StringPiece unnormalized_name) { + ProtoElement* e = element(); + if (e == NULL) { + InvalidName(unnormalized_name, "Root element must be a message."); + return NULL; + } + if (unnormalized_name.empty()) { + // Objects in repeated field inherit the same field descriptor. + if (e->parent_field() == NULL) { + InvalidName(unnormalized_name, "Proto fields must have a name."); + } else if (!IsRepeated(*e->parent_field())) { + InvalidName(unnormalized_name, "Proto fields must have a name."); + return NULL; + } + return e->parent_field(); + } + const google::protobuf::Field* field = + typeinfo_->FindField(&e->type(), unnormalized_name); + if (field == NULL) InvalidName(unnormalized_name, "Cannot find field."); + return field; +} + +const google::protobuf::Type* ProtoWriter::LookupType( + const google::protobuf::Field* field) { + return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE || + field->kind() == google::protobuf::Field_Kind_TYPE_GROUP) + ? typeinfo_->GetTypeByTypeUrl(field->type_url()) + : &element_->type()); +} + +void ProtoWriter::WriteRootMessage() { + GOOGLE_DCHECK(!done_); + int curr_pos = 0; + // Calls the destructor of CodedOutputStream to remove any uninitialized + // memory from the Cord before we read it. + stream_.reset(NULL); + const void* data; + int length; + google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size()); + while (input_stream.Next(&data, &length)) { + if (length == 0) continue; + int num_bytes = length; + // Write up to where we need to insert the size field. + // The number of bytes we may write is the smaller of: + // - the current fragment size + // - the distance to the next position where a size field needs to be + // inserted. + if (!size_insert_.empty() && + size_insert_.front().pos - curr_pos < num_bytes) { + num_bytes = size_insert_.front().pos - curr_pos; + } + output_->Append(static_cast<const char*>(data), num_bytes); + if (num_bytes < length) { + input_stream.BackUp(length - num_bytes); + } + curr_pos += num_bytes; + // Insert the size field. + // size_insert_.front(): the next <index, size> pair to be written. + // size_insert_.front().pos: position of the size field. + // size_insert_.front().size: the size (integer) to be inserted. + if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) { + // Varint32 occupies at most 10 bytes. + uint8 insert_buffer[10]; + uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray( + size_insert_.front().size, insert_buffer); + output_->Append(reinterpret_cast<const char*>(insert_buffer), + insert_buffer_pos - insert_buffer); + size_insert_.pop_front(); + } + } + output_->Flush(); + stream_.reset(new CodedOutputStream(&adapter_)); + done_ = true; +} + +void ProtoWriter::WriteTag(const google::protobuf::Field& field) { + WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( + static_cast<WireFormatLite::FieldType>(field.kind())); + stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); +} + + +} // namespace converter +} // namespace util +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h new file mode 100644 index 00000000..957565e7 --- /dev/null +++ b/src/google/protobuf/util/internal/proto_writer.h @@ -0,0 +1,330 @@ +// 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_UTIL_CONVERTER_PROTO_WRITER_H__ +#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__ + +#include <deque> +#include <google/protobuf/stubs/hash.h> +#include <string> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/util/internal/type_info.h> +#include <google/protobuf/util/internal/datapiece.h> +#include <google/protobuf/util/internal/error_listener.h> +#include <google/protobuf/util/internal/structured_objectwriter.h> +#include <google/protobuf/util/type_resolver.h> +#include <google/protobuf/stubs/bytestream.h> + +namespace google { +namespace protobuf { +namespace io { +class CodedOutputStream; +} // namespace io +} // namespace protobuf + + +namespace protobuf { +class Type; +class Field; +} // namespace protobuf + + +namespace protobuf { +namespace util { +namespace converter { + +class ObjectLocationTracker; + +// An ObjectWriter that can write protobuf bytes directly from writer events. +// This class does not support special types like Struct or Map. However, since +// this class supports raw protobuf, it can be used to provide support for +// special types by inheriting from it or by wrapping it. +// +// It also supports streaming. +class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { + public: +// Constructor. Does not take ownership of any parameter passed in. + ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, + strings::ByteSink* output, ErrorListener* listener); + virtual ~ProtoWriter(); + + // ObjectWriter methods. + virtual ProtoWriter* StartObject(StringPiece name); + virtual ProtoWriter* EndObject(); + virtual ProtoWriter* StartList(StringPiece name); + virtual ProtoWriter* EndList(); + virtual ProtoWriter* RenderBool(StringPiece name, bool value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderDouble(StringPiece name, double value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderFloat(StringPiece name, float value) { + return RenderDataPiece(name, DataPiece(value)); + } + virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) { + return RenderDataPiece(name, + DataPiece(value, use_strict_base64_decoding())); + } + virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { + return RenderDataPiece( + name, DataPiece(value, false, use_strict_base64_decoding())); + } + virtual ProtoWriter* RenderNull(StringPiece name) { + return RenderDataPiece(name, DataPiece::NullData()); + } + + // Renders a DataPiece 'value' into a field whose wire type is determined + // from the given field 'name'. + virtual ProtoWriter* RenderDataPiece(StringPiece name, + const DataPiece& value); + + // Returns the location tracker to use for tracking locations for errors. + const LocationTrackerInterface& location() { + return element_ != NULL ? *element_ : *tracker_; + } + + // When true, we finished writing to output a complete message. + bool done() { return done_; } + + // Returns the proto stream object. + google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); } + + // Getters and mutators of invalid_depth_. + void IncrementInvalidDepth() { ++invalid_depth_; } + void DecrementInvalidDepth() { --invalid_depth_; } + int invalid_depth() { return invalid_depth_; } + + ErrorListener* listener() { return listener_; } + + const TypeInfo* typeinfo() { return typeinfo_; } + + protected: + class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface { + public: + // Constructor for the root element. No parent nor field. + ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, + ProtoWriter* enclosing); + + // Constructor for a field of an element. + ProtoElement(ProtoElement* parent, const google::protobuf::Field* field, + const google::protobuf::Type& type, bool is_list); + + virtual ~ProtoElement() {} + + // Called just before the destructor for clean up: + // - reports any missing required fields + // - computes the space needed by the size field, and augment the + // length of all parent messages by this additional space. + // - releases and returns the parent pointer. + ProtoElement* pop(); + + // Accessors + // parent_field() may be NULL if we are at root. + const google::protobuf::Field* parent_field() const { + return parent_field_; + } + const google::protobuf::Type& type() const { return type_; } + + // Registers field for accounting required fields. + void RegisterField(const google::protobuf::Field* field); + + // To report location on error messages. + virtual string ToString() const; + + virtual ProtoElement* parent() const { + return static_cast<ProtoElement*>(BaseElement::parent()); + } + + // Returns true if the index is already taken by a preceeding oneof input. + bool IsOneofIndexTaken(int32 index); + + // Marks the oneof 'index' as taken. Future inputs to this oneof will + // generate an error. + void TakeOneofIndex(int32 index); + + private: + // Used for access to variables of the enclosing instance of + // ProtoWriter. + ProtoWriter* ow_; + + // Describes the element as a field in the parent message. + // parent_field_ is NULL if and only if this element is the root element. + const google::protobuf::Field* parent_field_; + + // TypeInfo to lookup types. + const TypeInfo* typeinfo_; + + // Additional variables if this element is a message: + // (Root element is always a message). + // type_ : the type of this element. + // required_fields_ : set of required fields. + // size_index_ : index into ProtoWriter::size_insert_ + // for later insertion of serialized message length. + const google::protobuf::Type& type_; + std::set<const google::protobuf::Field*> required_fields_; + const int size_index_; + + // Tracks position in repeated fields, needed for LocationTrackerInterface. + int array_index_; + + // Set of oneof indices already seen for the type_. Used to validate + // incoming messages so no more than one oneof is set. + hash_set<int32> oneof_indices_; + + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); + }; + + // Container for inserting 'size' information at the 'pos' position. + struct SizeInfo { + const int pos; + int size; + }; + + ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, + strings::ByteSink* output, ErrorListener* listener); + + virtual ProtoElement* element() { return element_.get(); } + + // Helper methods for calling ErrorListener. See error_listener.h. + void InvalidName(StringPiece unknown_name, StringPiece message); + void InvalidValue(StringPiece type_name, StringPiece value); + void MissingField(StringPiece missing_name); + + // Common code for BeginObject() and BeginList() that does invalid_depth_ + // bookkeeping associated with name lookup. + const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list); + + // Lookup the field in the current element. Looks in the base descriptor + // and in any extension. This will report an error if the field cannot be + // found or if multiple matching extensions are found. + const google::protobuf::Field* Lookup(StringPiece name); + + // Lookup the field type in the type descriptor. Returns NULL if the type + // is not known. + const google::protobuf::Type* LookupType( + const google::protobuf::Field* field); + + // Write serialized output to the final output ByteSink, inserting all + // the size information for nested messages that are missing from the + // intermediate Cord buffer. + void WriteRootMessage(); + + // Helper method to write proto tags based on the given field. + void WriteTag(const google::protobuf::Field& field); + + + // Returns true if the field for type_ can be set as a oneof. If field is not + // a oneof type, this function does nothing and returns true. + // If another field for this oneof is already set, this function returns + // false. It also calls the appropriate error callback. + // unnormalized_name is used for error string. + bool ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name); + + // 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. + // typeinfo_ : the TypeInfo object to lookup types. + const google::protobuf::Type& master_type_; + const TypeInfo* typeinfo_; + // Whether we own the typeinfo_ object. + bool own_typeinfo_; + + // Indicates whether we finished writing root message completely. + bool done_; + + // Variable for internal state processing: + // element_ : the current element. + // size_insert_: sizes of nested messages. + // pos - position to insert the size field. + // size - size value to be inserted. + google::protobuf::scoped_ptr<ProtoElement> element_; + std::deque<SizeInfo> size_insert_; + + // Variables for output generation: + // output_ : pointer to an external ByteSink for final user-visible output. + // buffer_ : buffer holding partial message before being ready for output_. + // adapter_ : internal adapter between CodedOutputStream and buffer_. + // stream_ : wrapper for writing tags and other encodings in wire format. + strings::ByteSink* output_; + string buffer_; + google::protobuf::io::StringOutputStream adapter_; + google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_; + + // Variables for error tracking and reporting: + // listener_ : a place to report any errors found. + // invalid_depth_: number of enclosing invalid nested messages. + // tracker_ : the root location tracker interface. + ErrorListener* listener_; + int invalid_depth_; + google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_; + + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter); +}; + +} // namespace converter +} // namespace util +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__ diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index aebf19a1..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."; } @@ -140,10 +175,10 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, bool include_start_and_end, ObjectWriter* ow) const { - const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); - if (type_renderer != NULL) { - return (*type_renderer)(this, type, name, ow); - } + const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); + if (type_renderer != NULL) { + return (*type_renderer)(this, type, name, ow); + } const google::protobuf::Field* field = NULL; string field_name; @@ -171,7 +206,9 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, if (field->cardinality() == google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { - if (IsMap(*field)) { + bool check_maps = true; + + if (check_maps && IsMap(*field)) { ow->StartObject(field_name); ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); ow->EndObject(); @@ -218,48 +255,44 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap( const google::protobuf::Type* field_type = typeinfo_->GetTypeByTypeUrl(field->type_url()); uint32 tag_to_return = 0; - if (IsPackable(*field) && - list_tag == - WireFormatLite::MakeTag(field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { - RETURN_IF_ERROR(RenderPackedMapEntry(field_type, ow)); - tag_to_return = stream_->ReadTag(); - } else { - do { - RETURN_IF_ERROR(RenderMapEntry(field_type, ow)); - } while ((tag_to_return = stream_->ReadTag()) == list_tag); - } - return tag_to_return; -} - -Status ProtoStreamObjectSource::RenderMapEntry( - const google::protobuf::Type* type, ObjectWriter* ow) const { - uint32 buffer32; - stream_->ReadVarint32(&buffer32); // message length - int old_limit = stream_->PushLimit(buffer32); - string map_key; - for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { - const google::protobuf::Field* field = FindAndVerifyField(*type, tag); - if (field == NULL) { - WireFormat::SkipField(stream_, tag, NULL); - continue; - } - // Map field numbers are key = 1 and value = 2 - if (field->number() == 1) { - map_key = ReadFieldValueAsString(*field); - } else if (field->number() == 2) { - if (map_key.empty()) { - return Status(util::error::INTERNAL, "Map key must be non-empty"); + do { + // Render map entry message type. + uint32 buffer32; + stream_->ReadVarint32(&buffer32); // message length + int old_limit = stream_->PushLimit(buffer32); + string map_key; + for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { + const google::protobuf::Field* field = + FindAndVerifyField(*field_type, tag); + if (field == NULL) { + WireFormat::SkipField(stream_, tag, NULL); + continue; + } + // Map field numbers are key = 1 and value = 2 + if (field->number() == 1) { + map_key = ReadFieldValueAsString(*field); + } else if (field->number() == 2) { + if (map_key.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."); } - // Disable case normalization for map keys as they are just data. We - // retain them intact. - ow->DisableCaseNormalizationForNextKey(); - RETURN_IF_ERROR(RenderField(field, map_key, ow)); } - } - stream_->PopLimit(old_limit); - - return Status::OK; + stream_->PopLimit(old_limit); + } while ((tag_to_return = stream_->ReadTag()) == list_tag); + return tag_to_return; } Status ProtoStreamObjectSource::RenderPacked( @@ -274,25 +307,13 @@ Status ProtoStreamObjectSource::RenderPacked( return Status::OK; } -Status ProtoStreamObjectSource::RenderPackedMapEntry( - const google::protobuf::Type* type, ObjectWriter* ow) const { - uint32 length; - stream_->ReadVarint32(&length); - int old_limit = stream_->PushLimit(length); - while (stream_->BytesUntilLimit() > 0) { - RETURN_IF_ERROR(RenderMapEntry(type, ow)); - } - stream_->PopLimit(old_limit); - return Status::OK; -} - Status ProtoStreamObjectSource::RenderTimestamp( const ProtoStreamObjectSource* os, const google::protobuf::Type& type, StringPiece field_name, ObjectWriter* ow) { 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)); @@ -316,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)); @@ -601,10 +622,10 @@ Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os, // nested_type cannot be null at this time. const google::protobuf::Type* nested_type = resolved_type.ValueOrDie(); - // We know the type so we can render it. Recursively parse the nested stream - // using a nested ProtoStreamObjectSource using our nested type information. google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size()); google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream); + // We know the type so we can render it. Recursively parse the nested stream + // using a nested ProtoStreamObjectSource using our nested type information. ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type); // We manually call start and end object here so we can inject the @type. @@ -676,8 +697,7 @@ void ProtoStreamObjectSource::InitRendererMap() { &ProtoStreamObjectSource::RenderString; (*renderers_)["google.protobuf.BytesValue"] = &ProtoStreamObjectSource::RenderBytes; - (*renderers_)["google.protobuf.Any"] = - &ProtoStreamObjectSource::RenderAny; + (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny; (*renderers_)["google.protobuf.Struct"] = &ProtoStreamObjectSource::RenderStruct; (*renderers_)["google.protobuf.Value"] = @@ -704,87 +724,120 @@ ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) { Status ProtoStreamObjectSource::RenderField( const google::protobuf::Field* field, StringPiece field_name, ObjectWriter* ow) const { + // Short-circuit message types as it tends to call WriteMessage recursively + // and ends up using a lot of stack space. Keep the stack usage of this + // message small in order to preserve stack space and not crash. + if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { + uint32 buffer32; + stream_->ReadVarint32(&buffer32); // message length + int old_limit = stream_->PushLimit(buffer32); + // Get the nested message type for this field. + const google::protobuf::Type* type = + typeinfo_->GetTypeByTypeUrl(field->type_url()); + if (type == NULL) { + return Status(util::error::INTERNAL, + StrCat("Invalid configuration. Could not find the type: ", + field->type_url())); + } + + // Short-circuit any special type rendering to save call-stack space. + const TypeRenderer* type_renderer = FindTypeRenderer(type->name()); + + bool use_type_renderer = type_renderer != NULL; + + 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, + "Nested protocol message not parsed in its entirety."); + } + stream_->PopLimit(old_limit); + } else { + // Render all other non-message types. + return RenderNonMessageField(field, field_name, ow); + } + return Status::OK; +} + +Status ProtoStreamObjectSource::RenderNonMessageField( + const google::protobuf::Field* field, StringPiece field_name, + ObjectWriter* ow) const { + // Temporary buffers of different types. + uint32 buffer32; + uint64 buffer64; + string strbuffer; switch (field->kind()) { case google::protobuf::Field_Kind_TYPE_BOOL: { - uint64 buffer64; stream_->ReadVarint64(&buffer64); ow->RenderBool(field_name, buffer64 != 0); break; } case google::protobuf::Field_Kind_TYPE_INT32: { - uint32 buffer32; stream_->ReadVarint32(&buffer32); ow->RenderInt32(field_name, bit_cast<int32>(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_INT64: { - uint64 buffer64; stream_->ReadVarint64(&buffer64); ow->RenderInt64(field_name, bit_cast<int64>(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_UINT32: { - uint32 buffer32; stream_->ReadVarint32(&buffer32); ow->RenderUint32(field_name, bit_cast<uint32>(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_UINT64: { - uint64 buffer64; stream_->ReadVarint64(&buffer64); ow->RenderUint64(field_name, bit_cast<uint64>(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_SINT32: { - uint32 buffer32; stream_->ReadVarint32(&buffer32); ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_SINT64: { - uint64 buffer64; stream_->ReadVarint64(&buffer64); ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_SFIXED32: { - uint32 buffer32; stream_->ReadLittleEndian32(&buffer32); ow->RenderInt32(field_name, bit_cast<int32>(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_SFIXED64: { - uint64 buffer64; stream_->ReadLittleEndian64(&buffer64); ow->RenderInt64(field_name, bit_cast<int64>(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_FIXED32: { - uint32 buffer32; stream_->ReadLittleEndian32(&buffer32); ow->RenderUint32(field_name, bit_cast<uint32>(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_FIXED64: { - uint64 buffer64; stream_->ReadLittleEndian64(&buffer64); ow->RenderUint64(field_name, bit_cast<uint64>(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_FLOAT: { - uint32 buffer32; stream_->ReadLittleEndian32(&buffer32); ow->RenderFloat(field_name, bit_cast<float>(buffer32)); break; } case google::protobuf::Field_Kind_TYPE_DOUBLE: { - uint64 buffer64; stream_->ReadLittleEndian64(&buffer64); ow->RenderDouble(field_name, bit_cast<double>(buffer64)); break; } case google::protobuf::Field_Kind_TYPE_ENUM: { - uint32 buffer32; stream_->ReadVarint32(&buffer32); // If the field represents an explicit NULL value, render null. @@ -803,48 +856,26 @@ Status ProtoStreamObjectSource::RenderField( 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) << "Unkown enum skipped: " << field->type_url(); + GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); } break; } case google::protobuf::Field_Kind_TYPE_STRING: { - uint32 buffer32; - string str; stream_->ReadVarint32(&buffer32); // string size. - stream_->ReadString(&str, buffer32); - ow->RenderString(field_name, str); + stream_->ReadString(&strbuffer, buffer32); + ow->RenderString(field_name, strbuffer); break; } case google::protobuf::Field_Kind_TYPE_BYTES: { - uint32 buffer32; stream_->ReadVarint32(&buffer32); // bytes size. - string value; - stream_->ReadString(&value, buffer32); - ow->RenderBytes(field_name, value); - break; - } - case google::protobuf::Field_Kind_TYPE_MESSAGE: { - uint32 buffer32; - stream_->ReadVarint32(&buffer32); // message length - int old_limit = stream_->PushLimit(buffer32); - // Get the nested message type for this field. - const google::protobuf::Type* type = - typeinfo_->GetTypeByTypeUrl(field->type_url()); - if (type == NULL) { - return Status(util::error::INTERNAL, - StrCat("Invalid configuration. Could not find the type: ", - field->type_url())); - } - - RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); - if (!stream_->ConsumedEntireMessage()) { - return Status(util::error::INVALID_ARGUMENT, - "Nested protocol message not parsed in its entirety."); - } - stream_->PopLimit(old_limit); + stream_->ReadString(&strbuffer, buffer32); + ow->RenderBytes(field_name, strbuffer); break; } default: @@ -1015,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 3cd37aa1..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 @@ -122,20 +157,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { StringPiece name, uint32 list_tag, ObjectWriter* ow) const; - // Renders an entry in a map, advancing stream pointers appropriately. - util::Status RenderMapEntry(const google::protobuf::Type* type, - ObjectWriter* ow) const; - // Renders a packed repeating field. A packed field is stored as: // {tag length item1 item2 item3} instead of the less efficient // {tag item1 tag item2 tag item3}. util::Status RenderPacked(const google::protobuf::Field* field, ObjectWriter* ow) const; - // Equivalent of RenderPacked, but for map entries. - util::Status RenderPackedMapEntry(const google::protobuf::Type* type, - ObjectWriter* ow) const; - // Renders a google.protobuf.Timestamp value to ObjectWriter static util::Status RenderTimestamp(const ProtoStreamObjectSource* os, const google::protobuf::Type& type, @@ -210,6 +237,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { util::Status RenderField(const google::protobuf::Field* field, StringPiece field_name, ObjectWriter* ow) const; + // Same as above but renders all non-message field types. Callers don't call + // this function directly. They just use RenderField. + util::Status RenderNonMessageField(const google::protobuf::Field* field, + StringPiece field_name, + ObjectWriter* ow) const; + // Reads field value according to Field spec in 'field' and returns the read // value as string. This only works for primitive datatypes (no message @@ -225,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_; @@ -238,6 +277,16 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // google::protobuf::Type of the message source. 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 f6e5ee7a..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, @@ -327,9 +340,16 @@ TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { DoTest(primitive, Primitive::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, CustomJsonName) { + Author author; + author.set_id(12345); + + ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject(); + DoTest(author, Author::descriptor()); +} + TEST_P(ProtostreamObjectSourceTest, NestedMessage) { Author* author = new Author(); - author->set_id(101L); author->set_name("Tolstoy"); Book book; book.set_title("My Book"); @@ -338,7 +358,6 @@ TEST_P(ProtostreamObjectSourceTest, NestedMessage) { ow_.StartObject("") ->RenderString("title", "My Book") ->StartObject("author") - ->RenderUint64("id", bit_cast<uint64>(101LL)) ->RenderString("name", "Tolstoy") ->EndObject() ->EndObject(); @@ -455,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() { @@ -535,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() { @@ -818,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 08a2fb9a..97a7909a 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -51,7 +51,6 @@ namespace util { namespace converter { using google::protobuf::internal::WireFormatLite; -using google::protobuf::io::CodedOutputStream; using util::error::INVALID_ARGUMENT; using util::Status; using util::StatusOr; @@ -59,231 +58,35 @@ using util::StatusOr; ProtoStreamObjectWriter::ProtoStreamObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) - : master_type_(type), - typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), - own_typeinfo_(true), - done_(false), - element_(NULL), - size_insert_(), - output_(output), - buffer_(), - adapter_(&buffer_), - stream_(new CodedOutputStream(&adapter_)), - listener_(listener), - invalid_depth_(0), - tracker_(new ObjectLocationTracker()) {} + strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options) + : ProtoWriter(type_resolver, type, output, listener), + master_type_(type), + current_(NULL), + options_(options) {} ProtoStreamObjectWriter::ProtoStreamObjectWriter( const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener) - : master_type_(type), - typeinfo_(typeinfo), - own_typeinfo_(false), - done_(false), - element_(NULL), - size_insert_(), - output_(output), - buffer_(), - adapter_(&buffer_), - stream_(new CodedOutputStream(&adapter_)), - listener_(listener), - invalid_depth_(0), - tracker_(new ObjectLocationTracker()) {} + : ProtoWriter(typeinfo, type, output, listener), + master_type_(type), + current_(NULL), + options_(ProtoStreamObjectWriter::Options::Defaults()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { - if (own_typeinfo_) { - delete typeinfo_; - } - if (element_ == NULL) return; + if (current_ == NULL) return; // Cleanup explicitly in order to avoid destructor stack overflow when input // is deeply nested. // Cast to BaseElement to avoid doing additional checks (like missing fields) // during pop(). google::protobuf::scoped_ptr<BaseElement> element( - static_cast<BaseElement*>(element_.get())->pop<BaseElement>()); + static_cast<BaseElement*>(current_.get())->pop<BaseElement>()); while (element != NULL) { element.reset(element->pop<BaseElement>()); } } namespace { - -// Writes an INT32 field, including tag to the stream. -inline Status WriteInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int32> i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream); - } - return i32.status(); -} - -// writes an SFIXED32 field, including tag, to the stream. -inline Status WriteSFixed32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int32> i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream); - } - return i32.status(); -} - -// Writes an SINT32 field, including tag, to the stream. -inline Status WriteSInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int32> i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream); - } - return i32.status(); -} - -// Writes a FIXED32 field, including tag, to the stream. -inline Status WriteFixed32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<uint32> u32 = data.ToUint32(); - if (u32.ok()) { - WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream); - } - return u32.status(); -} - -// Writes a UINT32 field, including tag, to the stream. -inline Status WriteUInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<uint32> u32 = data.ToUint32(); - if (u32.ok()) { - WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream); - } - return u32.status(); -} - -// Writes an INT64 field, including tag, to the stream. -inline Status WriteInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int64> i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream); - } - return i64.status(); -} - -// Writes an SFIXED64 field, including tag, to the stream. -inline Status WriteSFixed64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int64> i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream); - } - return i64.status(); -} - -// Writes an SINT64 field, including tag, to the stream. -inline Status WriteSInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<int64> i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream); - } - return i64.status(); -} - -// Writes a FIXED64 field, including tag, to the stream. -inline Status WriteFixed64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<uint64> u64 = data.ToUint64(); - if (u64.ok()) { - WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream); - } - return u64.status(); -} - -// Writes a UINT64 field, including tag, to the stream. -inline Status WriteUInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<uint64> u64 = data.ToUint64(); - if (u64.ok()) { - WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream); - } - return u64.status(); -} - -// Writes a DOUBLE field, including tag, to the stream. -inline Status WriteDouble(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<double> d = data.ToDouble(); - if (d.ok()) { - WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream); - } - return d.status(); -} - -// Writes a FLOAT field, including tag, to the stream. -inline Status WriteFloat(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<float> f = data.ToFloat(); - if (f.ok()) { - WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream); - } - return f.status(); -} - -// Writes a BOOL field, including tag, to the stream. -inline Status WriteBool(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<bool> b = data.ToBool(); - if (b.ok()) { - WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream); - } - return b.status(); -} - -// Writes a BYTES field, including tag, to the stream. -inline Status WriteBytes(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<string> c = data.ToBytes(); - if (c.ok()) { - WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream); - } - return c.status(); -} - -// Writes a STRING field, including tag, to the stream. -inline Status WriteString(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - StatusOr<string> s = data.ToString(); - if (s.ok()) { - WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream); - } - return s.status(); -} - -// Writes an ENUM field, including tag, to the stream. -inline Status WriteEnum(int field_number, const DataPiece& data, - const google::protobuf::Enum* enum_type, - CodedOutputStream* stream) { - StatusOr<int> e = data.ToEnum(enum_type); - if (e.ok()) { - WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); - } - return e.status(); -} - -// Given a google::protobuf::Type, returns the set of all required fields. -std::set<const google::protobuf::Field*> GetRequiredFields( - const google::protobuf::Type& type) { - std::set<const google::protobuf::Field*> required; - for (int i = 0; i < type.fields_size(); i++) { - const google::protobuf::Field& field = type.fields(i); - if (field.cardinality() == - google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { - required.insert(&field); - } - } - return required; -} - // Utility method to split a string representation of Timestamp or Duration and // return the parts. void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds, @@ -298,6 +101,78 @@ void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds, } } +Status GetNanosFromStringPiece(StringPiece s_nanos, + const char* parse_failure_message, + const char* exceeded_limit_message, + int32* nanos) { + *nanos = 0; + + // Count the number of leading 0s and consume them. + int num_leading_zeros = 0; + while (s_nanos.Consume("0")) { + num_leading_zeros++; + } + int32 i_nanos = 0; + // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to + // "0." + s_nanos.ToString() seconds. An int32 is used for the + // conversion to 'nanos', rather than a double, so that there is no + // loss of precision. + if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) { + return Status(INVALID_ARGUMENT, parse_failure_message); + } + if (i_nanos > kNanosPerSecond || i_nanos < 0) { + return Status(INVALID_ARGUMENT, exceeded_limit_message); + } + // s_nanos should only have digits. No whitespace. + if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) { + return Status(INVALID_ARGUMENT, parse_failure_message); + } + + if (i_nanos > 0) { + // 'scale' is the number of digits to the right of the decimal + // point in "0." + s_nanos.ToString() + int32 scale = num_leading_zeros + s_nanos.size(); + // 'conversion' converts i_nanos into nanoseconds. + // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale)) + // For efficiency, we precompute the conversion factor. + int32 conversion = 0; + switch (scale) { + case 1: + conversion = 100000000; + break; + case 2: + conversion = 10000000; + break; + case 3: + conversion = 1000000; + break; + case 4: + conversion = 100000; + break; + case 5: + conversion = 10000; + break; + case 6: + conversion = 1000; + break; + case 7: + conversion = 100; + break; + case 8: + conversion = 10; + break; + case 9: + conversion = 1; + break; + default: + return Status(INVALID_ARGUMENT, exceeded_limit_message); + } + *nanos = i_nanos * conversion; + } + + return Status::OK; +} + } // namespace ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) @@ -307,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() {} @@ -325,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); } } @@ -336,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 @@ -361,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); } @@ -391,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); } } @@ -421,7 +322,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { } // Resolve the type url, and report an error if we failed to resolve it. StatusOr<const google::protobuf::Type*> resolved_type = - parent_->typeinfo_->ResolveTypeUrl(type_url_); + parent_->typeinfo()->ResolveTypeUrl(type_url_); if (!resolved_type.ok()) { parent_->InvalidValue("Any", resolved_type.status().error_message()); invalid_ = true; @@ -430,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(""); + ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, + parent_->listener())); + + // 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() { @@ -453,604 +366,433 @@ void ProtoStreamObjectWriter::AnyWriter::WriteAny() { } // Render the type_url and value fields directly to the stream. // type_url has tag 1 and value has tag 2. - WireFormatLite::WriteString(1, type_url_, parent_->stream_.get()); + WireFormatLite::WriteString(1, type_url_, parent_->stream()); if (!data_.empty()) { - WireFormatLite::WriteBytes(2, data_, parent_->stream_.get()); + WireFormatLite::WriteBytes(2, data_, parent_->stream()); } } -ProtoStreamObjectWriter::ProtoElement::ProtoElement( - const TypeInfo* typeinfo, const google::protobuf::Type& type, - ProtoStreamObjectWriter* enclosing) +ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, + ItemType item_type, bool is_placeholder, + bool is_list) : BaseElement(NULL), ow_(enclosing), any_(), - field_(NULL), - typeinfo_(typeinfo), - type_(type), - required_fields_(GetRequiredFields(type)), - is_repeated_type_(false), - size_index_(-1), - array_index_(-1), - element_type_(GetElementType(type_)) { - if (element_type_ == ANY) { + item_type_(item_type), + is_placeholder_(is_placeholder), + is_list_(is_list) { + if (item_type_ == ANY) { any_.reset(new AnyWriter(ow_)); } } -ProtoStreamObjectWriter::ProtoElement::ProtoElement( - ProtoStreamObjectWriter::ProtoElement* parent, - const google::protobuf::Field* field, const google::protobuf::Type& type, - ElementType element_type) +ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent, + ItemType item_type, bool is_placeholder, + bool is_list) : BaseElement(parent), ow_(this->parent()->ow_), any_(), - field_(field), - typeinfo_(this->parent()->typeinfo_), - type_(type), - is_repeated_type_(element_type == ProtoElement::LIST || - element_type == ProtoElement::STRUCT_LIST || - element_type == ProtoElement::MAP || - element_type == ProtoElement::STRUCT_MAP), - size_index_(!is_repeated_type_ && - field->kind() == - google::protobuf::Field_Kind_TYPE_MESSAGE - ? ow_->size_insert_.size() - : -1), - array_index_(is_repeated_type_ ? 0 : -1), - element_type_(element_type) { - if (!is_repeated_type_) { - if (field->cardinality() == - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { - // Update array_index_ if it is an explicit list. - if (this->parent()->array_index_ >= 0) this->parent()->array_index_++; - } else { - this->parent()->RegisterField(field); - } - if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { - required_fields_ = GetRequiredFields(type_); - int start_pos = ow_->stream_->ByteCount(); - // length of serialized message is the final buffer position minus - // starting buffer position, plus length adjustments for size fields - // of any nested messages. We start with -start_pos here, so we only - // need to add the final buffer position to it at the end. - SizeInfo info = {start_pos, -start_pos}; - ow_->size_insert_.push_back(info); - } - } - if (element_type == ANY) { + item_type_(item_type), + is_placeholder_(is_placeholder), + is_list_(is_list) { + if (item_type == ANY) { any_.reset(new AnyWriter(ow_)); } } -ProtoStreamObjectWriter::ProtoElement* -ProtoStreamObjectWriter::ProtoElement::pop() { - // Calls the registered error listener for any required field(s) not yet - // seen. - for (set<const google::protobuf::Field*>::iterator it = - required_fields_.begin(); - it != required_fields_.end(); ++it) { - ow_->MissingField((*it)->name()); - } - // Computes the total number of proto bytes used by a message, also adjusts - // the size of all parent messages by the length of this size field. - // If size_index_ < 0, this is not a message, so no size field is added. - if (size_index_ >= 0) { - // Add the final buffer position to compute the total length of this - // serialized message. The stored value (before this addition) already - // contains the total length of the size fields of all nested messages - // minus the initial buffer position. - ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount(); - // Calculate the length required to serialize the size field of the - // message, and propagate this additional size information upward to - // all enclosing messages. - int size = ow_->size_insert_[size_index_].size; - int length = CodedOutputStream::VarintSize32(size); - for (ProtoElement* e = parent(); e != NULL; e = e->parent()) { - // Only nested messages have size field, lists do not have size field. - if (e->size_index_ >= 0) { - ow_->size_insert_[e->size_index_].size += length; - } - } - } - return BaseElement::pop<ProtoElement>(); -} - -void ProtoStreamObjectWriter::ProtoElement::RegisterField( - const google::protobuf::Field* field) { - if (!required_fields_.empty() && - field->cardinality() == - google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { - required_fields_.erase(field); - } -} - -string ProtoStreamObjectWriter::ProtoElement::ToString() const { - if (parent() == NULL) return ""; - string loc = parent()->ToString(); - if (field_->cardinality() != - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED || - parent()->field_ != field_) { - string name = field_->name(); - int i = 0; - while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i; - if (i > 0 && i == name.size()) { // safe field name - if (loc.empty()) { - loc = name; - } else { - StrAppend(&loc, ".", name); - } - } else { - StrAppend(&loc, "[\"", CEscape(name), "\"]"); - } - } - if (field_->cardinality() == - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED && - array_index_ > 0) { - StrAppend(&loc, "[", array_index_ - 1, "]"); - } - return loc.empty() ? "." : loc; -} - -bool ProtoStreamObjectWriter::ProtoElement::OneofIndexTaken(int32 index) { - return ContainsKey(oneof_indices_, index); -} - -void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) { - InsertIfNotPresent(&oneof_indices_, index); -} - -bool ProtoStreamObjectWriter::ProtoElement::InsertMapKeyIfNotPresent( +bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent( StringPiece map_key) { - return InsertIfNotPresent(&map_keys_, map_key); -} - -inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name, - StringPiece message) { - listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); -} - -inline void ProtoStreamObjectWriter::InvalidValue(StringPiece type_name, - StringPiece value) { - listener_->InvalidValue(location(), type_name, value); -} - -inline void ProtoStreamObjectWriter::MissingField(StringPiece missing_name) { - listener_->MissingField(location(), missing_name); + return InsertIfNotPresent(&map_keys_, map_key.ToString()); } ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( StringPiece name) { - // Starting the root message. Create the root ProtoElement and return. - if (element_ == NULL) { - if (!name.empty()) { - InvalidName(name, "Root element should not be named."); - } - element_.reset(new ProtoElement(typeinfo_, master_type_, this)); + if (invalid_depth() > 0) { + IncrementInvalidDepth(); + return this; + } + + // Starting the root message. Create the root Item and return. + // ANY message type does not need special handling, just set the ItemType + // to ANY. + if (current_ == NULL) { + ProtoWriter::StartObject(name); + current_.reset(new Item( + this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE, + false, false)); // If master type is a special type that needs extra values to be written to // stream, we write those values. if (master_type_.name() == kStructType) { - StartStruct(NULL); - } else if (master_type_.name() == kStructValueType) { - // We got a StartObject call with google.protobuf.Value field. This means - // we are starting an object within google.protobuf.Value type. The only - // object within that type is a struct type. So start a struct. - const google::protobuf::Field* field = StartStructValueInStruct(NULL); - StartStruct(field); + // Struct has a map<string, Value> field called "fields". + // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto + // "fields": [ + Push("fields", Item::MAP, true, true); + return this; } - return this; - } - const google::protobuf::Field* field = NULL; - if (element_ != NULL && element_->IsAny()) { - element_->any()->StartObject(name); - return this; - } else if (element_ != NULL && - (element_->IsMap() || element_->IsStructMap())) { - if (!ValidMapKey(name)) { - ++invalid_depth_; + if (master_type_.name() == kStructValueType) { + // We got a StartObject call with google.protobuf.Value field. The only + // object within that type is a struct type. So start a struct. + // + // The struct field in Value type is named "struct_value" + // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto + // Also start the map field "fields" within the struct. + // "struct_value": { + // "fields": [ + Push("struct_value", Item::MESSAGE, true, false); + Push("fields", Item::MAP, true, true); return this; } - field = StartMapEntry(name); - if (element_->IsStructMapEntry()) { - // If the top element is a map entry, this means we are starting another - // struct within a struct. - field = StartStructValueInStruct(field); + if (master_type_.name() == kStructListValueType) { + InvalidValue(kStructListValueType, + "Cannot start root message with ListValue."); } - } else if (element_ != NULL && element_->IsStructList()) { - // If the top element is a list, then we are starting a list field within a - // struct. - field = Lookup(name); - field = StartStructValueInStruct(field); - } else { - field = BeginNamed(name, false); - } - if (field == NULL) { - return this; - } - const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { - ++invalid_depth_; - InvalidName(name, - StrCat("Missing descriptor for field: ", field->type_url())); return this; } - // Check to see if this field is a oneof and that no oneof in that group has - // already been set. - if (!ValidOneof(*field, name)) { - ++invalid_depth_; + // Send all ANY events to AnyWriter. + if (current_->IsAny()) { + current_->any()->StartObject(name); return this; } - if (field->type_url() == GetFullTypeWithUrl(kStructType)) { - // Start a struct object. - StartStruct(field); - } else if (field->type_url() == GetFullTypeWithUrl(kStructValueType)) { - // We got a StartObject call with google.protobuf.Value field. This means we - // are starting an object within google.protobuf.Value type. The only object - // within that type is a struct type. So start a struct. - field = StartStructValueInStruct(field); - StartStruct(field); - } else if (field->type_url() == GetFullTypeWithUrl(kAnyType)) { - // Begin an Any. We can't do the real work till we get the @type field. - WriteTag(*field); - element_.reset( - new ProtoElement(element_.release(), field, *type, ProtoElement::ANY)); - } else if (IsMap(*field)) { - // Begin a map. - // A map is triggered by a StartObject() call if the current field has a map - // type. Map values are written to proto in a manner detailed in comments - // above StartMapEntry() function. - element_.reset( - new ProtoElement(element_.release(), field, *type, ProtoElement::MAP)); - } else { - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::MESSAGE)); - } - return this; -} - -// Proto3 maps are represented on the wire as a message with -// "key" and a "value". -// -// For example, the syntax: -// map<key_type, value_type> map_field = N; -// -// is represented as: -// message MapFieldEntry { -// option map_entry = true; // marks the map construct in the descriptor -// -// key_type key = 1; -// value_type value = 2; -// } -// repeated MapFieldEntry map_field = N; -// -// See go/proto3-maps for more information. -const google::protobuf::Field* ProtoStreamObjectWriter::StartMapEntry( - StringPiece name) { - // top of stack is already a map field - const google::protobuf::Field* field = element_->field(); - const google::protobuf::Type& type = element_->type(); - // If we come from a regular map, use MAP_ENTRY or if we come from a struct, - // use STRUCT_MAP_ENTRY. These values are used later in StartObject/StartList - // or RenderDataPiece for making appropriate decisions. - ProtoElement::ElementType element_type = element_->IsStructMap() - ? ProtoElement::STRUCT_MAP_ENTRY - : ProtoElement::MAP_ENTRY; - WriteTag(*field); - element_.reset( - new ProtoElement(element_.release(), field, type, element_type)); - RenderDataPiece("key", DataPiece(name)); - return BeginNamed("value", false); -} + // If we are within a map, we render name as keys and send StartObject to the + // value field. + if (current_->IsMap()) { + if (!ValidMapKey(name)) { + IncrementInvalidDepth(); + return this; + } -// Starts a google.protobuf.Struct. -// 'field' represents a field in a message of type google.protobuf.Struct. A -// struct contains a map with name 'fields'. This function starts this map as -// well. -// When 'field' is NULL, it means that the top level message is of struct -// type. -void ProtoStreamObjectWriter::StartStruct( - const google::protobuf::Field* field) { - const google::protobuf::Type* type = NULL; - if (field) { - type = LookupType(field); - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::STRUCT)); - } - const google::protobuf::Field* struct_field = BeginNamed("fields", false); + // Map is a repeated field of message type with a "key" and a "value" field. + // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps + // message MapFieldEntry { + // key_type key = 1; + // value_type value = 2; + // } + // + // repeated MapFieldEntry map_field = N; + // + // That means, we render the following element within a list (hence no + // name): + // { "key": "<name>", "value": { + Push("", Item::MESSAGE, false, false); + 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. + if (invalid_depth() > 0) return this; + + // If top of stack is g.p.Struct type, start the struct the map field within + // it. + if (element() != NULL && IsStruct(*element()->parent_field())) { + // Render "fields": [ + Push("fields", Item::MAP, true, true); + return this; + } - if (!struct_field) { - // It is a programmatic error if this happens. Log an error. - GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'fields' within " - << (field ? field->type_url() : "google.protobuf.Struct"); - return; + // If top of stack is g.p.Value type, start the Struct within it. + if (element() != NULL && IsStructValue(*element()->parent_field())) { + // Render + // "struct_value": { + // "fields": [ + Push("struct_value", Item::MESSAGE, true, false); + Push("fields", Item::MAP, true, true); + } + return this; } - type = LookupType(struct_field); - element_.reset(new ProtoElement(element_.release(), struct_field, *type, - ProtoElement::STRUCT_MAP)); -} + const google::protobuf::Field* field = BeginNamed(name, false); + if (field == NULL) return this; -// Starts a "struct_value" within struct.proto's google.protobuf.Value type. -// 'field' should be of the type google.protobuf.Value. -// Returns the field identifying "struct_value" within the given field. -// -// If field is NULL, then we are starting struct_value at the top-level, in -// this case skip writing any tag information for the passed field. -const google::protobuf::Field* -ProtoStreamObjectWriter::StartStructValueInStruct( - const google::protobuf::Field* field) { - if (field) { - const google::protobuf::Type* type = LookupType(field); - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::STRUCT_VALUE)); - } - return BeginNamed("struct_value", false); -} - -// Starts a "list_value" within struct.proto's google.protobuf.Value type. -// 'field' should be of the type google.protobuf.Value. -// Returns the field identifying "list_value" within the given field. -// -// If field is NULL, then we are starting list_value at the top-level, in -// this case skip writing any tag information for the passed field. -const google::protobuf::Field* ProtoStreamObjectWriter::StartListValueInStruct( - const google::protobuf::Field* field) { - if (field) { - const google::protobuf::Type* type = LookupType(field); - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::STRUCT_VALUE)); + if (IsStruct(*field)) { + // Start a struct object. + // Render + // "<name>": { + // "fields": { + Push(name, Item::MESSAGE, false, false); + Push("fields", Item::MAP, true, true); + return this; } - const google::protobuf::Field* list_value = BeginNamed("list_value", false); - if (!list_value) { - // It is a programmatic error if this happens. Log an error. - GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'list_value' within " - << (field ? field->type_url() : "google.protobuf.Value"); - return field; + if (IsStructValue(*field)) { + // We got a StartObject call with google.protobuf.Value field. The only + // object within that type is a struct type. So start a struct. + // Render + // "<name>": { + // "struct_value": { + // "fields": { + Push(name, Item::MESSAGE, false, false); + Push("struct_value", Item::MESSAGE, true, false); + Push("fields", Item::MAP, true, true); + return this; } - return StartRepeatedValuesInListValue(list_value); -} - -// Starts the repeated "values" field in struct.proto's -// google.protobuf.ListValue type. 'field' should be of type -// google.protobuf.ListValue. -// -// If field is NULL, then we are starting ListValue at the top-level, in -// this case skip writing any tag information for the passed field. -const google::protobuf::Field* -ProtoStreamObjectWriter::StartRepeatedValuesInListValue( - const google::protobuf::Field* field) { - if (field) { - const google::protobuf::Type* type = LookupType(field); - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::STRUCT_LIST_VALUE)); + if (IsMap(*field)) { + // Begin a map. A map is triggered by a StartObject() call if the current + // field has a map type. + // A map type is always repeated, hence set is_list to true. + // Render + // "<name>": [ + Push(name, Item::MAP, false, true); + return this; } - return BeginNamed("values", true); -} -void ProtoStreamObjectWriter::SkipElements() { - if (element_ == NULL) return; - - ProtoElement::ElementType element_type = element_->element_type(); - while (element_type == ProtoElement::STRUCT || - element_type == ProtoElement::STRUCT_LIST_VALUE || - element_type == ProtoElement::STRUCT_VALUE || - element_type == ProtoElement::STRUCT_MAP_ENTRY || - element_type == ProtoElement::MAP_ENTRY) { - element_.reset(element_->pop()); - element_type = - element_ != NULL ? element_->element_type() : ProtoElement::MESSAGE; - } + // A regular message type. Pass it directly to ProtoWriter. + // Render + // "<name>": { + Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false); + return this; } ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() { - if (invalid_depth_ > 0) { - --invalid_depth_; + if (invalid_depth() > 0) { + DecrementInvalidDepth(); return this; } - if (element_ != NULL && element_->IsAny()) { - if (element_->any()->EndObject()) { - return this; - } - } - if (element_ != NULL) { - element_.reset(element_->pop()); - } - - // Skip sentinel elements added to keep track of new proto3 types - map, - // struct. - SkipElements(); + if (current_ == NULL) return this; - // If ending the root element, - // then serialize the full message with calculated sizes. - if (element_ == NULL) { - WriteRootMessage(); + if (current_->IsAny()) { + if (current_->any()->EndObject()) return this; } + + Pop(); + return this; } ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { - const google::protobuf::Field* field = NULL; + if (invalid_depth() > 0) { + IncrementInvalidDepth(); + return this; + } + // Since we cannot have a top-level repeated item in protobuf, the only way - // element_ can be null when here is when we start a top-level list - // google.protobuf.ListValue. - if (element_ == NULL) { + // this is valid is if we start a special type google.protobuf.ListValue or + // google.protobuf.Value. + if (current_ == NULL) { if (!name.empty()) { InvalidName(name, "Root element should not be named."); + IncrementInvalidDepth(); + return this; } - element_.reset(new ProtoElement(typeinfo_, master_type_, this)); // If master type is a special type that needs extra values to be written to // stream, we write those values. if (master_type_.name() == kStructValueType) { // We got a StartList with google.protobuf.Value master type. This means // we have to start the "list_value" within google.protobuf.Value. - field = StartListValueInStruct(NULL); - } else if (master_type_.name() == kStructListValueType) { + // + // See + // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto + // + // Render + // "<name>": { + // "list_value": { + // "values": [ // Start this list. + ProtoWriter::StartObject(name); + current_.reset(new Item(this, Item::MESSAGE, false, false)); + Push("list_value", Item::MESSAGE, true, false); + Push("values", Item::MESSAGE, true, true); + return this; + } + + if (master_type_.name() == kStructListValueType) { // We got a StartList with google.protobuf.ListValue master type. This // means we have to start the "values" within google.protobuf.ListValue. - field = StartRepeatedValuesInListValue(NULL); + // + // Render + // "<name>": { + // "values": [ // Start this list. + ProtoWriter::StartObject(name); + current_.reset(new Item(this, Item::MESSAGE, false, false)); + Push("values", Item::MESSAGE, true, true); + return this; } - // field is NULL when master_type_ is anything other than - // google.protobuf.Value or google.protobuf.ListValue. - if (field) { - const google::protobuf::Type* type = LookupType(field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::STRUCT_LIST)); - } + // Send the event to ProtoWriter so proper errors can be reported. + // + // Render a regular list: + // "<name>": [ + ProtoWriter::StartList(name); + current_.reset(new Item(this, Item::MESSAGE, false, true)); return this; } - if (element_->IsAny()) { - element_->any()->StartList(name); + if (current_->IsAny()) { + current_->any()->StartList(name); return this; } - // The type of element we push to stack. - ProtoElement::ElementType element_type = ProtoElement::LIST; - // Check if we need to start a map. This can heppen when there is either a map - // or a struct type within a list. - if (element_->IsMap() || element_->IsStructMap()) { + // If the top of stack is a map, we are starting a list value within a map. + // Since map does not allow repeated values, this can only happen when the map + // value is of a special type that renders a list in JSON. These can be one + // of 3 cases: + // i. We are rendering a list value within google.protobuf.Struct + // ii. We are rendering a list value within google.protobuf.Value + // iii. We are rendering a list value with type google.protobuf.ListValue. + if (current_->IsMap()) { if (!ValidMapKey(name)) { - ++invalid_depth_; + IncrementInvalidDepth(); return this; } - field = StartMapEntry(name); - if (field == NULL) return this; + // Start the repeated map entry object. + // Render + // { "key": "<name>", "value": { + Push("", Item::MESSAGE, false, false); + 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. + if (invalid_depth() > 0) return this; + + // case i and ii above. Start "list_value" field within g.p.Value + if (element() != NULL && element()->parent_field() != NULL) { + // Render + // "list_value": { + // "values": [ // Start this list + if (IsStructValue(*element()->parent_field())) { + Push("list_value", Item::MESSAGE, true, false); + Push("values", Item::MESSAGE, true, true); + return this; + } - if (element_->IsStructMapEntry()) { - // If the top element is a map entry, this means we are starting a list - // within a struct or a map. - // An example sequence of calls would be - // StartObject -> StartList - field = StartListValueInStruct(field); - if (field == NULL) return this; + // Render + // "values": [ + if (IsStructListValue(*element()->parent_field())) { + // case iii above. Bind directly to g.p.ListValue + Push("values", Item::MESSAGE, true, true); + return this; + } } - element_type = ProtoElement::STRUCT_LIST; - } else if (element_->IsStructList()) { - // If the top element is a STRUCT_LIST, this means we are starting a list - // within the current list (inside a struct). - // An example call sequence would be - // StartObject -> StartList -> StartList - // with StartObject starting a struct. + // Report an error. + InvalidValue("Map", StrCat("Cannot have repeated items ('", name, + "') within a map.")); + return this; + } - // Lookup the last list type in element stack as we are adding an element of - // the same type. - field = Lookup(name); - if (field == NULL) return this; + // When name is empty and stack is not empty, we are rendering an item within + // a list. + if (name.empty()) { + if (element() != NULL && element()->parent_field() != NULL) { + if (IsStructValue(*element()->parent_field())) { + // Since it is g.p.Value, we bind directly to the list_value. + // Render + // { // g.p.Value item within the list + // "list_value": { + // "values": [ + Push("", Item::MESSAGE, false, false); + Push("list_value", Item::MESSAGE, true, false); + Push("values", Item::MESSAGE, true, true); + return this; + } - field = StartListValueInStruct(field); - if (field == NULL) return this; + if (IsStructListValue(*element()->parent_field())) { + // Since it is g.p.ListValue, we bind to it directly. + // Render + // { // g.p.ListValue item within the list + // "values": [ + Push("", Item::MESSAGE, false, false); + Push("values", Item::MESSAGE, true, true); + return this; + } + } - element_type = ProtoElement::STRUCT_LIST; - } else { - // Lookup field corresponding to 'name'. If it is a google.protobuf.Value - // or google.protobuf.ListValue type, then StartList is a valid call, start - // this list. - // We cannot use Lookup() here as it will produce InvalidName() error if the - // field is not found. We do not want to error here as it would cause us to - // report errors twice, once here and again later in BeginNamed() call. - // Also we ignore if the field is not found here as it is caught later. - field = typeinfo_->FindField(&element_->type(), name); - - // Only check for oneof collisions on the first StartList call. We identify - // the first call with !name.empty() check. Subsequent list element calls - // will not have the name filled. - if (!name.empty() && field && !ValidOneof(*field, name)) { - ++invalid_depth_; + // Pass the event to underlying ProtoWriter. + Push(name, Item::MESSAGE, false, true); + return this; + } + + // name is not empty + const google::protobuf::Field* field = Lookup(name); + if (field == NULL) { + IncrementInvalidDepth(); + return this; + } + + if (IsStructValue(*field)) { + // If g.p.Value is repeated, start that list. Otherwise, start the + // "list_value" within it. + if (IsRepeated(*field)) { + // Render it just like a regular repeated field. + // "<name>": [ + Push(name, Item::MESSAGE, false, true); return this; } - // It is an error to try to bind to map, which behind the scenes is a list. - if (field && IsMap(*field)) { - // Push field to stack for error location tracking & reporting. - element_.reset(new ProtoElement(element_.release(), field, - *LookupType(field), - ProtoElement::MESSAGE)); - InvalidValue("Map", "Cannot bind a list to map."); - ++invalid_depth_; - element_.reset(element_->pop()); + // Start the "list_value" field. + // Render + // "<name>": { + // "list_value": { + // "values": [ + Push(name, Item::MESSAGE, false, false); + Push("list_value", Item::MESSAGE, true, false); + Push("values", Item::MESSAGE, true, true); + return this; + } + + if (IsStructListValue(*field)) { + // If g.p.ListValue is repeated, start that list. Otherwise, start the + // "values" within it. + if (IsRepeated(*field)) { + // Render it just like a regular repeated field. + // "<name>": [ + Push(name, Item::MESSAGE, false, true); return this; } - if (field && field->type_url() == GetFullTypeWithUrl(kStructValueType)) { - // There are 2 cases possible: - // a. g.p.Value is repeated - // b. g.p.Value is not repeated - // - // For case (a), the StartList should bind to the repeated g.p.Value. - // For case (b), the StartList should bind to g.p.ListValue within the - // g.p.Value. - // - // This means, for case (a), we treat it just like any other repeated - // message, except we would apply an appropriate element_type so future - // Start or Render calls are routed appropriately. - if (field->cardinality() != - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { - field = StartListValueInStruct(field); - } - element_type = ProtoElement::STRUCT_LIST; - } else if (field && - field->type_url() == GetFullTypeWithUrl(kStructListValueType)) { - // We got a StartList with google.protobuf.ListValue master type. This - // means we have to start the "values" within google.protobuf.ListValue. - field = StartRepeatedValuesInListValue(field); - } else { - // If no special types are to be bound, fall back to normal processing of - // StartList. - field = BeginNamed(name, true); - } - if (field == NULL) return this; + // Start the "values" field within g.p.ListValue. + // Render + // "<name>": { + // "values": [ + Push(name, Item::MESSAGE, false, false); + Push("values", Item::MESSAGE, true, true); + return this; + } + + // If we are here, the field should be repeated. Report an error otherwise. + if (!IsRepeated(*field)) { + IncrementInvalidDepth(); + InvalidName(name, "Proto field is not repeating, cannot start list."); + return this; } - const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { - ++invalid_depth_; - InvalidName(name, - StrCat("Missing descriptor for field: ", field->type_url())); + if (IsMap(*field)) { + InvalidValue("Map", + StrCat("Cannot bind a list to map for field '", name, "'.")); + IncrementInvalidDepth(); return this; } - element_.reset( - new ProtoElement(element_.release(), field, *type, element_type)); + // Pass the event to ProtoWriter. + // Render + // "<name>": [ + Push(name, Item::MESSAGE, false, true); return this; } ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() { - if (invalid_depth_ > 0) { - --invalid_depth_; - } else if (element_ != NULL) { - if (element_->IsAny()) { - element_->any()->EndList(); - } else { - element_.reset(element_->pop()); - // Skip sentinel elements added to keep track of new proto3 types - map, - // struct. - SkipElements(); - } + if (invalid_depth() > 0) { + DecrementInvalidDepth(); + return this; } - // When element_ is NULL, we have reached the root message type. Write out - // the bytes. - if (element_ == NULL) { - WriteRootMessage(); + if (current_ == NULL) return this; + + if (current_->IsAny()) { + current_->any()->EndList(); + return this; } + + Pop(); return this; } @@ -1059,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; @@ -1083,7 +853,7 @@ Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow, "null values are supported."); } } - ow->RenderDataPiece(struct_field_name, data); + ow->ProtoWriter::RenderDataPiece(struct_field_name, data); return Status::OK; } @@ -1105,15 +875,15 @@ Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, } - ow->RenderDataPiece("seconds", DataPiece(seconds)); - ow->RenderDataPiece("nanos", DataPiece(nanos)); + ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); + ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); return Status::OK; } static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, StringPiece path) { - ow->RenderDataPiece("paths", - DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase))); + ow->ProtoWriter::RenderDataPiece( + "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); return Status::OK; } @@ -1129,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()); } @@ -1162,224 +932,135 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, "Invalid duration format, failed to parse seconds"); } - double d_nanos = 0; - if (!safe_strtod("0." + s_nanos.ToString(), &d_nanos)) { - return Status(INVALID_ARGUMENT, - "Invalid duration format, failed to parse nanos seconds"); + int32 nanos = 0; + Status nanos_status = GetNanosFromStringPiece( + s_nanos, "Invalid duration format, failed to parse nano seconds", + "Duration value exceeds limits", &nanos); + if (!nanos_status.ok()) { + return nanos_status; } + nanos = sign * nanos; - int32 nanos = sign * static_cast<int32>(d_nanos * kNanosPerSecond); 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"); } - ow->RenderDataPiece("seconds", DataPiece(seconds)); - ow->RenderDataPiece("nanos", DataPiece(nanos)); + ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); + ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); return Status::OK; } Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow, const DataPiece& data) { - ow->RenderDataPiece("value", data); + ow->ProtoWriter::RenderDataPiece("value", data); return Status::OK; } ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( StringPiece name, const DataPiece& data) { Status status; - if (invalid_depth_ > 0) return this; - if (element_ != NULL && element_->IsAny()) { - element_->any()->RenderDataPiece(name, data); + if (invalid_depth() > 0) return this; + + if (current_ == NULL) { + const TypeRenderer* type_renderer = + FindTypeRenderer(GetFullTypeWithUrl(master_type_.name())); + if (type_renderer == NULL) { + InvalidName(name, "Root element must be a message."); + return this; + } + // Render the special type. + // "<name>": { + // ... Render special type ... + // } + ProtoWriter::StartObject(name); + status = (*type_renderer)(this, data); + if (!status.ok()) { + InvalidValue(master_type_.name(), + StrCat("Field '", name, "', ", status.error_message())); + } + ProtoWriter::EndObject(); + return this; + } + + if (current_->IsAny()) { + current_->any()->RenderDataPiece(name, data); return this; } const google::protobuf::Field* field = NULL; - string type_url; - bool is_map_entry = false; - // We are at the root when element_ == NULL. - if (element_ == NULL) { - type_url = GetFullTypeWithUrl(master_type_.name()); - } else { - if (element_->IsMap() || element_->IsStructMap()) { - if (!ValidMapKey(name)) return this; - is_map_entry = true; - field = StartMapEntry(name); - } else { - field = Lookup(name); - } + if (current_->IsMap()) { + if (!ValidMapKey(name)) return this; + + // Render an item in repeated map list. + // { "key": "<name>", "value": + Push("", Item::MESSAGE, false, false); + 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."; return this; } - // Check to see if this field is a oneof and that no oneof in that group has - // already been set. - if (!ValidOneof(*field, name)) return this; + const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); + if (type_renderer != NULL) { + // Map's value type is a special type. Render it like a message: + // "value": { + // ... Render special type ... + // } + Push("value", Item::MESSAGE, true, false); + status = (*type_renderer)(this, data); + if (!status.ok()) { + InvalidValue(field->type_url(), + StrCat("Field '", name, "', ", status.error_message())); + } + Pop(); + return this; + } - type_url = field->type_url(); + // If we are rendering explicit null values and the backend proto field is + // not of the google.protobuf.NullType type, we do nothing. + if (data.type() == DataPiece::TYPE_NULL && + field->type_url() != kStructNullValueTypeUrl) { + Pop(); + return this; + } + + // Render the map value as a primitive type. + ProtoWriter::RenderDataPiece("value", data); + Pop(); + return this; } - // Check if there are any well known type renderers available for type_url. - const TypeRenderer* type_renderer = FindTypeRenderer(type_url); + field = Lookup(name); + if (field == NULL) return this; + + // Check if the field is of special type. Render it accordingly if so. + const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); if (type_renderer != NULL) { - // Push the current element to stack so lookups in type_renderer will - // find the fields. We do an EndObject soon after, which pops this. This is - // safe because all well-known types are messages. - if (element_ == NULL) { - element_.reset(new ProtoElement(typeinfo_, master_type_, this)); - } else { - if (field) { - WriteTag(*field); - const google::protobuf::Type* type = LookupType(field); - element_.reset(new ProtoElement(element_.release(), field, *type, - ProtoElement::MESSAGE)); - } - } + Push(name, Item::MESSAGE, false, false); status = (*type_renderer)(this, data); if (!status.ok()) { - InvalidValue(type_url, + InvalidValue(field->type_url(), StrCat("Field '", name, "', ", status.error_message())); } - EndObject(); - return this; - } else if (element_ == NULL) { // no message type found at root - element_.reset(new ProtoElement(typeinfo_, master_type_, this)); - InvalidName(name, "Root element must be a message."); + Pop(); return this; } - if (field == NULL) { - return this; - } - const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { - InvalidName(name, - StrCat("Missing descriptor for field: ", field->type_url())); + // If we are rendering explicit null values and the backend proto field is + // not of the google.protobuf.NullType type, we do nothing. + if (data.type() == DataPiece::TYPE_NULL && + field->type_url() != kStructNullValueTypeUrl) { return this; } - // Whether we should pop at the end. Set to true if the data field is a - // message type, which can happen in case of struct values. - bool should_pop = false; - - RenderSimpleDataPiece(*field, *type, data); - - if (should_pop && element_ != NULL) { - element_.reset(element_->pop()); - } - - if (is_map_entry) { - // Ending map is the same as ending an object. - EndObject(); - } + ProtoWriter::RenderDataPiece(name, data); return this; } -void ProtoStreamObjectWriter::RenderSimpleDataPiece( - const google::protobuf::Field& field, const google::protobuf::Type& type, - const DataPiece& data) { - // If we are rendering explicit null values and the backend proto field is not - // of the google.protobuf.NullType type, we do nothing. - if (data.type() == DataPiece::TYPE_NULL && - field.type_url() != kStructNullValueTypeUrl) { - return; - } - - // 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, - ProtoElement::MESSAGE)); - - // Make sure that field represents a simple data type. - 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("")); - return; - } - - Status status; - switch (field.kind()) { - case google::protobuf::Field_Kind_TYPE_INT32: { - status = WriteInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SFIXED32: { - status = WriteSFixed32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SINT32: { - status = WriteSInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FIXED32: { - status = WriteFixed32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_UINT32: { - status = WriteUInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_INT64: { - status = WriteInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SFIXED64: { - status = WriteSFixed64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SINT64: { - status = WriteSInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FIXED64: { - status = WriteFixed64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_UINT64: { - status = WriteUInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_DOUBLE: { - status = WriteDouble(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FLOAT: { - status = WriteFloat(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_BOOL: { - status = WriteBool(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_BYTES: { - status = WriteBytes(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_STRING: { - 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()), - stream_.get()); - break; - } - default: // TYPE_GROUP or TYPE_MESSAGE - status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); - } - if (!status.ok()) { - InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), - status.error_message()); - } - element_.reset(element_->pop()); -} - // Map of functions that are responsible for rendering well known type // represented by the key. hash_map<string, ProtoStreamObjectWriter::TypeRenderer>* @@ -1446,45 +1127,12 @@ ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) { return FindOrNull(*renderers_, type_url); } -ProtoStreamObjectWriter::ProtoElement::ElementType -ProtoStreamObjectWriter::GetElementType(const google::protobuf::Type& type) { - if (type.name() == kAnyType) { - return ProtoElement::ANY; - } else if (type.name() == kStructType) { - return ProtoElement::STRUCT; - } else if (type.name() == kStructValueType) { - return ProtoElement::STRUCT_VALUE; - } else if (type.name() == kStructListValueType) { - return ProtoElement::STRUCT_LIST_VALUE; - } else { - return ProtoElement::MESSAGE; - } -} - -bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field, - StringPiece unnormalized_name) { - if (element_ == NULL) return true; - - if (field.oneof_index() > 0) { - if (element_->OneofIndexTaken(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 ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) { - if (element_ == NULL) return true; + if (current_ == NULL) return true; - if (!element_->InsertMapKeyIfNotPresent(unnormalized_name)) { - InvalidName( - unnormalized_name, + if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) { + listener()->InvalidName( + location(), unnormalized_name, StrCat("Repeated map key: '", unnormalized_name, "' is already set.")); return false; } @@ -1492,134 +1140,30 @@ bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) { return true; } -const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed( - StringPiece name, bool is_list) { - if (invalid_depth_ > 0) { - ++invalid_depth_; - return NULL; - } - const google::protobuf::Field* field = Lookup(name); - if (field == NULL) { - ++invalid_depth_; - // InvalidName() already called in Lookup(). - return NULL; - } - if (is_list && - field->cardinality() != - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { - ++invalid_depth_; - InvalidName(name, "Proto field is not repeating, cannot start list."); - return NULL; - } - return field; -} +void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type, + bool is_placeholder, bool is_list) { + is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name); -const google::protobuf::Field* ProtoStreamObjectWriter::Lookup( - StringPiece unnormalized_name) { - ProtoElement* e = element(); - if (e == NULL) { - InvalidName(unnormalized_name, "Root element must be a message."); - return NULL; - } - if (unnormalized_name.empty()) { - // Objects in repeated field inherit the same field descriptor. - if (e->field() == NULL) { - InvalidName(unnormalized_name, "Proto fields must have a name."); - } else if (e->field()->cardinality() != - google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { - InvalidName(unnormalized_name, "Proto fields must have a name."); - return NULL; - } - return e->field(); - } - const google::protobuf::Field* field = - typeinfo_->FindField(&e->type(), unnormalized_name); - if (field == NULL) InvalidName(unnormalized_name, "Cannot find field."); - return field; -} - -const google::protobuf::Type* ProtoStreamObjectWriter::LookupType( - const google::protobuf::Field* field) { - return (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE - ? typeinfo_->GetTypeByTypeUrl(field->type_url()) - : &element_->type()); + // invalid_depth == 0 means it is a successful StartObject or StartList. + if (invalid_depth() == 0) + current_.reset( + new Item(current_.release(), item_type, is_placeholder, is_list)); } -// Looks up the oneof struct field based on the data type. -StatusOr<const google::protobuf::Field*> -ProtoStreamObjectWriter::LookupStructField(DataPiece::Type type) { - const google::protobuf::Field* field = NULL; - switch (type) { - // Our JSON parser parses numbers as either int64, uint64, or double. - case DataPiece::TYPE_INT64: - case DataPiece::TYPE_UINT64: - case DataPiece::TYPE_DOUBLE: { - field = Lookup("number_value"); - break; - } - case DataPiece::TYPE_STRING: { - field = Lookup("string_value"); - break; - } - case DataPiece::TYPE_BOOL: { - field = Lookup("bool_value"); - break; - } - case DataPiece::TYPE_NULL: { - field = Lookup("null_value"); - break; - } - default: { return Status(INVALID_ARGUMENT, "Invalid struct data type"); } +void ProtoStreamObjectWriter::Pop() { + // Pop all placeholder items sending StartObject or StartList events to + // ProtoWriter according to is_list value. + while (current_ != NULL && current_->is_placeholder()) { + PopOneElement(); } - if (field == NULL) { - return Status(INVALID_ARGUMENT, "Could not lookup struct field"); + if (current_ != NULL) { + PopOneElement(); } - return field; } -void ProtoStreamObjectWriter::WriteRootMessage() { - GOOGLE_DCHECK(!done_); - int curr_pos = 0; - // Calls the destructor of CodedOutputStream to remove any uninitialized - // memory from the Cord before we read it. - stream_.reset(NULL); - const void* data; - int length; - google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size()); - while (input_stream.Next(&data, &length)) { - if (length == 0) continue; - int num_bytes = length; - // Write up to where we need to insert the size field. - // The number of bytes we may write is the smaller of: - // - the current fragment size - // - the distance to the next position where a size field needs to be - // inserted. - if (!size_insert_.empty() && - size_insert_.front().pos - curr_pos < num_bytes) { - num_bytes = size_insert_.front().pos - curr_pos; - } - output_->Append(static_cast<const char*>(data), num_bytes); - if (num_bytes < length) { - input_stream.BackUp(length - num_bytes); - } - curr_pos += num_bytes; - // Insert the size field. - // size_insert_.front(): the next <index, size> pair to be written. - // size_insert_.front().pos: position of the size field. - // size_insert_.front().size: the size (integer) to be inserted. - if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) { - // Varint32 occupies at most 10 bytes. - uint8 insert_buffer[10]; - uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray( - size_insert_.front().size, insert_buffer); - output_->Append(reinterpret_cast<const char*>(insert_buffer), - insert_buffer_pos - insert_buffer); - size_insert_.pop_front(); - } - } - output_->Flush(); - stream_.reset(new CodedOutputStream(&adapter_)); - done_ = true; +void ProtoStreamObjectWriter::PopOneElement() { + current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject(); + current_.reset(current_->pop<Item>()); } bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { @@ -1630,7 +1174,7 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { return false; } const google::protobuf::Type* field_type = - typeinfo_->GetTypeByTypeUrl(field.type_url()); + typeinfo()->GetTypeByTypeUrl(field.type_url()); // TODO(xiaofeng): Unify option names. return GetBoolOptionOrDefault(field_type->options(), @@ -1638,12 +1182,23 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { GetBoolOptionOrDefault(field_type->options(), "map_entry", false); } -void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) { - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast<WireFormatLite::FieldType>(field.kind())); - stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); +bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) { + return GetTypeWithoutUrl(field.type_url()) == kAnyType; } +bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) { + return GetTypeWithoutUrl(field.type_url()) == kStructType; +} + +bool ProtoStreamObjectWriter::IsStructValue( + const google::protobuf::Field& field) { + return GetTypeWithoutUrl(field.type_url()) == kStructValueType; +} + +bool ProtoStreamObjectWriter::IsStructListValue( + const google::protobuf::Field& field) { + return GetTypeWithoutUrl(field.type_url()) == kStructListValueType; +} } // namespace converter } // namespace util diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index 19f747fe..e1162d43 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -42,6 +42,7 @@ #include <google/protobuf/util/internal/type_info.h> #include <google/protobuf/util/internal/datapiece.h> #include <google/protobuf/util/internal/error_listener.h> +#include <google/protobuf/util/internal/proto_writer.h> #include <google/protobuf/util/internal/structured_objectwriter.h> #include <google/protobuf/util/type_resolver.h> #include <google/protobuf/stubs/bytestream.h> @@ -67,14 +68,36 @@ namespace converter { class ObjectLocationTracker; // An ObjectWriter that can write protobuf bytes directly from writer events. +// This class supports all special types like Struct and Map. It uses +// the ProtoWriter class to write raw proto bytes. // // It also supports streaming. -class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter { +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. @@ -82,56 +105,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter virtual ProtoStreamObjectWriter* EndObject(); virtual ProtoStreamObjectWriter* StartList(StringPiece name); virtual ProtoStreamObjectWriter* EndList(); - virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, bool value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, int32 value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name, - uint32 value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, int64 value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name, - uint64 value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderDouble(StringPiece name, - double value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, float value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderString(StringPiece name, - StringPiece value) { - return RenderDataPiece(name, DataPiece(value)); - } - virtual ProtoStreamObjectWriter* RenderBytes(StringPiece name, - StringPiece value) { - return RenderDataPiece(name, DataPiece(value, false)); - } - virtual ProtoStreamObjectWriter* RenderNull(StringPiece name) { - return RenderDataPiece(name, DataPiece::NullData()); - } // Renders a DataPiece 'value' into a field whose wire type is determined // from the given field 'name'. - ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, - const DataPiece& value); - - // Returns the location tracker to use for tracking locations for errors. - const LocationTrackerInterface& location() { - return element_ != NULL ? *element_ : *tracker_; - } + virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, + const DataPiece& value); - // When true, we finished writing to output a complete message. - bool done() const { return done_; } - - private: + protected: // Function that renders a well known type with modified behavior. typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*, const DataPiece&); @@ -187,78 +167,47 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // 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_; }; - class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface { + // Represents an item in a stack of items used to keep state between + // ObjectWrier events. + class LIBPROTOBUF_EXPORT Item : public BaseElement { public: - // Indicates the type of element. Special types like LIST, MAP, MAP_ENTRY, - // STRUCT etc. are used to deduce other information based on their position - // on the stack of elements. - enum ElementType { - MESSAGE, // Simple message - LIST, // List/repeated element - MAP, // Proto3 map type - MAP_ENTRY, // Proto3 map message type, with 'key' and 'value' fields - ANY, // Proto3 Any type - STRUCT, // Proto3 struct type - STRUCT_VALUE, // Struct's Value message type - STRUCT_LIST, // List type indicator within a struct - STRUCT_LIST_VALUE, // Struct Value's ListValue message type - STRUCT_MAP, // Struct within a struct type - STRUCT_MAP_ENTRY // Struct map's entry type with 'key' and 'value' - // fields + // Indicates the type of item. + enum ItemType { + MESSAGE, // Simple message + MAP, // Proto3 map type + ANY, // Proto3 Any type }; - // Constructor for the root element. No parent nor field. - ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, - ProtoStreamObjectWriter* enclosing); - - // Constructor for a field of an element. - ProtoElement(ProtoElement* parent, const google::protobuf::Field* field, - const google::protobuf::Type& type, ElementType element_type); + // Constructor for the root item. + Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, + bool is_placeholder, bool is_list); - virtual ~ProtoElement() {} + // Constructor for a field of a message. + Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); - // Called just before the destructor for clean up: - // - reports any missing required fields - // - computes the space needed by the size field, and augment the - // length of all parent messages by this additional space. - // - releases and returns the parent pointer. - ProtoElement* pop(); - - // Accessors - const google::protobuf::Field* field() const { return field_; } - const google::protobuf::Type& type() const { return type_; } + virtual ~Item() {} // These functions return true if the element type is corresponding to the // type in function name. - bool IsMap() { return element_type_ == MAP; } - bool IsStructMap() { return element_type_ == STRUCT_MAP; } - bool IsStructMapEntry() { return element_type_ == STRUCT_MAP_ENTRY; } - bool IsStructList() { return element_type_ == STRUCT_LIST; } - bool IsAny() { return element_type_ == ANY; } - - ElementType element_type() { return element_type_; } - - void RegisterField(const google::protobuf::Field* field); - virtual string ToString() const; + bool IsMap() { return item_type_ == MAP; } + bool IsAny() { return item_type_ == ANY; } AnyWriter* any() const { return any_.get(); } - virtual ProtoElement* parent() const { - return static_cast<ProtoElement*>(BaseElement::parent()); + virtual Item* parent() const { + return static_cast<Item*>(BaseElement::parent()); } - // Returns true if the index is already taken by a preceeding oneof input. - bool OneofIndexTaken(int32 index); - - // Marks the oneof 'index' as taken. Future inputs to this oneof will - // generate an error. - void TakeOneofIndex(int32 index); - // Inserts map key into hash set if and only if the key did NOT already // exist in hash set. // The hash set (map_keys_) is ONLY used to keep track of map keys. @@ -266,6 +215,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // already present. bool InsertMapKeyIfNotPresent(StringPiece map_key); + bool is_placeholder() const { return is_placeholder_; } + bool is_list() const { return is_list_; } + private: // Used for access to variables of the enclosing instance of // ProtoStreamObjectWriter. @@ -274,126 +226,42 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // A writer for Any objects, handles all Any-related nonsense. google::protobuf::scoped_ptr<AnyWriter> any_; - // Describes the element as a field in the parent message. - // field_ is NULL if and only if this element is the root element. - const google::protobuf::Field* field_; - - // TypeInfo to lookup types. - const TypeInfo* typeinfo_; - - // Additional variables if this element is a message: - // (Root element is always a message). - // descriptor_ : describes allowed fields in the message. - // required_fields_: set of required fields. - // is_repeated_type_ : true if the element is of type list or map. - // size_index_ : index into ProtoStreamObjectWriter::size_insert_ - // for later insertion of serialized message length. - const google::protobuf::Type& type_; - std::set<const google::protobuf::Field*> required_fields_; - const bool is_repeated_type_; - const int size_index_; - - // Tracks position in repeated fields, needed for LocationTrackerInterface. - int array_index_; - // The type of this element, see enum for permissible types. - ElementType element_type_; - - // Set of oneof indices already seen for the type_. Used to validate - // incoming messages so no more than one oneof is set. - hash_set<int32> oneof_indices_; + ItemType item_type_; // Set of map keys already seen for the type_. Used to validate incoming // messages so no map key appears more than once. - hash_set<StringPiece> map_keys_; + hash_set<string> map_keys_; - GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); - }; + // Conveys whether this Item is a placeholder or not. Placeholder items are + // pushed to stack to account for special types. + bool is_placeholder_; + + // Conveys whether this Item is a list or not. This is used to send + // StartList or EndList calls to underlying ObjectWriter. + bool is_list_; - // Container for inserting 'size' information at the 'pos' position. - struct SizeInfo { - const int pos; - int size; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item); }; ProtoStreamObjectWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); - ProtoElement* element() { return element_.get(); } - - // Helper methods for calling ErrorListener. See error_listener.h. - void InvalidName(StringPiece unknown_name, StringPiece message); - void InvalidValue(StringPiece type_name, StringPiece value); - void MissingField(StringPiece missing_name); - - // Common code for BeginObject() and BeginList() that does invalid_depth_ - // bookkeeping associated with name lookup. - const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list); - - // Lookup the field in the current element. Looks in the base descriptor - // and in any extension. This will report an error if the field cannot be - // found or if multiple matching extensions are found. - const google::protobuf::Field* Lookup(StringPiece name); - - // Lookup the field type in the type descriptor. Returns NULL if the type - // is not known. - const google::protobuf::Type* LookupType( - const google::protobuf::Field* field); - - // Looks up the oneof struct Value field depending on the type. - // On failure to find, it returns an appropriate error. - util::StatusOr<const google::protobuf::Field*> LookupStructField( - DataPiece::Type type); - - // Starts an entry in map. This will be called after placing map element at - // the top of the stack. Uses this information to write map entries. - const google::protobuf::Field* StartMapEntry(StringPiece name); - - // Starts a google.protobuf.Struct. - // 'field' is of type google.protobuf.Struct. - // If field is NULL, it indicates that the top-level message is a struct - // type. - void StartStruct(const google::protobuf::Field* field); - - // Starts another struct within a struct. - // 'field' is of type google.protobuf.Value (see struct.proto). - const google::protobuf::Field* StartStructValueInStruct( - const google::protobuf::Field* field); - - // Starts a list within a struct. - // 'field' is of type google.protobuf.ListValue (see struct.proto). - const google::protobuf::Field* StartListValueInStruct( - const google::protobuf::Field* field); - - // Starts the repeated "values" field in struct.proto's - // google.protobuf.ListValue type. 'field' should be of type - // google.protobuf.ListValue. - const google::protobuf::Field* StartRepeatedValuesInListValue( - const google::protobuf::Field* field); - - // Pops sentinel elements off the stack. - void SkipElements(); - - // Write serialized output to the final output ByteSink, inserting all - // the size information for nested messages that are missing from the - // intermediate Cord buffer. - void WriteRootMessage(); - // Returns true if the field is a map. bool IsMap(const google::protobuf::Field& field); // Returns true if the field is an any. bool IsAny(const google::protobuf::Field& field); - // Helper method to write proto tags based on the given field. - void WriteTag(const google::protobuf::Field& field); + // Returns true if the field is google.protobuf.Struct. + bool IsStruct(const google::protobuf::Field& field); + // Returns true if the field is google.protobuf.Value. + bool IsStructValue(const google::protobuf::Field& field); - // Helper function to render primitive data types in DataPiece. - void RenderSimpleDataPiece(const google::protobuf::Field& field, - const google::protobuf::Type& type, - const DataPiece& data); + // Returns true if the field is google.protobuf.ListValue. + bool IsStructListValue(const google::protobuf::Field& field); // Renders google.protobuf.Value in struct.proto. It picks the right oneof // type based on value's type. @@ -417,69 +285,49 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow, const DataPiece& value); - // Helper functions to create the map and find functions responsible for - // rendering well known types, keyed by type URL. - static hash_map<string, TypeRenderer>* renderers_; static void InitRendererMap(); static void DeleteRendererMap(); static TypeRenderer* FindTypeRenderer(const string& type_url); - // Returns the ProtoElement::ElementType for the given Type. - static ProtoElement::ElementType GetElementType( - const google::protobuf::Type& type); - - // Returns true if the field for type_ can be set as a oneof. If field is not - // a oneof type, this function does nothing and returns true. - // If another field for this oneof is already set, this function returns - // false. It also calls the appropriate error callback. - // unnormalized_name is used for error string. - bool ValidOneof(const google::protobuf::Field& field, - StringPiece unnormalized_name); - // Returns true if the map key for type_ is not duplicated key. // If map key is duplicated key, this function returns false. - // Note that caller should make sure that the current proto element (element_) + // Note that caller should make sure that the current proto element (current_) // is of element type MAP or STRUCT_MAP. // It also calls the appropriate error callback and unnormalzied_name is used // for error string. bool ValidMapKey(StringPiece unnormalized_name); + // Pushes an item on to the stack. Also calls either StartObject or StartList + // on the underlying ObjectWriter depending on whether is_list is false or + // not. + // is_placeholder conveys whether the item is a placeholder item or not. + // Placeholder items are pushed when adding auxillary types' StartObject or + // StartList calls. + void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder, + bool is_list); + + // Pops items from the stack. All placeholder items are popped until a + // non-placeholder item is found. + void Pop(); + + // Pops one element from the stack. Calls EndObject() or EndList() on the + // underlying ObjectWriter depending on the value of is_list_. + void PopOneElement(); + + private: + // Helper functions to create the map and find functions responsible for + // rendering well known types, keyed by type URL. + static hash_map<string, TypeRenderer>* renderers_; + // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. - // typeinfo_ : the TypeInfo object to lookup types. const google::protobuf::Type& master_type_; - const TypeInfo* typeinfo_; - // Whether we own the typeinfo_ object. - bool own_typeinfo_; - - // Indicates whether we finished writing root message completely. - bool done_; - - // Variable for internal state processing: - // element_ : the current element. - // size_insert_: sizes of nested messages. - // pos - position to insert the size field. - // size - size value to be inserted. - google::protobuf::scoped_ptr<ProtoElement> element_; - std::deque<SizeInfo> size_insert_; - - // Variables for output generation: - // output_ : pointer to an external ByteSink for final user-visible output. - // buffer_ : buffer holding partial message before being ready for output_. - // adapter_ : internal adapter between CodedOutputStream and Cord buffer_. - // stream_ : wrapper for writing tags and other encodings in wire format. - strings::ByteSink* output_; - string buffer_; - google::protobuf::io::StringOutputStream adapter_; - google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_; - - // Variables for error tracking and reporting: - // listener_ : a place to report any errors found. - // invalid_depth_: number of enclosing invalid nested messages. - // tracker_ : the root location tracker interface. - ErrorListener* listener_; - int invalid_depth_; - google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_; + + // 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 cb9f97f7..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; @@ -241,6 +249,21 @@ TEST_P(ProtoStreamObjectWriterTest, SimpleMessage) { CheckOutput(book); } +TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) { + Book book; + Author* robert = book.mutable_author(); + robert->set_id(12345); + robert->set_name("robert"); + + ow_->StartObject("") + ->StartObject("author") + ->RenderUint64("@id", 12345) + ->RenderString("name", "robert") + ->EndObject() + ->EndObject(); + CheckOutput(book); +} + TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { Primitive full; full.set_fix32(101); @@ -274,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") @@ -348,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\""))) @@ -382,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\""))) @@ -796,10 +816,6 @@ TEST_P(ProtoStreamObjectWriterTest, RootNamedList) { InvalidName(_, StringPiece("oops"), StringPiece("Root element should not be named."))) .With(Args<0>(HasObjectLocation(""))); - EXPECT_CALL(listener_, - InvalidName(_, StringPiece(""), - StringPiece("Proto fields must have a name."))) - .With(Args<0>(HasObjectLocation(""))); ow_->StartList("oops")->RenderString("", "item")->EndList(); CheckOutput(empty, 0); } @@ -864,6 +880,136 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, ::testing::Values( testing::USE_TYPE_RESOLVER)); +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(1448249855); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "2015-11-23T03:37:35.033155Z") + ->EndObject(); + 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; @@ -914,17 +1060,90 @@ 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", "-8031-10-18T00:00:00.000Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2015-11-23T03:37:35.033155 Z"))); + + ow_->StartObject("") + // Whitespace in the Timestamp nanos is not allowed. + ->RenderString("ts", "2015-11-23T03:37:35.033155 Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2015-11-23T03:37:35.033155 1234Z"))); + + ow_->StartObject("") + // Whitespace in the Timestamp nanos is not allowed. + ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2015-11-23T03:37:35.033abc155Z"))); + + ow_->StartObject("") + // Non-numeric characters in the Timestamp nanos is not allowed. + ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z") + ->EndObject(); + 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", "-8032-10-18T00:00:00.000Z") + ->RenderString("ts", "0-12-31T23:59:59.000Z") ->EndObject(); CheckOutput(timestamp); } -// TODO(skarvaje): Write a test for nanos that exceed limit. Currently, it is -// not possible to construct a test case where nanos exceed limit because of -// floating point arithmetic. +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) { + TimestampDuration duration; + google::protobuf::Duration* dur = duration.mutable_dur(); + dur->set_seconds(1448216930); + dur->set_nanos(132262000); + + ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject(); + CheckOutput(duration); +} TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) { TimestampDuration duration; @@ -962,7 +1181,7 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) { InvalidValue( _, StringPiece("type.googleapis.com/google.protobuf.Duration"), StringPiece("Field 'dur', Invalid duration format, failed to " - "parse nanos seconds"))); + "parse nano seconds"))); ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject(); CheckOutput(duration); @@ -981,6 +1200,19 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) { CheckOutput(duration); } +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) { + TimestampDuration duration; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Duration value exceeds limits"))); + + ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject(); + CheckOutput(duration); +} + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, MismatchedTimestampTypeInput) { TimestampDuration timestamp; @@ -1012,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()); @@ -1066,12 +1301,12 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) { TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) { EXPECT_CALL( listener_, - InvalidName(_, StringPiece("k1"), - StringPiece("Repeated map key: 'k1' is already set."))); + InvalidName(_, StringPiece("gBike"), + StringPiece("Repeated map key: 'gBike' is already set."))); ow_->StartObject("") ->StartObject("object") - ->RenderString("k1", "v1") - ->RenderString("k1", "v2") + ->RenderString("gBike", "v1") + ->RenderString("gBike", "v2") ->EndObject() ->EndObject(); } @@ -1108,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() @@ -1121,10 +1378,11 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { MapIn mm; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Map"), - StringPiece("Cannot bind a list to map."))) - .With(Args<0>(HasObjectLocation("map_input"))); + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Map"), + StringPiece("Cannot bind a list to map for field 'map_input'."))); ow_->StartObject("") ->StartList("map_input") ->RenderString("a", "b") @@ -1155,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); } }; @@ -1363,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: @@ -1591,13 +2067,17 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) { TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { FieldMaskTest expected; expected.mutable_single_mask()->add_paths( - "path.to.map[\"(),[],\\\"'!@#$%^&*123_|Warå™å¤©æ¶Œ,./?><\\\\\"]"); + // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character å™. + // We cannot embed non-ASCII characters in the code directly because + // some windows compilers will try to interpret them using the system's + // current encoding and end up with invalid UTF-8 byte sequence. + "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]"); expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]"); ow_->StartObject(""); ow_->RenderString( "single_mask", - "path.to.map[\"(),[],\\\"'!@#$%^&*123_|Warå™å¤©æ¶Œ,./?><\\\\\"]," + "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]," "path.to.map[\"key2\"]"); ow_->EndObject(); diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter.h b/src/google/protobuf/util/internal/snake2camel_objectwriter.h deleted file mode 100644 index 9b4ab8a3..00000000 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter.h +++ /dev/null @@ -1,165 +0,0 @@ -// 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_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__ - -#include <string> - -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/stringpiece.h> -#include <google/protobuf/util/internal/object_writer.h> -#include <google/protobuf/util/internal/utility.h> - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// Snake2CamelObjectWriter is an ObjectWriter than translates each field name -// from snake_case to camelCase. Typical usage is: -// ProtoStreamObjectSource psos(...); -// JsonObjectWriter jow(...); -// Snake2CamelObjectWriter snake_to_camel(&jow); -// psos.writeTo(&snake_to_camel); -class Snake2CamelObjectWriter : public ObjectWriter { - public: - explicit Snake2CamelObjectWriter(ObjectWriter* ow) - : ow_(ow), normalize_case_(true) {} - virtual ~Snake2CamelObjectWriter() {} - - // ObjectWriter methods. - virtual Snake2CamelObjectWriter* StartObject(StringPiece name) { - ow_->StartObject(name); - return this; - } - - virtual Snake2CamelObjectWriter* EndObject() { - ow_->EndObject(); - return this; - } - - virtual Snake2CamelObjectWriter* StartList(StringPiece name) { - ow_->StartList(name); - return this; - } - - virtual Snake2CamelObjectWriter* EndList() { - ow_->EndList(); - return this; - } - - virtual Snake2CamelObjectWriter* RenderBool(StringPiece name, bool value) { - ow_->RenderBool(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderInt32(StringPiece name, int32 value) { - ow_->RenderInt32(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderUint32(StringPiece name, - uint32 value) { - ow_->RenderUint32(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderInt64(StringPiece name, int64 value) { - ow_->RenderInt64(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderUint64(StringPiece name, - uint64 value) { - ow_->RenderUint64(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderDouble(StringPiece name, - double value) { - ow_->RenderDouble(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderFloat(StringPiece name, float value) { - ow_->RenderFloat(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderString(StringPiece name, - StringPiece value) { - ow_->RenderString(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderBytes(StringPiece name, - StringPiece value) { - ow_->RenderBytes(name, value); - return this; - } - - virtual Snake2CamelObjectWriter* RenderNull(StringPiece name) { - ow_->RenderNull(name); - return this; - } - - virtual Snake2CamelObjectWriter* DisableCaseNormalizationForNextKey() { - normalize_case_ = false; - return this; - } - - private: - ObjectWriter* ow_; - bool normalize_case_; - - bool ShouldNormalizeCase(StringPiece name) { - if (normalize_case_) { - return !IsCamel(name); - } else { - normalize_case_ = true; - return false; - } - } - - bool IsCamel(StringPiece name) { - return name.empty() || (ascii_islower(name[0]) && !name.contains("_")); - } - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Snake2CamelObjectWriter); -}; - -} // namespace converter -} // namespace util -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto index 6e2f109b..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; } @@ -66,7 +73,7 @@ message Publisher { // An author of a book message Author { - optional uint64 id = 1; + optional uint64 id = 1 [json_name = "@id"]; optional string name = 2; repeated string pseudonym = 3; optional bool alive = 4; @@ -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/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto index ebbdf6ab..cccc741c 100644 --- a/src/google/protobuf/util/internal/testdata/default_value.proto +++ b/src/google/protobuf/util/internal/testdata/default_value.proto @@ -75,9 +75,10 @@ message DefaultValueTestCases { IntToStringMap int_to_string = 403; MixedMap mixed1 = 404; MixedMap2 mixed2 = 405; - MessageMap map_of_objects = 406; - MixedMap mixed_empty = 407; - MessageMap message_map_empty = 408; + MixedMap2 empty_mixed2 = 406; + MessageMap map_of_objects = 407; + MixedMap mixed_empty = 408; + MessageMap message_map_empty = 409; DoubleValueMessage double_value = 501; DoubleValueMessage double_value_default = 502; } diff --git a/src/google/protobuf/util/internal/testdata/default_value_test.proto b/src/google/protobuf/util/internal/testdata/default_value_test.proto index 21b85e6d..93288341 100644 --- a/src/google/protobuf/util/internal/testdata/default_value_test.proto +++ b/src/google/protobuf/util/internal/testdata/default_value_test.proto @@ -43,4 +43,11 @@ message DefaultValueTest { bool bool_value = 13; string string_value = 15; bytes bytes_value = 17 [ctype = CORD]; + + enum EnumDefault { + ENUM_FIRST = 0; + ENUM_SECOND = 1; + ENUM_THIRD = 2; + } + EnumDefault enum_value = 18; } diff --git a/src/google/protobuf/util/internal/testdata/maps.proto b/src/google/protobuf/util/internal/testdata/maps.proto index 7fb42a26..6475ecdd 100644 --- a/src/google/protobuf/util/internal/testdata/maps.proto +++ b/src/google/protobuf/util/internal/testdata/maps.proto @@ -44,6 +44,35 @@ message MapOut { map<string, MapM> map1 = 1; map<string, MapOut> map2 = 2; map<int32, string> map3 = 3; + map<bool, string> map4 = 5; + string bar = 4; +} + +// A message with exactly the same wire representation as MapOut, but using +// repeated message fields instead of map fields. We use this message to test +// the wire-format compatibility of the JSON transcoder (e.g., whether it +// handles missing keys correctly). +message MapOutWireFormat { + message Map1Entry { + string key = 1; + MapM value = 2; + } + repeated Map1Entry map1 = 1; + message Map2Entry { + string key = 1; + MapOut value = 2; + } + repeated Map2Entry map2 = 2; + message Map3Entry { + int32 key = 1; + string value = 2; + } + repeated Map3Entry map3 = 3; + message Map4Entry { + bool key = 1; + string value = 2; + } + repeated Map4Entry map4 = 5; string bar = 4; } diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc index a45a76e3..00a8ee7a 100644 --- a/src/google/protobuf/util/internal/type_info.cc +++ b/src/google/protobuf/util/internal/type_info.cc @@ -136,8 +136,7 @@ class TypeInfoForTypeResolver : public TypeInfo { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); StringPiece name = field.name(); - StringPiece camel_case_name = - *string_storage_.insert(ToCamelCase(name)).first; + StringPiece camel_case_name = field.json_name(); const StringPiece* existing = InsertOrReturnExisting( &camel_case_name_table_, camel_case_name, name); if (existing && *existing != name) { 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 61899c24..ee7a51fc 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -49,7 +49,8 @@ namespace converter { namespace { const StringPiece SkipWhiteSpace(StringPiece str) { StringPiece::size_type i; - for (i = 0; i < str.size() && isspace(str[i]); ++i) {} + for (i = 0; i < str.size() && isspace(str[i]); ++i) { + } GOOGLE_DCHECK(i == str.size() || !isspace(str[i])); return StringPiece(str, i); } @@ -160,6 +161,19 @@ const google::protobuf::Field* FindFieldInTypeOrNull( return NULL; } +const google::protobuf::Field* FindJsonFieldInTypeOrNull( + const google::protobuf::Type* type, StringPiece json_name) { + if (type != NULL) { + for (int i = 0; i < type->fields_size(); ++i) { + const google::protobuf::Field& field = type->fields(i); + if (field.json_name() == json_name) { + return &field; + } + } + } + return NULL; +} + const google::protobuf::EnumValue* FindEnumValueByNameOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name) { if (enum_type != NULL) { @@ -208,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; @@ -217,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; } @@ -316,16 +335,23 @@ string FloatAsString(float value) { return DoubleAsString(value); } -bool SafeStrToFloat(StringPiece str, float *value) { +bool SafeStrToFloat(StringPiece str, float* value) { double double_value; if (!safe_strtod(str, &double_value)) { return false; } - *value = static_cast<float>(double_value); - if (MathLimits<float>::IsInf(*value)) { + if (MathLimits<double>::IsInf(double_value) || + MathLimits<double>::IsNaN(double_value)) + return false; + + // Fail if the value is not representable in float. + if (double_value > std::numeric_limits<float>::max() || + double_value < -std::numeric_limits<float>::max()) { return false; } + + *value = static_cast<float>(double_value); return true; } diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h index 5ba97bd2..33df8eda 100644 --- a/src/google/protobuf/util/internal/utility.h +++ b/src/google/protobuf/util/internal/utility.h @@ -127,6 +127,11 @@ const google::protobuf::Option* FindOptionOrNull( const google::protobuf::Field* FindFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece field_name); +// Similar to FindFieldInTypeOrNull, but this looks up fields with given +// json_name. +const google::protobuf::Field* FindJsonFieldInTypeOrNull( + const google::protobuf::Type* type, StringPiece json_name); + // Finds and returns the EnumValue identified by enum_name in the passed tech // Enum object. Returns NULL if none found. const google::protobuf::EnumValue* FindEnumValueByNameOrNull( diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto index e8137677..a1e24c18 100644 --- a/src/google/protobuf/util/json_format_proto3.proto +++ b/src/google/protobuf/util/json_format_proto3.proto @@ -165,3 +165,12 @@ message TestListValue { google.protobuf.ListValue value = 1; repeated google.protobuf.ListValue repeated_value = 2; } + +message TestBoolValue { + bool bool_value = 1; + map<bool, int32> bool_map = 2; +} + +message TestCustomJsonName { + int32 value = 1 [json_name = "@value"]; +} 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 47237e5a..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> @@ -238,9 +239,25 @@ void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) { GOOGLE_CHECK(key_comparator == NULL) << "Cannot treat this repeated field as both Map and Set for" << " comparison. Field name is: " << field->full_name(); + GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end()) + << "Cannot treat the same field as both SET and LIST. Field name is: " + << field->full_name(); set_fields_.insert(field); } +void MessageDifferencer::TreatAsList(const FieldDescriptor* field) { + GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: " + << field->full_name(); + const MapKeyComparator* key_comparator = GetMapKeyComparator(field); + GOOGLE_CHECK(key_comparator == NULL) + << "Cannot treat this repeated field as both Map and Set for" + << " comparison. Field name is: " << field->full_name(); + GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end()) + << "Cannot treat the same field as both SET and LIST. Field name is: " + << field->full_name(); + list_fields_.insert(field); +} + void MessageDifferencer::TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key) { GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: " @@ -255,6 +272,9 @@ void MessageDifferencer::TreatAsMap(const FieldDescriptor* field, GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end()) << "Cannot treat this repeated field as both Map and Set for " << "comparison."; + GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end()) + << "Cannot treat this repeated field as both Map and List for " + << "comparison."; MapKeyComparator* key_comparator = new MultipleFieldsMapKeyComparator(this, key); owned_key_comparators_.push_back(key_comparator); @@ -436,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. @@ -920,7 +942,8 @@ bool MessageDifferencer::CheckPathChanged( bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) { if (!field->is_repeated()) return false; if (field->is_map()) return true; - if (repeated_field_comparison_ == AS_SET) return true; + if (repeated_field_comparison_ == AS_SET) + return list_fields_.find(field) == list_fields_.end(); return (set_fields_.find(field) != set_fields_.end()); } @@ -1001,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; } @@ -1011,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; @@ -1364,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/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index 34c173db..3ea74e67 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -397,9 +397,16 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // + n^3) in which n^3 is the time complexity of the maximum matching // algorithm. // - // REQUIRES: field->is_repeated() + // REQUIRES: field->is_repeated() and field not registered with TreatAsList void TreatAsSet(const FieldDescriptor* field); + // The elements of the given repeated field will be treated as a list for + // diffing purposes, so different orderings of the same elements will NOT be + // considered equal. + // + // REQUIRED: field->is_repeated() and field not registered with TreatAsSet + void TreatAsList(const FieldDescriptor* field); + // The elements of the given repeated field will be treated as a map for // diffing purposes, with |key| being the map key. Thus, elements with the // same key will be compared even if they do not appear at the same index. @@ -791,6 +798,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { RepeatedFieldComparison repeated_field_comparison_; FieldSet set_fields_; + FieldSet list_fields_; // Keeps track of MapKeyComparators that are created within // MessageDifferencer. These MapKeyComparators should be deleted // before MessageDifferencer is destroyed. diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index 701b94ae..a867c881 100755 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -1103,12 +1103,19 @@ TEST(MessageDifferencerTest, RepeatedFieldSetTest_Combination) { msg1.add_rw("change"); msg2.add_rw("change"); // Compare - util::MessageDifferencer differencer; - differencer.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), - item->GetDescriptor()->FindFieldByName("a")); - differencer.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv")); - differencer.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra")); - EXPECT_TRUE(differencer.Compare(msg1, msg2)); + util::MessageDifferencer differencer1; + differencer1.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), + item->GetDescriptor()->FindFieldByName("a")); + differencer1.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv")); + differencer1.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra")); + EXPECT_TRUE(differencer1.Compare(msg1, msg2)); + + util::MessageDifferencer differencer2; + differencer2.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), + item->GetDescriptor()->FindFieldByName("a")); + differencer2.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); + differencer2.TreatAsList(msg1.GetDescriptor()->FindFieldByName("rw")); + EXPECT_TRUE(differencer2.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldMapTest_Partial) { @@ -1168,6 +1175,11 @@ TEST(MessageDifferencerTest, RepeatedFieldSetTest_Duplicates) { differencer.TreatAsSet(GetFieldDescriptor(a, "rv")); EXPECT_TRUE(differencer.Compare(b, a)); EXPECT_FALSE(differencer.Compare(c, a)); + + util::MessageDifferencer differencer1; + differencer1.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); + EXPECT_TRUE(differencer1.Compare(b, a)); + EXPECT_FALSE(differencer1.Compare(c, a)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_PartialSimple) { @@ -1442,11 +1454,10 @@ static const char* const kIgnoredFields[] = {"rm.b", "rm.m.b"}; class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria { public: - bool IsIgnored( + virtual bool IsIgnored( const Message& message1, const Message& message2, const FieldDescriptor* field, - const vector<util::MessageDifferencer::SpecificField>& parent_fields) - override { + const vector<util::MessageDifferencer::SpecificField>& parent_fields) { string name = ""; for (int i = 0; i < parent_fields.size(); ++i) { name += parent_fields[i].field->name() + "."; @@ -1488,8 +1499,10 @@ TEST(MessageDifferencerTest, TreatRepeatedFieldAsMapWithIgnoredKeyFields) { class ValueProductMapKeyComparator : public util::MessageDifferencer::MapKeyComparator { public: - virtual bool IsMatch(const Message &message1, - const Message &message2) const { + typedef util::MessageDifferencer::SpecificField SpecificField; + virtual bool IsMatch( + const Message &message1, const Message &message2, + const vector<SpecificField>& parent_fields) const { const Reflection* reflection1 = message1.GetReflection(); const Reflection* reflection2 = message2.GetReflection(); // FieldDescriptor for item.ra @@ -2803,15 +2816,20 @@ class MatchingTest : public testing::Test { const Message& msg1, const Message& msg2, bool result) { string output; - io::StringOutputStream output_stream(&output); - MessageDifferencer::StreamReporter reporter(&output_stream); - reporter.set_report_modified_aggregates(true); - differencer->set_report_matches(true); - differencer->ReportDifferencesTo(&reporter); - if (result) { - EXPECT_TRUE(differencer->Compare(msg1, msg2)); - } else { - EXPECT_FALSE(differencer->Compare(msg1, msg2)); + { + // Before we return the "output" string, we must make sure the + // StreamReporter is destructored because its destructor will + // flush the stream. + io::StringOutputStream output_stream(&output); + MessageDifferencer::StreamReporter reporter(&output_stream); + reporter.set_report_modified_aggregates(true); + differencer->set_report_matches(true); + differencer->ReportDifferencesTo(&reporter); + if (result) { + EXPECT_TRUE(differencer->Compare(msg1, msg2)); + } else { + EXPECT_FALSE(differencer->Compare(msg1, msg2)); + } } return output; } diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index a0996954..96393903 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -159,7 +159,10 @@ class DescriptorPoolTypeResolver : public TypeResolver { } field->set_number(descriptor->number()); field->set_name(descriptor->name()); - field->set_json_name(converter::ToCamelCase(descriptor->name())); + field->set_json_name(descriptor->json_name()); + if (descriptor->has_default_value()) { + field->set_default_value(DefaultValueAsString(descriptor)); + } if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { field->set_type_url(GetTypeUrl(descriptor->message_type())); } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { @@ -200,6 +203,46 @@ class DescriptorPoolTypeResolver : public TypeResolver { return url_prefix_ + "/" + descriptor->full_name(); } + string DefaultValueAsString(const FieldDescriptor* descriptor) { + switch (descriptor->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(descriptor->default_value_int32()); + break; + case FieldDescriptor::CPPTYPE_INT64: + return SimpleItoa(descriptor->default_value_int64()); + break; + case FieldDescriptor::CPPTYPE_UINT32: + return SimpleItoa(descriptor->default_value_uint32()); + break; + case FieldDescriptor::CPPTYPE_UINT64: + return SimpleItoa(descriptor->default_value_uint64()); + break; + case FieldDescriptor::CPPTYPE_FLOAT: + return SimpleFtoa(descriptor->default_value_float()); + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + return SimpleDtoa(descriptor->default_value_double()); + break; + case FieldDescriptor::CPPTYPE_BOOL: + return descriptor->default_value_bool() ? "true" : "false"; + break; + case FieldDescriptor::CPPTYPE_STRING: + if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { + return CEscape(descriptor->default_value_string()); + } else { + return descriptor->default_value_string(); + } + break; + case FieldDescriptor::CPPTYPE_ENUM: + return descriptor->default_value_enum()->name(); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(DFATAL) << "Messages can't have default values!"; + break; + } + return ""; + } + string url_prefix_; const DescriptorPool* pool_; }; diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc index 74b2d0da..8a0bf652 100644 --- a/src/google/protobuf/util/type_resolver_util_test.cc +++ b/src/google/protobuf/util/type_resolver_util_test.cc @@ -43,6 +43,7 @@ #include <google/protobuf/map_unittest.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> +#include <google/protobuf/util/json_format_proto3.pb.h> #include <google/protobuf/util/type_resolver.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -332,6 +333,19 @@ TEST_F(DescriptorPoolTypeResolverTest, TestEnum) { EnumHasValue(type, "NEG", -1); } +TEST_F(DescriptorPoolTypeResolverTest, TestJsonName) { + Type type; + ASSERT_TRUE(resolver_->ResolveMessageType( + GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type) + .ok()); + EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name()); + + ASSERT_TRUE(resolver_->ResolveMessageType( + GetTypeUrl<proto3::TestCustomJsonName>(), &type) + .ok()); + EXPECT_EQ("@value", FindField(type, "value")->json_name()); +} + } // namespace } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 847e3500..f2517074 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -49,8 +49,10 @@ namespace google { namespace protobuf { namespace internal { -#ifndef _MSC_VER // MSVC doesn't like definitions of inline constants, GCC - // requires them. + +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +// Old version of MSVC doesn't like definitions of inline constants, GCC +// requires them. const int WireFormatLite::kMessageSetItemStartTag; const int WireFormatLite::kMessageSetItemEndTag; const int WireFormatLite::kMessageSetTypeIdTag; @@ -410,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); } @@ -419,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); } @@ -434,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 991c3d04..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. @@ -412,12 +412,12 @@ inline bool WireFormatLite::ReadPackedPrimitive< \ CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values); \ } -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32); -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64); -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32); -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64); -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT); -READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE); +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32) +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64) +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32) +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64) +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT) +READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE) #undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE @@ -835,12 +835,14 @@ inline int WireFormatLite::EnumSize(int value) { } inline int WireFormatLite::StringSize(const string& value) { - return io::CodedOutputStream::VarintSize32(value.size()) + - value.size(); + return static_cast<int>( + io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) + + value.size()); } inline int WireFormatLite::BytesSize(const string& value) { - return io::CodedOutputStream::VarintSize32(value.size()) + - value.size(); + return static_cast<int>( + io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) + + value.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 b2a7e970..60801423 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -2,11 +2,12 @@ // source: google/protobuf/wrappers.proto #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "google/protobuf/wrappers.pb.h" +#include <google/protobuf/wrappers.pb.h> #include <algorithm> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -262,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(\014BP\n\023com" - ".google.protobufB\rWrappersProtoP\001\240\001\001\242\002\003G" - "PB\252\002\036Google.Protobuf.WellKnownTypesb\006pro" - "to3", 403); + " \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(); @@ -308,9 +310,9 @@ static void MergeFromFail(int line) { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int DoubleValue::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 DoubleValue::DoubleValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -318,6 +320,14 @@ DoubleValue::DoubleValue() // @@protoc_insertion_point(constructor:google.protobuf.DoubleValue) } +DoubleValue::DoubleValue(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue) +} + void DoubleValue::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -342,10 +352,20 @@ DoubleValue::~DoubleValue() { } void DoubleValue::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void DoubleValue::ArenaDtor(void* object) { + DoubleValue* _this = reinterpret_cast< DoubleValue* >(object); + (void)_this; +} +void DoubleValue::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void DoubleValue::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -364,20 +384,17 @@ const DoubleValue& DoubleValue::default_instance() { DoubleValue* DoubleValue::default_instance_ = NULL; DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const { - DoubleValue* n = new DoubleValue; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<DoubleValue>(arena); } 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 (;;) { @@ -444,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; @@ -458,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()); @@ -477,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); @@ -495,6 +519,18 @@ bool DoubleValue::IsInitialized() const { void DoubleValue::Swap(DoubleValue* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + DoubleValue temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void DoubleValue::UnsafeArenaSwap(DoubleValue* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void DoubleValue::InternalSwap(DoubleValue* other) { @@ -532,9 +568,9 @@ void DoubleValue::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int FloatValue::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 FloatValue::FloatValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -542,6 +578,14 @@ FloatValue::FloatValue() // @@protoc_insertion_point(constructor:google.protobuf.FloatValue) } +FloatValue::FloatValue(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue) +} + void FloatValue::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -566,10 +610,20 @@ FloatValue::~FloatValue() { } void FloatValue::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void FloatValue::ArenaDtor(void* object) { + FloatValue* _this = reinterpret_cast< FloatValue* >(object); + (void)_this; +} +void FloatValue::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FloatValue::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -588,20 +642,17 @@ const FloatValue& FloatValue::default_instance() { FloatValue* FloatValue::default_instance_ = NULL; FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const { - FloatValue* n = new FloatValue; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<FloatValue>(arena); } 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 (;;) { @@ -668,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; @@ -682,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()); @@ -701,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); @@ -719,6 +777,18 @@ bool FloatValue::IsInitialized() const { void FloatValue::Swap(FloatValue* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + FloatValue temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void FloatValue::UnsafeArenaSwap(FloatValue* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void FloatValue::InternalSwap(FloatValue* other) { @@ -756,9 +826,9 @@ void FloatValue::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Int64Value::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Int64Value::Int64Value() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -766,6 +836,14 @@ Int64Value::Int64Value() // @@protoc_insertion_point(constructor:google.protobuf.Int64Value) } +Int64Value::Int64Value(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value) +} + void Int64Value::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -790,10 +868,20 @@ Int64Value::~Int64Value() { } void Int64Value::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void Int64Value::ArenaDtor(void* object) { + Int64Value* _this = reinterpret_cast< Int64Value* >(object); + (void)_this; +} +void Int64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void Int64Value::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -812,20 +900,17 @@ const Int64Value& Int64Value::default_instance() { Int64Value* Int64Value::default_instance_ = NULL; Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const { - Int64Value* n = new Int64Value; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<Int64Value>(arena); } 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 (;;) { @@ -892,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; @@ -908,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()); @@ -927,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); @@ -945,6 +1037,18 @@ bool Int64Value::IsInitialized() const { void Int64Value::Swap(Int64Value* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + Int64Value temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void Int64Value::UnsafeArenaSwap(Int64Value* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void Int64Value::InternalSwap(Int64Value* other) { @@ -982,9 +1086,9 @@ void Int64Value::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int UInt64Value::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 UInt64Value::UInt64Value() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -992,6 +1096,14 @@ UInt64Value::UInt64Value() // @@protoc_insertion_point(constructor:google.protobuf.UInt64Value) } +UInt64Value::UInt64Value(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value) +} + void UInt64Value::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -1016,10 +1128,20 @@ UInt64Value::~UInt64Value() { } void UInt64Value::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void UInt64Value::ArenaDtor(void* object) { + UInt64Value* _this = reinterpret_cast< UInt64Value* >(object); + (void)_this; +} +void UInt64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void UInt64Value::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1038,20 +1160,17 @@ const UInt64Value& UInt64Value::default_instance() { UInt64Value* UInt64Value::default_instance_ = NULL; UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const { - UInt64Value* n = new UInt64Value; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<UInt64Value>(arena); } 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 (;;) { @@ -1118,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; @@ -1134,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()); @@ -1153,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); @@ -1171,6 +1297,18 @@ bool UInt64Value::IsInitialized() const { void UInt64Value::Swap(UInt64Value* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + UInt64Value temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void UInt64Value::UnsafeArenaSwap(UInt64Value* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void UInt64Value::InternalSwap(UInt64Value* other) { @@ -1208,9 +1346,9 @@ void UInt64Value::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Int32Value::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 Int32Value::Int32Value() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1218,6 +1356,14 @@ Int32Value::Int32Value() // @@protoc_insertion_point(constructor:google.protobuf.Int32Value) } +Int32Value::Int32Value(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value) +} + void Int32Value::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -1242,10 +1388,20 @@ Int32Value::~Int32Value() { } void Int32Value::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void Int32Value::ArenaDtor(void* object) { + Int32Value* _this = reinterpret_cast< Int32Value* >(object); + (void)_this; +} +void Int32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void Int32Value::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1264,20 +1420,17 @@ const Int32Value& Int32Value::default_instance() { Int32Value* Int32Value::default_instance_ = NULL; Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const { - Int32Value* n = new Int32Value; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<Int32Value>(arena); } 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 (;;) { @@ -1344,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; @@ -1360,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()); @@ -1379,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); @@ -1397,6 +1557,18 @@ bool Int32Value::IsInitialized() const { void Int32Value::Swap(Int32Value* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + Int32Value temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void Int32Value::UnsafeArenaSwap(Int32Value* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void Int32Value::InternalSwap(Int32Value* other) { @@ -1434,9 +1606,9 @@ void Int32Value::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int UInt32Value::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 UInt32Value::UInt32Value() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1444,6 +1616,14 @@ UInt32Value::UInt32Value() // @@protoc_insertion_point(constructor:google.protobuf.UInt32Value) } +UInt32Value::UInt32Value(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value) +} + void UInt32Value::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -1468,10 +1648,20 @@ UInt32Value::~UInt32Value() { } void UInt32Value::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void UInt32Value::ArenaDtor(void* object) { + UInt32Value* _this = reinterpret_cast< UInt32Value* >(object); + (void)_this; +} +void UInt32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void UInt32Value::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1490,20 +1680,17 @@ const UInt32Value& UInt32Value::default_instance() { UInt32Value* UInt32Value::default_instance_ = NULL; UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const { - UInt32Value* n = new UInt32Value; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<UInt32Value>(arena); } 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 (;;) { @@ -1570,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; @@ -1586,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()); @@ -1605,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); @@ -1623,6 +1817,18 @@ bool UInt32Value::IsInitialized() const { void UInt32Value::Swap(UInt32Value* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + UInt32Value temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void UInt32Value::UnsafeArenaSwap(UInt32Value* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void UInt32Value::InternalSwap(UInt32Value* other) { @@ -1660,9 +1866,9 @@ void UInt32Value::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int BoolValue::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 BoolValue::BoolValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1670,6 +1876,14 @@ BoolValue::BoolValue() // @@protoc_insertion_point(constructor:google.protobuf.BoolValue) } +BoolValue::BoolValue(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue) +} + void BoolValue::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -1694,10 +1908,20 @@ BoolValue::~BoolValue() { } void BoolValue::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void BoolValue::ArenaDtor(void* object) { + BoolValue* _this = reinterpret_cast< BoolValue* >(object); + (void)_this; +} +void BoolValue::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void BoolValue::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1716,20 +1940,17 @@ const BoolValue& BoolValue::default_instance() { BoolValue* BoolValue::default_instance_ = NULL; BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const { - BoolValue* n = new BoolValue; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<BoolValue>(arena); } 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 (;;) { @@ -1796,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; @@ -1810,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()); @@ -1829,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); @@ -1847,6 +2075,18 @@ bool BoolValue::IsInitialized() const { void BoolValue::Swap(BoolValue* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + BoolValue temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void BoolValue::UnsafeArenaSwap(BoolValue* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void BoolValue::InternalSwap(BoolValue* other) { @@ -1884,9 +2124,9 @@ void BoolValue::clear_value() { // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int StringValue::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 StringValue::StringValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -1894,6 +2134,14 @@ StringValue::StringValue() // @@protoc_insertion_point(constructor:google.protobuf.StringValue) } +StringValue::StringValue(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue) +} + void StringValue::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -1919,11 +2167,21 @@ StringValue::~StringValue() { } void StringValue::SharedDtor() { - value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (GetArenaNoVirtual() != NULL) { + return; + } + + value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void StringValue::ArenaDtor(void* object) { + StringValue* _this = reinterpret_cast< StringValue* >(object); + (void)_this; +} +void StringValue::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void StringValue::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1942,20 +2200,17 @@ const StringValue& StringValue::default_instance() { StringValue* StringValue::default_instance_ = NULL; StringValue* StringValue::New(::google::protobuf::Arena* arena) const { - StringValue* n = new StringValue; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<StringValue>(arena); } void StringValue::Clear() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +// @@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 (;;) { @@ -2035,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; @@ -2051,32 +2307,37 @@ 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) { - - value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_); + set_value(from.value()); } } 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); @@ -2089,6 +2350,18 @@ bool StringValue::IsInitialized() const { void StringValue::Swap(StringValue* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + StringValue temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void StringValue::UnsafeArenaSwap(StringValue* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void StringValue::InternalSwap(StringValue* other) { @@ -2110,36 +2383,46 @@ void StringValue::InternalSwap(StringValue* other) { // optional string value = 1; void StringValue::clear_value() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } const ::std::string& StringValue::value() const { // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value) - return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } void StringValue::set_value(const ::std::string& value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value) } void StringValue::set_value(const char* value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value) } - void StringValue::set_value(const char* value, size_t size) { + void StringValue::set_value(const char* value, + size_t size) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value) } ::std::string* StringValue::mutable_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value) - return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + 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_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } void StringValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -2147,17 +2430,30 @@ void StringValue::clear_value() { } else { } - value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) } + void StringValue::unsafe_arena_set_allocated_value( + ::std::string* value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (value != NULL) { + + } else { + + } + value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + value, GetArenaNoVirtual()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== -#ifndef _MSC_VER +#if !defined(_MSC_VER) || _MSC_VER >= 1900 const int BytesValue::kValueFieldNumber; -#endif // !_MSC_VER +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 BytesValue::BytesValue() : ::google::protobuf::Message(), _internal_metadata_(NULL) { @@ -2165,6 +2461,14 @@ BytesValue::BytesValue() // @@protoc_insertion_point(constructor:google.protobuf.BytesValue) } +BytesValue::BytesValue(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue) +} + void BytesValue::InitAsDefaultInstance() { _is_default_instance_ = true; } @@ -2190,11 +2494,21 @@ BytesValue::~BytesValue() { } void BytesValue::SharedDtor() { - value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (GetArenaNoVirtual() != NULL) { + return; + } + + value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void BytesValue::ArenaDtor(void* object) { + BytesValue* _this = reinterpret_cast< BytesValue* >(object); + (void)_this; +} +void BytesValue::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void BytesValue::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -2213,20 +2527,17 @@ const BytesValue& BytesValue::default_instance() { BytesValue* BytesValue::default_instance_ = NULL; BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const { - BytesValue* n = new BytesValue; - if (arena != NULL) { - arena->Own(n); - } - return n; + return ::google::protobuf::Arena::CreateMessage<BytesValue>(arena); } void BytesValue::Clear() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +// @@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 (;;) { @@ -2294,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; @@ -2310,32 +2622,37 @@ 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) { - - value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_); + set_value(from.value()); } } 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); @@ -2348,6 +2665,18 @@ bool BytesValue::IsInitialized() const { void BytesValue::Swap(BytesValue* other) { if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + BytesValue temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void BytesValue::UnsafeArenaSwap(BytesValue* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); InternalSwap(other); } void BytesValue::InternalSwap(BytesValue* other) { @@ -2369,36 +2698,46 @@ void BytesValue::InternalSwap(BytesValue* other) { // optional bytes value = 1; void BytesValue::clear_value() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } const ::std::string& BytesValue::value() const { // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value) - return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } void BytesValue::set_value(const ::std::string& value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value) } void BytesValue::set_value(const char* value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value) } - void BytesValue::set_value(const void* value, size_t size) { + void BytesValue::set_value(const void* value, + size_t size) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value) } ::std::string* BytesValue::mutable_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value) - return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* BytesValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value) - return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + 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(), + GetArenaNoVirtual()); } void BytesValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -2406,9 +2745,22 @@ void BytesValue::clear_value() { } else { } - value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) } + void BytesValue::unsafe_arena_set_allocated_value( + ::std::string* value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (value != NULL) { + + } else { + + } + value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + value, GetArenaNoVirtual()); + // @@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 15bcc7a2..10784778 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -61,9 +61,14 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const DoubleValue& default_instance(); + void UnsafeArenaSwap(DoubleValue* other); void Swap(DoubleValue* other); // implements Message ---------------------------------------------- @@ -90,6 +95,11 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(DoubleValue* other); + protected: + explicit DoubleValue(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -115,6 +125,9 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; double value_; mutable int _cached_size_; @@ -139,9 +152,14 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const FloatValue& default_instance(); + void UnsafeArenaSwap(FloatValue* other); void Swap(FloatValue* other); // implements Message ---------------------------------------------- @@ -168,6 +186,11 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(FloatValue* other); + protected: + explicit FloatValue(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -193,6 +216,9 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; float value_; mutable int _cached_size_; @@ -217,9 +243,14 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const Int64Value& default_instance(); + void UnsafeArenaSwap(Int64Value* other); void Swap(Int64Value* other); // implements Message ---------------------------------------------- @@ -246,6 +277,11 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(Int64Value* other); + protected: + explicit Int64Value(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -271,6 +307,9 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::int64 value_; mutable int _cached_size_; @@ -295,9 +334,14 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const UInt64Value& default_instance(); + void UnsafeArenaSwap(UInt64Value* other); void Swap(UInt64Value* other); // implements Message ---------------------------------------------- @@ -324,6 +368,11 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(UInt64Value* other); + protected: + explicit UInt64Value(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -349,6 +398,9 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::uint64 value_; mutable int _cached_size_; @@ -373,9 +425,14 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const Int32Value& default_instance(); + void UnsafeArenaSwap(Int32Value* other); void Swap(Int32Value* other); // implements Message ---------------------------------------------- @@ -402,6 +459,11 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(Int32Value* other); + protected: + explicit Int32Value(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -427,6 +489,9 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::int32 value_; mutable int _cached_size_; @@ -451,9 +516,14 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const UInt32Value& default_instance(); + void UnsafeArenaSwap(UInt32Value* other); void Swap(UInt32Value* other); // implements Message ---------------------------------------------- @@ -480,6 +550,11 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(UInt32Value* other); + protected: + explicit UInt32Value(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -505,6 +580,9 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::uint32 value_; mutable int _cached_size_; @@ -529,9 +607,14 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const BoolValue& default_instance(); + void UnsafeArenaSwap(BoolValue* other); void Swap(BoolValue* other); // implements Message ---------------------------------------------- @@ -558,6 +641,11 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(BoolValue* other); + protected: + explicit BoolValue(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -583,6 +671,9 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message { private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; bool value_; mutable int _cached_size_; @@ -607,9 +698,14 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const StringValue& default_instance(); + void UnsafeArenaSwap(StringValue* other); void Swap(StringValue* other); // implements Message ---------------------------------------------- @@ -636,6 +732,11 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(StringValue* other); + protected: + explicit StringValue(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -661,11 +762,17 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message { ::std::string* mutable_value(); ::std::string* release_value(); void set_allocated_value(::std::string* value); + ::std::string* unsafe_arena_release_value(); + void unsafe_arena_set_allocated_value( + ::std::string* value); // @@protoc_insertion_point(class_scope:google.protobuf.StringValue) private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::internal::ArenaStringPtr value_; mutable int _cached_size_; @@ -690,9 +797,14 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message { return *this; } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const BytesValue& default_instance(); + void UnsafeArenaSwap(BytesValue* other); void Swap(BytesValue* other); // implements Message ---------------------------------------------- @@ -719,6 +831,11 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message { void SharedDtor(); void SetCachedSize(int size) const; void InternalSwap(BytesValue* other); + protected: + explicit BytesValue(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); private: inline ::google::protobuf::Arena* GetArenaNoVirtual() const { return _internal_metadata_.arena(); @@ -744,11 +861,17 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message { ::std::string* mutable_value(); ::std::string* release_value(); void set_allocated_value(::std::string* value); + ::std::string* unsafe_arena_release_value(); + void unsafe_arena_set_allocated_value( + ::std::string* value); // @@protoc_insertion_point(class_scope:google.protobuf.BytesValue) private: ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; bool _is_default_instance_; ::google::protobuf::internal::ArenaStringPtr value_; mutable int _cached_size_; @@ -895,36 +1018,46 @@ inline void BoolValue::set_value(bool value) { // optional string value = 1; inline void StringValue::clear_value() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline const ::std::string& StringValue::value() const { // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value) - return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void StringValue::set_value(const ::std::string& value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value) } inline void StringValue::set_value(const char* value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value) } -inline void StringValue::set_value(const char* value, size_t size) { +inline void StringValue::set_value(const char* value, + size_t size) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value) } inline ::std::string* StringValue::mutable_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value) - return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + 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_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void StringValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -932,9 +1065,22 @@ inline void StringValue::set_allocated_value(::std::string* value) { } else { } - value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) } +inline void StringValue::unsafe_arena_set_allocated_value( + ::std::string* value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (value != NULL) { + + } else { + + } + value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + value, GetArenaNoVirtual()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) +} // ------------------------------------------------------------------- @@ -942,36 +1088,46 @@ inline void StringValue::set_allocated_value(::std::string* value) { // optional bytes value = 1; inline void BytesValue::clear_value() { - value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline const ::std::string& BytesValue::value() const { // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value) - return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void BytesValue::set_value(const ::std::string& value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value) } inline void BytesValue::set_value(const char* value) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value) } -inline void BytesValue::set_value(const void* value, size_t size) { +inline void BytesValue::set_value(const void* value, + size_t size) { - value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); + value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value) } inline ::std::string* BytesValue::mutable_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value) - return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + 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_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + 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(), + GetArenaNoVirtual()); } inline void BytesValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -979,9 +1135,22 @@ inline void BytesValue::set_allocated_value(::std::string* value) { } else { } - value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) } +inline void BytesValue::unsafe_arena_set_allocated_value( + ::std::string* value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (value != NULL) { + + } else { + + } + value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + value, GetArenaNoVirtual()); + // @@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 a1d6e446..4828ad9a 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -37,11 +37,13 @@ syntax = "proto3"; package google.protobuf; -option java_generate_equals_and_hash = true; -option java_multiple_files = true; -option java_outer_classname = "WrappersProto"; -option java_package = "com.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; +option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; // Wrapper message for `double`. |