diff options
Diffstat (limited to 'src')
200 files changed, 10426 insertions, 3536 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 2985b5d8..2ba0ef9b 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 @@ -513,6 +518,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 = \ @@ -624,7 +630,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) @@ -722,6 +730,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 +746,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..4e312c0c --- /dev/null +++ b/src/README.md @@ -0,0 +1,209 @@ +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) + +On Ubuntu, you can install them with: + + $ sudo apt-get install autoconf automake libtool curl + +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. + +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..f3ca06bf 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -65,9 +65,16 @@ 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()); + const string full_name = descriptor->full_name(); + if (type_url.length() < full_name.length()) { + return false; + } + return (0 == type_url.compare( + type_url.length() - full_name.length(), + full_name.length(), + full_name)); } bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index f760ad5d..c8dbef13 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -75,7 +75,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..0bf523b3 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> @@ -119,10 +120,10 @@ 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_) { diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index c324c4af..97982ecf 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 { diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index 423699be..e8a18bc3 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -27,21 +27,22 @@ // 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 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. // +// // JSON // ==== // The JSON representation of an `Any` value uses the regular @@ -62,8 +63,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", @@ -80,7 +81,7 @@ 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] + // * 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 diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index 0a2c4ec0..e589a89d 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) { @@ -904,7 +905,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 +913,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) { @@ -1608,10 +1609,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) { diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 3c5a6f31..e1dca4e4 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 { 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.h b/src/google/protobuf/arena.h index 16e0d50e..5ad94fa9 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -76,7 +76,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); } @@ -490,27 +490,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 +573,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 +777,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 +909,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/arenastring.h b/src/google/protobuf/arenastring.h index 1dacdc68..e2e2f254 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,7 @@ 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 +163,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 +175,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 +215,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/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 26a4f0b0..3a816b05 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> @@ -48,6 +49,10 @@ #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 +276,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 +313,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_; }; @@ -1353,7 +1376,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 +1466,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 +1546,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 +1679,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 +1691,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 +1726,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 +1738,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..f196ffc5 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -262,8 +262,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..dda007d4 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -63,13 +63,13 @@ #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> +namespace google { +namespace protobuf { +namespace compiler { // Disable the whole test when we use tcmalloc for "draconian" heap checks, in // which case tcmalloc will print warnings that fail the plugin tests. #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN -namespace google { -namespace protobuf { -namespace compiler { #if defined(_WIN32) #ifndef STDIN_FILENO @@ -294,6 +294,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 +315,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 @@ -884,6 +886,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 +923,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) { @@ -1411,6 +1421,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 +1822,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..47729e1c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -107,7 +107,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..5ee6f000 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -178,12 +178,13 @@ 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)); printer->Print(vars, - "static const $nested_name$ $tag$ = $classname$_$tag$;\n"); + "static $constexpr$const $nested_name$ $tag$ = $classname$_$tag$;\n"); } printer->Print(vars, @@ -237,6 +238,7 @@ 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())) { printer->Print(vars, @@ -278,16 +280,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 +299,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_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_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 8e8bd8b7..37e4bae4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -237,6 +237,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { } void FileGenerator::GenerateSource(io::Printer* printer) { + bool well_known = IsWellKnownMessage(file_); string header = StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( @@ -246,16 +247,19 @@ 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", well_known ? "<" : "\"", + "right", well_known ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { @@ -846,7 +850,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (IsAnyMessage(file_)) { printer->Print( - "#include \"google/protobuf/any.h\"\n"); + "#include <google/protobuf/any.h>\n"); } } @@ -857,14 +861,16 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { } for (int i = 0; i < file_->dependency_count(); i++) { + bool well_known = 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", well_known ? "<" : "\"", + "right", well_known ? ">" : "\""); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 09845458..fb46e387 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); @@ -600,6 +601,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. diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 985cb04c..a22d414d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -265,6 +265,8 @@ inline bool SupportsArenas(const FieldDescriptor* field) { bool IsAnyMessage(const FileDescriptor* descriptor); bool IsAnyMessage(const Descriptor* descriptor); +bool IsWellKnownMessage(const FileDescriptor* descriptor); + void GenerateUtf8CheckCodeForString( const FieldDescriptor* field, bool for_parse, diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 8cc8c7ba..8304ebbd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -1772,6 +1772,17 @@ GenerateShutdownCode(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + // mutable_unknown_fields wrapper function for LazyStringOutputStream + // callback. + if (!UseUnknownFieldSet(descriptor_->file())) { + 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" @@ -1807,7 +1818,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 +1827,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. @@ -2814,7 +2825,9 @@ GenerateMergeFrom(io::Printer* printer) { "}\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"); } } @@ -2889,11 +2902,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "classname", classname_); if (!UseUnknownFieldSet(descriptor_->file())) { + // 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::StringOutputStream unknown_fields_string(\n" - " mutable_unknown_fields());\n" + " ::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( @@ -3364,7 +3382,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"); } } } diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index e5db844c..422eb73b 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -28,30 +28,31 @@ // (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 <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/googletest.h> #include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> namespace google { namespace protobuf { -namespace util { -namespace converter { - -class Snake2CamelObjectWriterTest : public ::testing::Test { - protected: - Snake2CamelObjectWriterTest() : mock_(), expects_(&mock_), testing_(&mock_) {} - virtual ~Snake2CamelObjectWriterTest() {} - - MockObjectWriter mock_; - ExpectingObjectWriter expects_; - Snake2CamelObjectWriter testing_; -}; - -// 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. +namespace compiler { +namespace cpp { +namespace { -} // namespace converter -} // namespace util +} // namespace +} // namespace cpp +} // namespace compiler } // namespace protobuf } // namespace google 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..9616f172 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -49,8 +49,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) { } 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..3b88954c 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; 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..df9730f8 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,14 @@ 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 { *error = "Unknown generator option: " + options[i].first; return false; @@ -122,8 +88,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 +102,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_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index 333b4912..41265f9a 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? @@ -218,16 +195,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 +242,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 +353,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..eaf85014 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -46,6 +46,7 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; class FieldGeneratorBase; // TODO: start using this enum. @@ -69,14 +70,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 +83,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); @@ -101,17 +98,19 @@ 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/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/csharp/csharp_options.h index cb6ca1b1..9e5573ca 100644 --- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -28,16 +28,48 @@ // (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"; +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ -package protobuf_unittest; +#include <string> -message TestLargeEnumValue { - enum EnumWithLargeValue { - VALUE_1 = 1; - VALUE_MAX = 0x7fffffff; +#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) { } -} + // 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; +}; + +} // 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..bd459dda 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() { @@ -60,6 +63,10 @@ std::string SourceGeneratorBase::class_access_level() { return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on. } +const Options* SourceGeneratorBase::options() { + return this->options_; +} + } // namespace csharp } // namespace compiler } // namespace protobuf 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..be19aa2e 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -71,6 +71,7 @@ class MockErrorCollector : public MultiFileErrorCollector { ~MockErrorCollector() {} string text_; + string warning_text_; // implements ErrorCollector --------------------------------------- void AddError(const string& filename, int line, int column, @@ -78,6 +79,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 +130,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_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index c06988c8..26cd76c9 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -85,17 +85,10 @@ 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(); for (int i = 0; i < canonical_values_.size(); i++) { @@ -315,7 +308,6 @@ 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"); } 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..44e379fb 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -596,9 +596,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 +621,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,7 +633,7 @@ 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"); } @@ -649,7 +647,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList($name$_);\n" + " $name$_ = newIntList($name$_);\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -660,7 +658,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 +667,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 +675,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 +690,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 +704,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,7 +803,7 @@ 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:: @@ -840,9 +838,9 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "int rawValue = input.readEnum();\n" "if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ = newIntList();\n" "}\n" - "$name$_.add(rawValue);\n"); + "$name$_.addInt(rawValue);\n"); } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" @@ -855,9 +853,9 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "} else {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ = newIntList();\n" " }\n" - " $name$_.add(rawValue);\n" + " $name$_.addInt(rawValue);\n" "}\n"); } } @@ -897,12 +895,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 +915,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_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index 4d7cd3f0..141217d7 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,15 +137,7 @@ 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" @@ -197,7 +181,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_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/google/protobuf/compiler/java/java_extension_lite.cc diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/google/protobuf/compiler/java/java_extension_lite.h diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 68b47ee1..c8172330 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> @@ -281,8 +282,13 @@ 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_)) { + 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); @@ -543,13 +549,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_)) { + 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_) { diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index a26030dd..8b8f8347 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -668,34 +668,34 @@ 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.parseWithIOException(PARSER, input);" "}\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.parseWithIOException(PARSER, input, extensionRegistry);" "}\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.parseDelimitedWithIOException(PARSER, input);" "}\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.parseDelimitedWithIOException(PARSER, input, extensionRegistry);" "}\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.parseWithIOException(PARSER, input);" "}\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.parseWithIOException(PARSER, input, extensionRegistry);" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -1221,9 +1221,8 @@ GenerateParsingConstructor(io::Printer* printer) { "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" " throw new RuntimeException(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 RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n" + " .setUnfinishedMessage(this));\n" "} finally {\n"); printer->Indent(); @@ -1360,7 +1359,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_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc index 1b86d2a9..e747b041 100644 --- a/src/google/protobuf/compiler/java/java_message_builder.cc +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -538,7 +538,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_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 392333b8..5a7bf82d 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -87,11 +87,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["field_list_type"] = "com.google.protobuf.Internal." + capitalized_type + "List"; (*variables)["new_list"] = "new" + capitalized_type + "List"; + (*variables)["new_list_with_capacity"] = + "new" + capitalized_type + "ListWithCapacity"; (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; - (*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"] = @@ -102,11 +104,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, "com.google.protobuf.Internal.ProtobufList<" + (*variables)["boxed_type"] + ">"; (*variables)["new_list"] = "newProtobufList"; + (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity"; (*variables)["empty_list"] = "emptyProtobufList()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; - (*variables)["repeated_index_get"] = - (*variables)["name"] + "_.get(index)"; + (*variables)["repeated_get"] = (*variables)["name"] + "_.get"; (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; } @@ -629,7 +631,7 @@ 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() && @@ -773,6 +775,9 @@ 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" @@ -785,8 +790,21 @@ 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$_ = $new_list$();\n"); + } else { + printer->Print(variables_, + " $name$_ = $new_list_with_capacity$(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 +832,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 +853,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_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 72ebaeca..7f757e47 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -405,7 +405,7 @@ void ImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "String s = input.readStringRequireUtf8();\n" + "java.lang.String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); } else if (!HasDescriptorMethods(descriptor_->file())) { @@ -414,7 +414,7 @@ GenerateParsingCode(io::Printer* printer) const { // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, - "String s = input.readString();\n" + "java.lang.String s = input.readString();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); } else { @@ -665,7 +665,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "String s = input.readStringRequireUtf8();\n" + "java.lang.String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); } else if (!HasDescriptorMethods(descriptor_->file())) { @@ -674,7 +674,7 @@ GenerateParsingCode(io::Printer* printer) const { // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, - "String s = input.readString();\n" + "java.lang.String s = input.readString();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); } else { @@ -773,12 +773,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 +933,14 @@ void RepeatedImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, - "String s = input.readStringRequireUtf8();\n"); + "java.lang.String s = input.readStringRequireUtf8();\n"); } else if (!HasDescriptorMethods(descriptor_->file())) { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, - "String s = input.readString();\n"); + "java.lang.String s = input.readString();\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n"); @@ -966,30 +960,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 +969,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 +990,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..eb5964bd 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -647,12 +647,6 @@ 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" @@ -835,29 +829,6 @@ GenerateParsingCode(io::Printer* printer) const { } 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"); -} - -void RepeatedImmutableStringFieldLiteGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_mutable$) {\n" @@ -870,21 +841,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 +866,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..4d9b4bd7 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.h +++ b/src/google/protobuf/compiler/java/java_string_field_lite.h @@ -129,7 +129,6 @@ class RepeatedImmutableStringFieldLiteGenerator void GenerateMergingCode(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/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc new file mode 100755 index 00000000..0de7e2c6 --- /dev/null +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -0,0 +1,2799 @@ +// 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 { + +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(robinson): 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) { + const char* suffix = HasSuffixString(filename, ".protodevel") + ? ".protodevel" : ".proto"; + return StripSuffixString(filename, suffix) + "_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; +} + +// Returns the message/response ID, if set. +string GetMessageId(const Descriptor* desc) { + return string(); +} + + +// Used inside Google only -- do not remove. +bool IsResponse(const Descriptor* desc) { return false; } +bool IgnoreField(const FieldDescriptor* field) { return false; } + + +// 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; +} + +// Returns the field name as a capitalized portion of a getter/setter method +// name, e.g. MyField for .getMyField(). +string JSGetterName(const FieldDescriptor* field) { + string name = JSIdent(field, + /* is_upper_camel = */ true, + /* is_map = */ false); + 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. Since JS strings are UTF-16, we only +// need to handle the BMP (16-bit range) here. +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. |is_utf8| determines whether the input data (in a C++ string of +// chars) is UTF-8 encoded (in which case codepoints become JavaScript string +// characters, escaped with 16-bit hex escapes where necessary) or raw binary +// (in which case bytes become JavaScript string characters 0 -- 255). +string EscapeJSString(const string& in, bool is_utf8) { + string result; + size_t decoded = 0; + for (size_t i = 0; i < in.size(); i += decoded) { + uint16 codepoint = 0; + if (is_utf8) { + // Decode the next UTF-8 codepoint. + size_t have_bytes = in.size() - i; + uint8 bytes[3] = { + static_cast<uint8>(in[i]), + static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0), + static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0), + }; + codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); + if (have_bytes == 0) { + break; + } + decoded = have_bytes; + } else { + codepoint = static_cast<uint16>(static_cast<uint8>(in[i])); + decoded = 1; + } + + // Next byte -- used for minimal octal escapes below. + char next_byte = (i + decoded) < in.size() ? + in[i + decoded] : 0; + bool pad_octal = (next_byte >= '0' && next_byte <= '7'); + + switch (codepoint) { + case '\0': result += pad_octal ? "\\000" : "\\0"; break; + case '\b': result += "\\\b"; break; + case '\t': result += "\\\t"; break; + case '\n': result += "\\\n"; break; + case '\r': result += "\\\r"; break; + case '\f': result += "\\\f"; break; + case '\\': result += "\\\\"; break; + case '"': result += pad_octal ? "\\042" : "\\42"; break; + case '&': result += pad_octal ? "\\046" : "\\46"; break; + case '\'': result += pad_octal ? "\\047" : "\\47"; break; + case '<': result += pad_octal ? "\\074" : "\\74"; break; + case '=': result += pad_octal ? "\\075" : "\\75"; break; + case '>': result += pad_octal ? "\\076" : "\\76"; break; + default: + // All other non-ASCII codepoints are escaped. + // Original codegen uses hex for >= 0x100 and octal for others. + if (codepoint >= 0x20 && codepoint <= 0x7e) { + result += static_cast<char>(codepoint); + } else { + if (codepoint >= 0x100) { + result += StringPrintf("\\u%04x", codepoint); + } else { + if (pad_octal || codepoint >= 0100) { + result += "\\"; + result += ('0' + ((codepoint >> 6) & 07)); + result += ('0' + ((codepoint >> 3) & 07)); + result += ('0' + ((codepoint >> 0) & 07)); + } else if (codepoint >= 010) { + result += "\\"; + result += ('0' + ((codepoint >> 3) & 07)); + result += ('0' + ((codepoint >> 0) & 07)); + } else { + result += "\\"; + result += ('0' + ((codepoint >> 0) & 07)); + } + } + } + break; + } + } + return result; +} + +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) { + return "\"" + EscapeJSString(field->default_value_string(), true) + + "\""; + } else { + 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 JSTypeName(const GeneratorOptions& options, + const FieldDescriptor* field) { + 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 "string"; + 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, + bool always_singular) { + bool is_primitive = + (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE); + + string jstype = JSTypeName(options, field); + + if (field->is_repeated() && + !always_singular && + (field->is_packed() || !singular_if_not_packed)) { + 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 (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) { + // Override for `bytes` fields: treat string as raw bytes, not base64. + name = "BytesRawString"; + } + if (field->is_packed()) { + name = "Packed" + name; + } else if (is_writer && field->is_repeated()) { + 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) { + 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"; + } + return comments; +} + +bool ShouldGenerateExtension(const FieldDescriptor* field) { + return + field->is_extension() && + !IgnoreField(field); +} + +bool HasExtensions(const Descriptor* desc) { + if (desc->extension_count() > 0) { + 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 https://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 https://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: + return "\"\""; + + default: + // BYTES and MESSAGE are handled separately. + assert(false); + return ""; + } +} + +} // 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::GenerateRequires(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::GenerateRequires(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& files, + std::set<string>* provided) const { + if (options.import_style == GeneratorOptions::IMPORT_BROWSER) { + return; + } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { + // For Closure imports we need to import every message type individually. + std::set<string> required; + std::set<string> forwards; + bool have_extensions = false; + bool have_message = false; + + 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); + } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { + // CommonJS imports are based on files + } +} + +void Generator::GenerateRequires(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()) { + // Delegate to the generated get<field>() method in order not to duplicate + // the proto3-field-default-value logic here. + printer->Print("msg.get$getter$()", + "getter", JSGetterName(field)); + } else { + if (field->has_default_value()) { + printer->Print("jspb.Message.getField(msg, $index$) != null ? " + "jspb.Message.getField(msg, $index$) : $defaultValue$", + "index", JSFieldIndex(field), + "defaultValue", JSFieldDefault(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 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), + "type", JSFieldTypeAnnotation(options, field, + /* force_optional = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false, + /* always_singular = */ 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, + /* always_singular = */ 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, + /* always_singular = */ 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 { + string typed_annotation; + + // Simple (primitive) field, either singular or repeated. + { + typed_annotation = JSFieldTypeAnnotation(options, field, + /* force_optional = */ false, + /* force_present = */ !HasFieldPresence(field), + /* singular_if_not_packed = */ false, + /* always_singular = */ false), + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * @return {$type$}\n" + " */\n", + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field), + "type", typed_annotation); + } + + printer->Print( + "$class$.prototype.get$name$ = function() {\n", + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field)); + + { + 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 ? " + "jspb.Message.getField(this, $index$) : $defaultValue$", + "index", JSFieldIndex(field), + "defaultValue", JSFieldDefault(field)); + } else { + printer->Print("jspb.Message.getField(this, $index$)", + "index", JSFieldIndex(field)); + } + } + + { + printer->Print( + ");\n" + "};\n" + "\n" + "\n"); + } + + { + printer->Print( + "/** @param {$optionaltype$} value $returndoc$ */\n", + "optionaltype", + JSFieldTypeAnnotation(options, field, + /* force_optional = */ true, + /* force_present = */ !HasFieldPresence(field), + /* singular_if_not_packed = */ false, + /* always_singular = */ false), + "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", "", + "typeclose", "", + "oneofgroup", + (field->containing_oneof() ? (", " + JSOneofArray(options, field)) + : ""), + "returnvalue", JSReturnClause(field), "rptvalueinit", + (field->is_repeated() ? " || []" : "")); + + + 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, + /* always_singular = */ false), + "reader", JSBinaryReaderMethodName(field)); + } + + if (field->is_repeated() && !field->is_packed()) { + // Repeated fields receive a |value| one at at a time; append to array + // returned by get$name$(). + printer->Print( + " msg.get$name$().push(value);\n", + "name", JSGetterName(field)); + } 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)); + + 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), + "name", JSGetterName(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, + /* always_singular = */ 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 std::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() { /* ... */ } + std::set<std::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); + GenerateRequires(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) { + // Collect all types, and print each type to a separate file. Pull out + // free-floating extensions while we make this pass. + map< string, vector<const FieldDescriptor*> > extensions_by_namespace; + + // If we're generating code in file-per-type mode, avoid overwriting files + // by choosing the last descriptor that writes each filename and permitting + // only those to generate code. + + // Current descriptor that will generate each filename, indexed by filename. + map<string, const void*> desc_by_filename; + // Set of descriptors allowed to generate files. + set<const void*> allowed_descs; + + for (int i = 0; i < files.size(); i++) { + // Collect all (descriptor, filename) pairs. + map<const void*, string> descs_in_file; + for (int j = 0; j < files[i]->message_type_count(); j++) { + const Descriptor* desc = files[i]->message_type(j); + string filename = + options.output_dir + "/" + ToFileName(desc->name()) + ".js"; + descs_in_file[desc] = filename; + } + for (int j = 0; j < files[i]->enum_type_count(); j++) { + const EnumDescriptor* desc = files[i]->enum_type(j); + string filename = + options.output_dir + "/" + ToFileName(desc->name()) + ".js"; + descs_in_file[desc] = filename; + } + + // For each (descriptor, filename) pair, update the + // descriptors-by-filename map, and if a previous descriptor was already + // writing the filename, remove it from the allowed-descriptors set. + map<const void*, string>::iterator it; + for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) { + const void* desc = it->first; + const string& filename = it->second; + if (desc_by_filename.find(filename) != desc_by_filename.end()) { + if (options.error_on_name_conflict) { + *error = "Name conflict: file name " + filename + + " would be generated by two descriptors"; + return false; + } + allowed_descs.erase(desc_by_filename[filename]); + } + desc_by_filename[filename] = desc; + allowed_descs.insert(desc); + } + } + + // Generate code. + for (int i = 0; i < files.size(); i++) { + const FileDescriptor* file = files[i]; + for (int j = 0; j < file->message_type_count(); j++) { + const Descriptor* desc = file->message_type(j); + if (allowed_descs.find(desc) == allowed_descs.end()) { + continue; + } + + string filename = options.output_dir + "/" + + ToFileName(desc->name()) + ".js"; + 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); + GenerateRequires(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_descs.find(enumdesc) == allowed_descs.end()) { + continue; + } + + string filename = options.output_dir + "/" + + ToFileName(enumdesc->name()) + ".js"; + + 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; + } + } + // Pull out all free-floating extensions and generate files for those too. + for (int j = 0; j < file->extension_count(); j++) { + const FieldDescriptor* extension = file->extension(j); + extensions_by_namespace[GetPath(options, files[i])] + .push_back(extension); + } + } + + // Generate extensions in separate files. + map< string, vector<const FieldDescriptor*> >::iterator it; + for (it = extensions_by_namespace.begin(); + it != extensions_by_namespace.end(); + ++it) { + string filename = options.output_dir + "/" + + ToFileName(it->first) + ".js"; + + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + + GenerateHeader(options, &printer); + + std::set<string> provided; + FindProvidesForFields(options, &printer, it->second, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequires(options, &printer, it->second, &provided); + + for (int j = 0; j < it->second.size(); j++) { + if (ShouldGenerateExtension(it->second[j])) { + GenerateExtension(options, &printer, it->second[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..db9178d3 --- /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 GenerateRequires(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FileDescriptor*>& file, + std::set<string>* provided) const; + void GenerateRequires(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set<string>* provided) const; + // For extension fields at file scope. + void GenerateRequires(const GeneratorOptions& options, + io::Printer* printer, + const vector<const FieldDescriptor*>& fields, + std::set<string>* provided) const; + void 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..121d917b 100644 --- a/src/google/protobuf/compiler/mock_code_generator.cc +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -147,6 +147,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/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..fda51807 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,50 @@ string DefaultValue(const FieldDescriptor* field) { return NULL; } +bool HasNonZeroDefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return false; + } + + if (!field->has_default_value()) { + // No custom default set in the proto file. + return false; + } + + // 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 +818,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 +936,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 +973,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 +984,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 +1012,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 +1023,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.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 0792d875..a2da8eee 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) { @@ -656,11 +657,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) { @@ -1021,10 +1022,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) { diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index ab79bdae..0a03e979 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 { 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..a30ac305 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 { diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index b40fe95a..78a34617 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; @@ -560,7 +560,7 @@ class FileDescriptorTables { ~FileDescriptorTables(); // Empty table, used with placeholder files. - static const FileDescriptorTables kEmpty; + inline static const FileDescriptorTables& GetEmptyInstance(); // ----------------------------------------------------------------- // Finding items. @@ -665,7 +665,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 +2075,7 @@ class SourceLocationCommentPrinter { } private: + bool have_source_loc_; SourceLocation source_loc_; DebugStringOptions options_; @@ -2951,7 +2977,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 +3562,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; @@ -3996,7 +4023,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile( if (!unused_dependency_.empty()) { - LogUnusedDependency(result); + LogUnusedDependency(proto, result); } if (had_errors_) { @@ -4143,6 +4170,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, } } + void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, const Descriptor* parent, FieldDescriptor* result, @@ -4248,8 +4276,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 +4449,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, AllocateOptions(proto.options(), result); } + AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result)); } @@ -5533,11 +5562,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 +6228,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 +6255,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..7e3a7496 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -1645,7 +1645,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 +1690,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 +1705,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 +1726,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..ff0cfcf8 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 @@ -520,6 +527,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 +616,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 +669,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 +746,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\"\256\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 +758,60 @@ 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" - "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!" - " \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" + " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022+\n\037javana" + "no_use_deprecated_package\030& \001(\010B\002\030\001\022C\n\024u" + "ninterpreted_option\030\347\007 \003(\0132$.google.prot" + "obuf.UninterpretedOption\":\n\014OptimizeMode" + "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTI" + "ME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027me" + "ssage_set_wire_format\030\001 \001(\010:\005false\022.\n\037no" + "_standard_descriptor_accessor\030\002 \001(\010:\005fal" + "se\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_ent" + "ry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132" + "$.google.protobuf.UninterpretedOption*\t\010" + "\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\016" + "2#.google.protobuf.FieldOptions.CType:\006S" + "TRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$." + "google.protobuf.FieldOptions.JSType:\tJS_" + "NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecate" + "d\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024u" + "ninterpreted_option\030\347\007 \003(\0132$.google.prot" + "obuf.UninterpretedOption\"/\n\005CType\022\n\n\006STR" + "ING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JST" + "ype\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_" + "NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013a" + "llow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fa" + "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" + "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200" + "\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 " + "\001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(" + "\0132$.google.protobuf.UninterpretedOption*" + "\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecat" "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" - "tion*\t\010\350\007\020\200\200\200\200\002\"\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); + "tion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepr" + "ecated\030! \001(\010:\005false\022C\n\024uninterpreted_opt" + "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" + "edOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpt" + "ion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unin" + "terpretedOption.NamePart\022\030\n\020identifier_v" + "alue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032" + "\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_val" + "ue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggreg" + "ate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part" + "\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceC" + "odeInfo\022:\n\010location\030\001 \003(\0132(.google.proto" + "buf.SourceCodeInfo.Location\032\206\001\n\010Location" + "\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020" + "leading_comments\030\003 \001(\t\022\031\n\021trailing_comme" + "nts\030\004 \001(\t\022!\n\031leading_detached_comments\030\006" + " \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotation" + "\030\001 \003(\0132-.google.protobuf.GeneratedCodeIn" + "fo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003(" + "\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(" + "\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020D" + "escriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032Go" + "ogle.Protobuf.Reflection", 5184); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -784,6 +836,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 +860,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 +884,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) { @@ -1095,7 +1151,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 +1164,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) { @@ -2349,10 +2405,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) { @@ -2632,10 +2688,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) { @@ -2915,7 +2971,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 +2982,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) { @@ -4056,7 +4112,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 +4134,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 +4150,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 +4169,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) { @@ -5210,9 +5266,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) { @@ -5516,11 +5572,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) { @@ -5989,11 +6045,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) { @@ -6452,11 +6508,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) { @@ -6925,14 +6981,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) { @@ -7691,15 +7747,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; @@ -7716,7 +7772,7 @@ 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) { @@ -8073,7 +8129,7 @@ bool FileOptions::MergePartialFromCodedStream( break; } - // optional bool javanano_use_deprecated_package = 38; + // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; case 38: { if (tag == 304) { parse_javanano_use_deprecated_package: @@ -8231,7 +8287,7 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), output); } - // optional bool javanano_use_deprecated_package = 38; + // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; if (has_javanano_use_deprecated_package()) { ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output); } @@ -8357,7 +8413,7 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), target); } - // optional bool javanano_use_deprecated_package = 38; + // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; if (has_javanano_use_deprecated_package()) { target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target); } @@ -8468,7 +8524,7 @@ int FileOptions::ByteSize() const { this->csharp_namespace()); } - // optional bool javanano_use_deprecated_package = 38; + // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; if (has_javanano_use_deprecated_package()) { total_size += 2 + 1; } @@ -9109,7 +9165,7 @@ void FileOptions::clear_csharp_namespace() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) } -// optional bool javanano_use_deprecated_package = 38; +// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; bool FileOptions::has_javanano_use_deprecated_package() const { return (_has_bits_[0] & 0x00004000u) != 0; } @@ -9167,13 +9223,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) { @@ -9725,14 +9781,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 +9804,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 +9820,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) { @@ -10440,11 +10496,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) { @@ -10863,10 +10919,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) { @@ -11212,10 +11268,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) { @@ -11561,10 +11617,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) { @@ -11910,10 +11966,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) { @@ -12216,7 +12272,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 +12280,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) { @@ -13083,13 +13139,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) { @@ -13568,9 +13624,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) { @@ -14056,6 +14112,812 @@ 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() { +#define ZR_HELPER_(f) reinterpret_cast<char*>(\ + &reinterpret_cast<GeneratedCodeInfo_Annotation*>(16)->f) + +#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 (!(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 { + 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) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const GeneratedCodeInfo_Annotation* source = + ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) { + 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) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) { + 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() { + 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 (!(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 { + 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) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const GeneratedCodeInfo* source = + ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) { + 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) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) { + 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() { + 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..3fe07bf5 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; @@ -2015,12 +2017,12 @@ 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(); + // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; + bool has_javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; + void clear_javanano_use_deprecated_package() PROTOBUF_DEPRECATED; static const int kJavananoUseDeprecatedPackageFieldNumber = 38; - bool javanano_use_deprecated_package() const; - void set_javanano_use_deprecated_package(bool value); + bool javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; + void set_javanano_use_deprecated_package(bool value) PROTOBUF_DEPRECATED; // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int uninterpreted_option_size() const; @@ -3390,6 +3392,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_; +}; // =================================================================== @@ -5970,7 +6194,7 @@ 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; +// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; inline bool FileOptions::has_javanano_use_deprecated_package() const { return (_has_bits_[0] & 0x00004000u) != 0; } @@ -7194,6 +7418,175 @@ 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() { + 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 +7630,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..3e664d59 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -379,7 +379,7 @@ message FileOptions { // Whether the nano proto compiler should generate in the deprecated non-nano // suffixed package. - optional bool javanano_use_deprecated_package = 38; + optional bool javanano_use_deprecated_package = 38 [deprecated = true]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -777,3 +777,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..be8e0b72 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -178,6 +178,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 +3175,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 +5196,6 @@ TEST_F(ValidationErrorTest, AllowEnumAlias) { } TEST_F(ValidationErrorTest, UnusedImportWarning) { - pool_.AddUnusedImportTrackFile("bar.proto"); BuildFile( "name: \"bar.proto\" " @@ -5155,7 +5227,7 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) { // } // pool_.AddUnusedImportTrackFile("forward.proto"); - BuildFile( + BuildFileWithWarnings( "name: \"forward.proto\"" "dependency: \"base.proto\"" "dependency: \"bar.proto\"" @@ -5165,7 +5237,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 { diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index 2e22ccb1..b325944e 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> @@ -111,10 +112,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) { diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 7f172aa6..78bcc74b 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.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_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 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 diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 72a8483f..7b69867a 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> @@ -425,7 +425,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 diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index 50cbd9a8..f2eec782 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,9 @@ 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\005EmptyBP\n\023com.google.protobufB\n" + "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob" + "uf.WellKnownTypesb\006proto3", 145); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/empty.proto", &protobuf_RegisterTypes); Empty::default_instance_ = new Empty(); @@ -108,8 +109,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 +118,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 +149,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,11 +181,7 @@ 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() { @@ -255,6 +270,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..b96daf28 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -27,16 +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_multiple_files = true; -option java_outer_classname = "EmptyProto"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 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..01a6ce56 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) { diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index 8b21c692..908c8a86 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): // // diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 4bcd354f..e3a34d0a 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -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/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/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..3d57707c 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."); } diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index 6526056a..20d50a2c 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -875,6 +875,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..083beca4 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -157,6 +157,7 @@ StringOutputStream::~StringOutputStream() { } bool StringOutputStream::Next(void** data, int* size) { + GOOGLE_CHECK_NE(NULL, target_); int old_size = target_->size(); // Grow the string. @@ -188,14 +189,44 @@ bool StringOutputStream::Next(void** data, int* size) { void StringOutputStream::BackUp(int count) { GOOGLE_CHECK_GE(count, 0); + GOOGLE_CHECK_NE(NULL, target_); GOOGLE_CHECK_LE(count, target_->size()); target_->resize(target_->size() - count); } int64 StringOutputStream::ByteCount() const { + GOOGLE_CHECK_NE(NULL, target_); 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() {} 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..1c397dea 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -148,6 +148,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 +159,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 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/map.h b/src/google/protobuf/map.h index 72a1b1a3..83199380 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -155,7 +155,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_; @@ -188,7 +188,6 @@ class LIBPROTOBUF_EXPORT MapKey { 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; @@ -275,7 +274,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; @@ -497,7 +496,7 @@ class Map { insert(other.begin(), other.end()); } template <class InputIt> - explicit Map(const InputIt& first, const InputIt& last) + Map(const InputIt& first, const InputIt& last) : arena_(NULL), allocator_(arena_), elements_(0, hasher(), key_equal(), allocator_), @@ -546,10 +545,16 @@ 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,21 +589,22 @@ 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; + typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> + InnerMap; + public: // Iterators class const_iterator : 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; public: const_iterator() {} @@ -625,8 +631,7 @@ class Map { }; 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; + typedef typename InnerMap::iterator InnerIt; public: iterator() {} @@ -742,8 +747,7 @@ class Map { // Erase size_type erase(const key_type& key) { - typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>, - Allocator>::iterator it = elements_.find(key); + typename InnerMap::iterator it = elements_.find(key); if (it == elements_.end()) { return 0; } else { @@ -813,7 +817,7 @@ class Map { Arena* arena_; Allocator allocator_; - hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_; + InnerMap elements_; int default_enum_value_; friend class ::google::protobuf::Arena; @@ -852,7 +856,6 @@ struct hash<google::protobuf::MapKey> { 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; @@ -877,7 +880,6 @@ struct hash<google::protobuf::MapKey> { 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; 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_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.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/repeated_field.h b/src/google/protobuf/repeated_field.h index 5530fefe..5447fa42 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. @@ -565,7 +574,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> @@ -618,7 +627,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 +674,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 +692,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); } }; @@ -885,10 +894,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. diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index c8397639..f2eb7ae7 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) { 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..e020597a 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> @@ -212,9 +213,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) { @@ -480,14 +481,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) { @@ -1218,9 +1219,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) { diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto index b3e9e699..8562e2c1 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.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_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 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"; 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/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/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_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/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..27d47575 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. 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..b0a5ce63 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> @@ -380,6 +381,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 +391,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 +657,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; } @@ -1357,7 +1358,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 +1427,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 +1780,21 @@ void TextFormat::Printer::PrintFieldValue( ? reflection->GetRepeatedStringReference( message, field, index, &scratch) : reflection->GetStringReference(message, field, &scratch); + int64 size = value.size(); + if (truncate_string_field_longer_than_ > 0) { + size = std::min(truncate_string_field_longer_than_, + static_cast<int64>(value.size())); + } + string truncated_value(value.substr(0, size) + "...<truncated>..."); + const string* value_to_print = &value; + if (size < value.size()) { + 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 +1941,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/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index 2ee0ec29..c1c4402c 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,9 @@ 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(\005BT\n\023com.google.protobufB\016" + "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr" + "otobuf.WellKnownTypesb\006proto3", 189); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/timestamp.proto", &protobuf_RegisterTypes); Timestamp::default_instance_ = new Timestamp(); @@ -111,10 +112,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 +123,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 +156,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,11 +188,7 @@ 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() { @@ -349,6 +364,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..b51fc3fa 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.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 = "TimestampProto"; -option java_package = "com.google.protobuf"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +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 +94,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..7b47b3bd 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) { @@ -967,7 +969,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 +992,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 +1009,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 +1017,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 +1028,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 +1061,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 +1073,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_) { } } @@ -1113,6 +1118,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_ @@ -1270,6 +1276,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 +1384,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,6 +1467,17 @@ 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; } @@ -1493,6 +1537,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++) { @@ -1549,6 +1600,10 @@ 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) { @@ -1582,6 +1637,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_); } @@ -1826,17 +1882,60 @@ 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() { + + 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) { @@ -2379,11 +2478,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) { @@ -2775,10 +2874,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) { diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index deda9213..76fe8a65 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 { @@ -471,6 +471,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 +495,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(); @@ -1264,6 +1276,49 @@ 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() { + + 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 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_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_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.h b/src/google/protobuf/util/field_comparator.h index ee676265..8b83c69f 100644 --- a/src/google/protobuf/util/field_comparator.h +++ b/src/google/protobuf/util/field_comparator.h @@ -93,7 +93,7 @@ class LIBPROTOBUF_EXPORT FieldComparator { // Basic implementation of FieldComparator. Supports four modes of floating // point value comparison: exact, approximate using MathUtil::AlmostEqual -// method, and arbitrarilly precise using MathUtil::WithinFracionOrMargin. +// method, and arbitrarilly 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..23f7d51d 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -34,8 +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 { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc index 29ca9c1e..c59f43aa 100644 --- a/src/google/protobuf/util/field_mask_util.cc +++ b/src/google/protobuf/util/field_mask_util.cc @@ -103,7 +103,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/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index ea360798..b557429f 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 { @@ -57,13 +57,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 +71,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 +112,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>(); } diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h index 2ab3fa88..f22bfe70 100644 --- a/src/google/protobuf/util/internal/datapiece.h +++ b/src/google/protobuf/util/internal/datapiece.h @@ -98,7 +98,8 @@ class LIBPROTOBUF_EXPORT DataPiece { static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); } - virtual ~DataPiece() {} + virtual ~DataPiece() { + } // Accessors Type type() const { return type_; } diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 97b248ff..a63e560d 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,13 +43,25 @@ 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).*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), ow_(ow) {} @@ -165,12 +178,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( return this; } -DefaultValueObjectWriter* -DefaultValueObjectWriter::DisableCaseNormalizationForNextKey() { - disable_normalize_ = true; - return this; -} - DefaultValueObjectWriter::Node::Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, @@ -178,7 +185,6 @@ DefaultValueObjectWriter::Node::Node(const string& name, : name_(name), type_(type), kind_(kind), - disable_normalize_(false), is_any_(false), data_(data), is_placeholder_(is_placeholder) {} @@ -198,10 +204,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; @@ -324,6 +326,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( } } } + if (!is_map && field.cardinality() == google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { @@ -336,11 +339,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)); new_children.push_back(child.release()); } // Adds all leftover nodes in children_ to the beginning of new_child. @@ -363,41 +366,68 @@ 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()); + + 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()) + : 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()); } case google::protobuf::Field_Kind_TYPE_BYTES: { - return DataPiece("", false); + return DataPiece(field.default_value(), false); } 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(); } } @@ -408,7 +438,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( if (current_ == NULL) { root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), false)); - root_->set_disable_normalize(GetAndResetDisableNormalize()); root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; @@ -428,7 +457,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( } child->set_is_placeholder(false); - child->set_disable_normalize(GetAndResetDisableNormalize()); if (child->kind() == OBJECT && child->number_of_children() == 0) { child->PopulateChildren(typeinfo_); } @@ -454,21 +482,18 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( if (current_ == NULL) { root_.reset( new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false)); - root_->set_disable_normalize(GetAndResetDisableNormalize()); 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)); child = node.get(); current_->AddChild(node.release()); } child->set_is_placeholder(false); - child->set_disable_normalize(GetAndResetDisableNormalize()); stack_.push(current_); current_ = child; @@ -526,7 +551,6 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, } 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..695b9dd8 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -98,8 +98,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { virtual DefaultValueObjectWriter* RenderNull(StringPiece name); - virtual DefaultValueObjectWriter* DisableCaseNormalizationForNextKey(); - private: enum NodeKind { PRIMITIVE = 0, @@ -149,10 +147,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { 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_; } void set_is_any(bool is_any) { is_any_ = is_any; } @@ -176,8 +170,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. @@ -201,16 +193,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 +214,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. 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_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index dcd60601..9d820162 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_; @@ -64,36 +63,34 @@ class JsonObjectWriterTest : public ::testing::Test { 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\"," diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index a7ef7fe2..df916751 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -157,10 +157,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 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..3414826e 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -348,6 +348,7 @@ 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 diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h index 20bd3627..e695f45e 100644 --- a/src/google/protobuf/util/internal/object_writer.h +++ b/src/google/protobuf/util/internal/object_writer.h @@ -101,11 +101,6 @@ 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); 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..47e0009e --- /dev/null +++ b/src/google/protobuf/util/internal/proto_writer.cc @@ -0,0 +1,744 @@ +// 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; + } + + WriteTag(*field); + element_.reset(new ProtoElement(element_.release(), field, *type, false)); + return this; +} + +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; + } + + element_.reset(new ProtoElement(element_.release(), field, *type, true)); + return this; +} + +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; + } + + // 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; +} + +bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name) { + if (element_ == NULL) return true; + + if (field.oneof_index() > 0) { + if (element_->IsOneofIndexTaken(field.oneof_index())) { + InvalidValue( + "oneof", + StrCat("oneof field '", + element_->type().oneofs(field.oneof_index() - 1), + "' is already set. Cannot set '", unnormalized_name, "'")); + return false; + } + element_->TakeOneofIndex(field.oneof_index()); + } + return true; +} + +bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { + return field.cardinality() == + google::protobuf::Field_Cardinality_CARDINALITY_REPEATED; +} + +const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, + bool is_list) { + if (invalid_depth_ > 0) { + ++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..e631e56f --- /dev/null +++ b/src/google/protobuf/util/internal/proto_writer.h @@ -0,0 +1,315 @@ +// 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)); + } + virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { + return RenderDataPiece(name, DataPiece(value, false)); + } + 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() const { 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); + + 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..034d616f 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -140,10 +140,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 +171,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 +220,32 @@ 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()) { + return Status(util::error::INTERNAL, "Map key must be non-empty"); + } + RETURN_IF_ERROR(RenderField(field, map_key, ow)); } - // 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,18 +260,6 @@ 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) { @@ -601,10 +575,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 +650,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 +677,118 @@ 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(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); + } 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. @@ -806,45 +810,20 @@ Status ProtoStreamObjectSource::RenderField( 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: diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 3cd37aa1..78defa1d 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -122,20 +122,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 +202,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 @@ -238,6 +236,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // google::protobuf::Type of the message source. const google::protobuf::Type& type_; + 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..561f6763 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -327,9 +327,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 +345,6 @@ TEST_P(ProtostreamObjectSourceTest, NestedMessage) { ow_.StartObject("") ->RenderString("title", "My Book") ->StartObject("author") - ->RenderUint64("id", bit_cast<uint64>(101LL)) ->RenderString("name", "Tolstoy") ->EndObject() ->EndObject(); diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 08a2fb9a..786bf0be 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; @@ -60,230 +59,31 @@ 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()) {} + : ProtoWriter(type_resolver, type, output, listener), + master_type_(type), + current_(NULL) {} 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) {} 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 +98,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) @@ -421,7 +293,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; @@ -440,8 +312,8 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { // Create our object writer and initialize it with the first StartObject // call. - ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo_, *type, &output_, - parent_->listener_)); + ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, + parent_->listener())); ow_->StartObject(""); } @@ -453,604 +325,431 @@ 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)); + 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)); + 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; } - const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { - ++invalid_depth_; - InvalidName(name, - StrCat("Missing descriptor for field: ", field->type_url())); + // 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; } - element_.reset( - new ProtoElement(element_.release(), field, *type, element_type)); + if (IsMap(*field)) { + InvalidValue("Map", + StrCat("Cannot bind a list to map for field '", name, "'.")); + IncrementInvalidDepth(); + return this; + } + + // 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; } @@ -1083,7 +782,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 +804,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))); return Status::OK; } @@ -1162,224 +861,133 @@ 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 || 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)); + field = Lookup("value"); if (field == NULL) { + GOOGLE_LOG(DFATAL) << "Map does not have a value field."; + 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; } - // 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; + // 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; + } - type_url = field->type_url(); + // 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 +1054,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 +1067,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 +1101,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 +1109,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..08ac6e33 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,9 +68,11 @@ 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: // Constructor. Does not take ownership of any parameter passed in. ProtoStreamObjectWriter(TypeResolver* type_resolver, @@ -82,56 +85,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); + virtual 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_; - } - - // 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&); @@ -192,73 +152,37 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter bool has_injected_value_message_; }; - 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 +190,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 +201,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_; - // Container for inserting 'size' information at the 'pos' position. - struct SizeInfo { - const int pos; - int size; + // Conveys whether this Item is a list or not. This is used to send + // StartList or EndList calls to underlying ObjectWriter. + bool is_list_; + + 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 +260,46 @@ 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_; 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..5f9ffb95 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -241,6 +241,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); @@ -796,10 +811,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 +875,18 @@ 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, InvalidTimestampError1) { TimestampDuration timestamp; @@ -922,9 +945,66 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { 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, 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, 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 +1042,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 +1061,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; @@ -1066,12 +1159,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(); } @@ -1121,10 +1214,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") @@ -1591,13 +1685,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..82b81760 100644 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ b/src/google/protobuf/util/internal/testdata/books.proto @@ -66,7 +66,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; 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/utility.cc b/src/google/protobuf/util/internal/utility.cc index 61899c24..1ddf2487 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) { @@ -316,16 +330,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/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 47237e5a..0f879dc7 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -238,9 +238,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 +271,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); @@ -920,7 +939,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()); } 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..7f1093c8 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; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index 991c3d04..79493ca0 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -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/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index b2a7e970..212dd219 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,10 @@ 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(\014BS\n\023com" + ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242" + "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006" + "proto3", 406); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/wrappers.proto", &protobuf_RegisterTypes); DoubleValue::default_instance_ = new DoubleValue(); @@ -308,9 +309,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 +319,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 +351,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,11 +383,7 @@ 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() { @@ -495,6 +510,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 +559,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 +569,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 +601,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,11 +633,7 @@ 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() { @@ -719,6 +760,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 +809,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 +819,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 +851,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,11 +883,7 @@ 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() { @@ -945,6 +1012,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 +1061,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 +1071,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 +1103,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,11 +1135,7 @@ 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() { @@ -1171,6 +1264,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 +1313,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 +1323,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 +1355,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,11 +1387,7 @@ 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() { @@ -1397,6 +1516,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 +1565,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 +1575,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 +1607,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,11 +1639,7 @@ 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() { @@ -1623,6 +1768,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 +1817,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 +1827,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 +1859,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,11 +1891,7 @@ 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() { @@ -1847,6 +2018,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 +2067,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 +2077,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 +2110,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,15 +2143,11 @@ 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()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool StringValue::MergePartialFromCodedStream( @@ -2065,8 +2262,7 @@ void StringValue::MergeFrom(const ::google::protobuf::Message& from) { void StringValue::MergeFrom(const StringValue& from) { 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()); } } @@ -2089,6 +2285,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 +2318,44 @@ 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() { - return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} + ::std::string* StringValue::unsafe_arena_release_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + + return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } void StringValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -2147,7 +2363,20 @@ 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_set_allocated:google.protobuf.StringValue.value) } @@ -2155,9 +2384,9 @@ void StringValue::clear_value() { // =================================================================== -#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 +2394,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 +2427,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,15 +2460,11 @@ 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()); + value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool BytesValue::MergePartialFromCodedStream( @@ -2324,8 +2567,7 @@ void BytesValue::MergeFrom(const ::google::protobuf::Message& from) { void BytesValue::MergeFrom(const BytesValue& from) { 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()); } } @@ -2348,6 +2590,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 +2623,44 @@ 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() { - return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} + ::std::string* BytesValue::unsafe_arena_release_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,7 +2668,20 @@ 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_set_allocated:google.protobuf.BytesValue.value) } diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index 15bcc7a2..7dca938c 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,44 @@ 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() { - return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* StringValue::unsafe_arena_release_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + + return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void StringValue::set_allocated_value(::std::string* value) { if (value != NULL) { @@ -932,7 +1063,20 @@ 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_set_allocated:google.protobuf.StringValue.value) } @@ -942,36 +1086,44 @@ 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() { - return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* BytesValue::unsafe_arena_release_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,7 +1131,20 @@ 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_set_allocated:google.protobuf.BytesValue.value) } diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index a1d6e446..040d8a24 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -37,11 +37,12 @@ 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 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`. |