aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf
diff options
context:
space:
mode:
authorGravatar xiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2012-09-22 02:40:50 +0000
committerGravatar xiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2012-09-22 02:40:50 +0000
commitb55a20fa2c669b181f47ea9219b8e74d1263da19 (patch)
tree3936a0e7c22196587a6d8397372de41434fe2129 /src/google/protobuf
parent9ced30caf94bb4e7e9629c199679ff44e8ca7389 (diff)
Down-integrate from internal branch
Diffstat (limited to 'src/google/protobuf')
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc232
-rw-r--r--src/google/protobuf/compiler/command_line_interface.h45
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc120
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc23
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.h7
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc31
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h16
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc59
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc37
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h15
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc55
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc29
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h58
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc17
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc83
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc75
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.h51
-rw-r--r--src/google/protobuf/compiler/importer.h5
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment.cc236
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment.h69
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment_unittest.cc66
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc42
-rw-r--r--src/google/protobuf/compiler/java/java_enum.h2
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc108
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.h2
-rw-r--r--src/google/protobuf/compiler/java/java_extension.cc2
-rw-r--r--src/google/protobuf/compiler/java/java_field.h1
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc100
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.cc58
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h27
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc456
-rw-r--r--src/google/protobuf/compiler/java/java_message.h3
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc146
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.h2
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc104
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.h2
-rw-r--r--src/google/protobuf/compiler/java/java_service.cc3
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc164
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.h2
-rw-r--r--src/google/protobuf/compiler/main.cc2
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc12
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.h4
-rw-r--r--src/google/protobuf/compiler/parser.cc400
-rw-r--r--src/google/protobuf/compiler/parser.h53
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc768
-rw-r--r--src/google/protobuf/compiler/plugin.h1
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc79
-rw-r--r--src/google/protobuf/compiler/plugin.pb.h194
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc191
-rw-r--r--src/google/protobuf/compiler/python/python_generator.h5
-rw-r--r--src/google/protobuf/compiler/subprocess.cc1
-rw-r--r--src/google/protobuf/compiler/subprocess.h2
-rw-r--r--src/google/protobuf/descriptor.cc660
-rw-r--r--src/google/protobuf/descriptor.h162
-rw-r--r--src/google/protobuf/descriptor.pb.cc1348
-rw-r--r--src/google/protobuf/descriptor.pb.h1725
-rw-r--r--src/google/protobuf/descriptor.proto98
-rw-r--r--src/google/protobuf/descriptor_database.cc2
-rw-r--r--src/google/protobuf/descriptor_database.h1
-rw-r--r--src/google/protobuf/descriptor_unittest.cc702
-rw-r--r--src/google/protobuf/dynamic_message.cc43
-rw-r--r--src/google/protobuf/dynamic_message.h4
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc4
-rw-r--r--src/google/protobuf/extension_set.cc411
-rw-r--r--src/google/protobuf/extension_set.h227
-rw-r--r--src/google/protobuf/extension_set_heavy.cc274
-rw-r--r--src/google/protobuf/extension_set_unittest.cc92
-rw-r--r--src/google/protobuf/generated_enum_reflection.h85
-rw-r--r--src/google/protobuf/generated_message_reflection.cc97
-rw-r--r--src/google/protobuf/generated_message_reflection.h49
-rw-r--r--src/google/protobuf/generated_message_reflection_unittest.cc100
-rw-r--r--src/google/protobuf/generated_message_util.cc1
-rw-r--r--src/google/protobuf/generated_message_util.h21
-rw-r--r--src/google/protobuf/io/coded_stream.cc48
-rw-r--r--src/google/protobuf/io/coded_stream.h47
-rw-r--r--src/google/protobuf/io/coded_stream_inl.h2
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc62
-rw-r--r--src/google/protobuf/io/gzip_stream.cc19
-rw-r--r--src/google/protobuf/io/gzip_stream.h14
-rw-r--r--src/google/protobuf/io/printer.cc7
-rw-r--r--src/google/protobuf/io/printer_unittest.cc26
-rw-r--r--src/google/protobuf/io/tokenizer.cc497
-rw-r--r--src/google/protobuf/io/tokenizer.h85
-rw-r--r--src/google/protobuf/io/tokenizer_unittest.cc241
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.cc3
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.cc4
-rw-r--r--src/google/protobuf/io/zero_copy_stream_unittest.cc94
-rw-r--r--src/google/protobuf/lite_unittest.cc75
-rw-r--r--src/google/protobuf/message.cc43
-rw-r--r--src/google/protobuf/message.h162
-rw-r--r--src/google/protobuf/message_lite.cc4
-rw-r--r--src/google/protobuf/message_lite.h9
-rw-r--r--src/google/protobuf/message_unittest.cc73
-rw-r--r--src/google/protobuf/reflection_ops.cc19
-rw-r--r--src/google/protobuf/reflection_ops.h1
-rw-r--r--src/google/protobuf/repeated_field.cc4
-rw-r--r--src/google/protobuf/repeated_field.h339
-rw-r--r--src/google/protobuf/repeated_field_reflection_unittest.cc193
-rw-r--r--src/google/protobuf/repeated_field_unittest.cc353
-rw-r--r--src/google/protobuf/stubs/common.cc18
-rw-r--r--src/google/protobuf/stubs/common.h35
-rw-r--r--src/google/protobuf/stubs/hash.h12
-rw-r--r--src/google/protobuf/stubs/map-util.h24
-rw-r--r--src/google/protobuf/stubs/stl_util.h121
-rw-r--r--src/google/protobuf/stubs/stringprintf.cc170
-rw-r--r--src/google/protobuf/stubs/stringprintf.h76
-rw-r--r--src/google/protobuf/stubs/stringprintf_unittest.cc152
-rw-r--r--src/google/protobuf/stubs/strutil.cc38
-rw-r--r--src/google/protobuf/stubs/strutil.h14
-rw-r--r--src/google/protobuf/stubs/substitute.cc2
-rw-r--r--src/google/protobuf/stubs/template_util.h138
-rw-r--r--src/google/protobuf/stubs/template_util_unittest.cc130
-rw-r--r--src/google/protobuf/stubs/type_traits.h346
-rw-r--r--src/google/protobuf/stubs/type_traits_unittest.cc647
-rw-r--r--src/google/protobuf/test_util.cc307
-rw-r--r--src/google/protobuf/test_util.h21
-rw-r--r--src/google/protobuf/test_util_lite.cc152
-rw-r--r--src/google/protobuf/testdata/golden_messagebin487 -> 509 bytes
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data.txt12
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_extensions_data.txt12
-rw-r--r--src/google/protobuf/testing/googletest.cc11
-rw-r--r--src/google/protobuf/testing/googletest.h11
-rw-r--r--src/google/protobuf/text_format.cc264
-rw-r--r--src/google/protobuf/text_format.h63
-rw-r--r--src/google/protobuf/text_format_unittest.cc104
-rw-r--r--src/google/protobuf/unittest.proto88
-rw-r--r--src/google/protobuf/unittest_custom_options.proto21
-rw-r--r--src/google/protobuf/unittest_import.proto3
-rw-r--r--src/google/protobuf/unittest_import_lite.proto2
-rw-r--r--src/google/protobuf/unittest_import_public.proto40
-rw-r--r--src/google/protobuf/unittest_import_public_lite.proto42
-rw-r--r--src/google/protobuf/unittest_lite.proto48
-rw-r--r--src/google/protobuf/unknown_field_set.cc78
-rw-r--r--src/google/protobuf/unknown_field_set.h75
-rw-r--r--src/google/protobuf/unknown_field_set_unittest.cc88
-rw-r--r--src/google/protobuf/wire_format.cc36
-rw-r--r--src/google/protobuf/wire_format.h3
-rw-r--r--src/google/protobuf/wire_format_lite.cc4
-rw-r--r--src/google/protobuf/wire_format_lite.h10
-rw-r--r--src/google/protobuf/wire_format_lite_inl.h12
-rw-r--r--src/google/protobuf/wire_format_unittest.cc93
155 files changed, 13435 insertions, 2970 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 1c76994b..8dac5f42 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -59,12 +59,13 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -145,7 +146,7 @@ void AddTrailingSlash(string* path) {
bool VerifyDirectoryExists(const string& path) {
if (path.empty()) return true;
- if (access(path.c_str(), W_OK) == -1) {
+ if (access(path.c_str(), F_OK) == -1) {
cerr << path << ": " << strerror(errno) << endl;
return false;
} else {
@@ -566,6 +567,7 @@ CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false),
+ source_info_in_descriptor_set_(false),
disallow_services_(false),
inputs_are_proto_path_relative_(false) {}
CommandLineInterface::~CommandLineInterface() {}
@@ -574,9 +576,23 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name,
CodeGenerator* generator,
const string& help_text) {
GeneratorInfo info;
+ info.flag_name = flag_name;
info.generator = generator;
info.help_text = help_text;
- generators_[flag_name] = info;
+ generators_by_flag_name_[flag_name] = info;
+}
+
+void CommandLineInterface::RegisterGenerator(const string& flag_name,
+ const string& option_flag_name,
+ CodeGenerator* generator,
+ const string& help_text) {
+ GeneratorInfo info;
+ info.flag_name = flag_name;
+ info.option_flag_name = option_flag_name;
+ info.generator = generator;
+ info.help_text = help_text;
+ generators_by_flag_name_[flag_name] = info;
+ generators_by_option_name_[option_flag_name] = info;
}
void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
@@ -585,7 +601,14 @@ void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
int CommandLineInterface::Run(int argc, const char* const argv[]) {
Clear();
- if (!ParseArguments(argc, argv)) return 1;
+ switch (ParseArguments(argc, argv)) {
+ case PARSE_ARGUMENT_DONE_AND_EXIT:
+ return 0;
+ case PARSE_ARGUMENT_FAIL:
+ return 1;
+ case PARSE_ARGUMENT_DONE_AND_CONTINUE:
+ break;
+ }
// Set up the source tree.
DiskSourceTree source_tree;
@@ -713,6 +736,7 @@ void CommandLineInterface::Clear() {
mode_ = MODE_COMPILE;
imports_in_descriptor_set_ = false;
+ source_info_in_descriptor_set_ = false;
disallow_services_ = false;
}
@@ -755,7 +779,8 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
return true;
}
-bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
executable_name_ = argv[0];
// Iterate through all arguments and parse them.
@@ -769,41 +794,50 @@ bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
if (name == "--decode") {
cerr << "To decode an unknown message, use --decode_raw." << endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else {
++i;
value = argv[i];
}
}
- if (!InterpretArgument(name, value)) return false;
+ ParseArgumentStatus status = InterpretArgument(name, value);
+ if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
+ return status;
}
// If no --proto_path was given, use the current working directory.
if (proto_path_.empty()) {
- proto_path_.push_back(make_pair<string, string>("", "."));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>("", "."));
}
// Check some errror cases.
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
if (decoding_raw && !input_files_.empty()) {
cerr << "When using --decode_raw, no input files should be given." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else if (!decoding_raw && input_files_.empty()) {
cerr << "Missing input file." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ == MODE_COMPILE && output_directives_.empty() &&
descriptor_set_name_.empty()) {
cerr << "Missing output directives." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
cerr << "--include_imports only makes sense when combined with "
"--descriptor_set_out." << endl;
}
+ if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
+ cerr << "--include_source_info only makes sense when combined with "
+ "--descriptor_set_out." << endl;
+ }
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
bool CommandLineInterface::ParseArgument(const char* arg,
@@ -853,6 +887,7 @@ bool CommandLineInterface::ParseArgument(const char* arg,
if (*name == "-h" || *name == "--help" ||
*name == "--disallow_services" ||
*name == "--include_imports" ||
+ *name == "--include_source_info" ||
*name == "--version" ||
*name == "--decode_raw") {
// HACK: These are the only flags that don't take a value.
@@ -865,8 +900,9 @@ bool CommandLineInterface::ParseArgument(const char* arg,
return true;
}
-bool CommandLineInterface::InterpretArgument(const string& name,
- const string& value) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::InterpretArgument(const string& name,
+ const string& value) {
if (name.empty()) {
// Not a flag. Just a filename.
if (value.empty()) {
@@ -874,7 +910,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
"arguments to " << executable_name_ << ". This is actually "
"sort of hard to do. Congrats. Unfortunately it is not valid "
"input so the program is going to die now." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
input_files_.push_back(value);
@@ -902,7 +938,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
if (disk_path.empty()) {
cerr << "--proto_path passed empty directory name. (Use \".\" for "
"current directory.)" << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
// Make sure disk path exists, warn otherwise.
@@ -910,35 +946,45 @@ bool CommandLineInterface::InterpretArgument(const string& name,
cerr << disk_path << ": warning: directory does not exist." << endl;
}
- proto_path_.push_back(make_pair<string, string>(virtual_path, disk_path));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
}
} else if (name == "-o" || name == "--descriptor_set_out") {
if (!descriptor_set_name_.empty()) {
cerr << name << " may only be passed once." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (value.empty()) {
cerr << name << " requires a non-empty value." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ != MODE_COMPILE) {
cerr << "Cannot use --encode or --decode and generate descriptors at the "
"same time." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
descriptor_set_name_ = value;
} else if (name == "--include_imports") {
if (imports_in_descriptor_set_) {
cerr << name << " may only be passed once." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
imports_in_descriptor_set_ = true;
+ } else if (name == "--include_source_info") {
+ if (source_info_in_descriptor_set_) {
+ cerr << name << " may only be passed once." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ source_info_in_descriptor_set_ = true;
+
} else if (name == "-h" || name == "--help") {
PrintHelpText();
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--version") {
if (!version_info_.empty()) {
@@ -947,7 +993,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
cout << "libprotoc "
<< protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
<< endl;
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--disallow_services") {
disallow_services_ = true;
@@ -956,12 +1002,12 @@ bool CommandLineInterface::InterpretArgument(const string& name,
name == "--decode_raw") {
if (mode_ != MODE_COMPILE) {
cerr << "Only one of --encode and --decode can be specified." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
cerr << "Cannot use " << name
<< " and generate code or descriptors at the same time." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
@@ -971,10 +1017,10 @@ bool CommandLineInterface::InterpretArgument(const string& name,
if (name == "--decode") {
cerr << "To decode an unknown message, use --decode_raw." << endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else if (!value.empty() && name == "--decode_raw") {
cerr << "--decode_raw does not take a parameter." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
codec_type_ = value;
@@ -986,16 +1032,16 @@ bool CommandLineInterface::InterpretArgument(const string& name,
error_format_ = ERROR_FORMAT_MSVS;
} else {
cerr << "Unknown error format: " << value << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
} else if (name == "--plugin") {
if (plugin_prefix_.empty()) {
cerr << "This compiler does not support plugins." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
- string name;
+ string plugin_name;
string path;
string::size_type equals_pos = value.find_first_of('=');
@@ -1003,57 +1049,68 @@ bool CommandLineInterface::InterpretArgument(const string& name,
// Use the basename of the file.
string::size_type slash_pos = value.find_last_of('/');
if (slash_pos == string::npos) {
- name = value;
+ plugin_name = value;
} else {
- name = value.substr(slash_pos + 1);
+ plugin_name = value.substr(slash_pos + 1);
}
path = value;
} else {
- name = value.substr(0, equals_pos);
+ plugin_name = value.substr(0, equals_pos);
path = value.substr(equals_pos + 1);
}
- plugins_[name] = path;
+ plugins_[plugin_name] = path;
} else {
// Some other flag. Look it up in the generators list.
- const GeneratorInfo* generator_info = FindOrNull(generators_, name);
+ const GeneratorInfo* generator_info =
+ FindOrNull(generators_by_flag_name_, name);
if (generator_info == NULL &&
(plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
- cerr << "Unknown flag: " << name << endl;
- return false;
- }
+ // Check if it's a generator option flag.
+ generator_info = FindOrNull(generators_by_option_name_, name);
+ if (generator_info == NULL) {
+ cerr << "Unknown flag: " << name << endl;
+ return PARSE_ARGUMENT_FAIL;
+ } else {
+ string* parameters = &generator_parameters_[generator_info->flag_name];
+ if (!parameters->empty()) {
+ parameters->append(",");
+ }
+ parameters->append(value);
+ }
+ } else {
+ // It's an output flag. Add it to the output directives.
+ if (mode_ != MODE_COMPILE) {
+ cerr << "Cannot use --encode or --decode and generate code at the "
+ "same time." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
- // It's an output flag. Add it to the output directives.
- if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate code at the "
- "same time." << endl;
- return false;
- }
+ OutputDirective directive;
+ directive.name = name;
+ if (generator_info == NULL) {
+ directive.generator = NULL;
+ } else {
+ directive.generator = generator_info->generator;
+ }
- OutputDirective directive;
- directive.name = name;
- if (generator_info == NULL) {
- directive.generator = NULL;
- } else {
- directive.generator = generator_info->generator;
- }
+ // Split value at ':' to separate the generator parameter from the
+ // filename. However, avoid doing this if the colon is part of a valid
+ // Windows-style absolute path.
+ string::size_type colon_pos = value.find_first_of(':');
+ if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
+ directive.output_location = value;
+ } else {
+ directive.parameter = value.substr(0, colon_pos);
+ directive.output_location = value.substr(colon_pos + 1);
+ }
- // Split value at ':' to separate the generator parameter from the
- // filename. However, avoid doing this if the colon is part of a valid
- // Windows-style absolute path.
- string::size_type colon_pos = value.find_first_of(':');
- if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
- directive.output_location = value;
- } else {
- directive.parameter = value.substr(0, colon_pos);
- directive.output_location = value.substr(colon_pos + 1);
+ output_directives_.push_back(directive);
}
-
- output_directives_.push_back(directive);
}
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
void CommandLineInterface::PrintHelpText() {
@@ -1086,6 +1143,12 @@ void CommandLineInterface::PrintHelpText() {
" --include_imports When using --descriptor_set_out, also include\n"
" all dependencies of the input files in the\n"
" set, so that the set is self-contained.\n"
+" --include_source_info When using --descriptor_set_out, do not strip\n"
+" SourceCodeInfo from the FileDescriptorProto.\n"
+" This results in vastly larger descriptors that\n"
+" include information about the original\n"
+" location of each decl in the source file as\n"
+" well as surrounding comments.\n"
" --error_format=FORMAT Set the format in which to print errors.\n"
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
" (Microsoft Visual Studio format)." << endl;
@@ -1101,8 +1164,8 @@ void CommandLineInterface::PrintHelpText() {
" the executable's own name differs." << endl;
}
- for (GeneratorMap::iterator iter = generators_.begin();
- iter != generators_.end(); ++iter) {
+ for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
+ iter != generators_by_flag_name_.end(); ++iter) {
// FIXME(kenton): If the text is long enough it will wrap, which is ugly,
// but fixing this nicely (e.g. splitting on spaces) is probably more
// trouble than it's worth.
@@ -1136,10 +1199,16 @@ bool CommandLineInterface::GenerateOutput(
}
} else {
// Regular generator.
+ string parameters = output_directive.parameter;
+ if (!generator_parameters_[output_directive.name].empty()) {
+ if (!parameters.empty()) {
+ parameters.append(",");
+ }
+ parameters.append(generator_parameters_[output_directive.name]);
+ }
for (int i = 0; i < parsed_files.size(); i++) {
- if (!output_directive.generator->Generate(
- parsed_files[i], output_directive.parameter,
- generator_context, &error)) {
+ if (!output_directive.generator->Generate(parsed_files[i], parameters,
+ generator_context, &error)) {
// Generator returned an error.
cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
<< error << endl;
@@ -1168,8 +1237,9 @@ bool CommandLineInterface::GeneratePluginOutput(
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
request.add_file_to_generate(parsed_files[i]->name());
- GetTransitiveDependencies(parsed_files[i], &already_seen,
- request.mutable_proto_file());
+ GetTransitiveDependencies(parsed_files[i],
+ true, // Include source code info.
+ &already_seen, request.mutable_proto_file());
}
// Invoke the plugin.
@@ -1299,12 +1369,17 @@ bool CommandLineInterface::WriteDescriptorSet(
if (imports_in_descriptor_set_) {
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
- GetTransitiveDependencies(
- parsed_files[i], &already_seen, file_set.mutable_file());
+ GetTransitiveDependencies(parsed_files[i],
+ source_info_in_descriptor_set_,
+ &already_seen, file_set.mutable_file());
}
} else {
for (int i = 0; i < parsed_files.size(); i++) {
- parsed_files[i]->CopyTo(file_set.add_file());
+ FileDescriptorProto* file_proto = file_set.add_file();
+ parsed_files[i]->CopyTo(file_proto);
+ if (source_info_in_descriptor_set_) {
+ parsed_files[i]->CopySourceCodeInfoTo(file_proto);
+ }
}
}
@@ -1334,7 +1409,7 @@ bool CommandLineInterface::WriteDescriptorSet(
}
void CommandLineInterface::GetTransitiveDependencies(
- const FileDescriptor* file,
+ const FileDescriptor* file, bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output) {
if (!already_seen->insert(file).second) {
@@ -1344,11 +1419,16 @@ void CommandLineInterface::GetTransitiveDependencies(
// Add all dependencies.
for (int i = 0; i < file->dependency_count(); i++) {
- GetTransitiveDependencies(file->dependency(i), already_seen, output);
+ GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+ already_seen, output);
}
// Add this file.
- file->CopyTo(output->Add());
+ FileDescriptorProto* new_descriptor = output->Add();
+ file->CopyTo(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 0b507d80..86ea9bde 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -112,6 +112,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
CodeGenerator* generator,
const string& help_text);
+ // Register a code generator for a language.
+ // Besides flag_name you can specify another option_flag_name that could be
+ // used to pass extra parameters to the registered code generator.
+ // Suppose you have registered a generator by calling:
+ // command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
+ // Then you could invoke the compiler with a command like:
+ // protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
+ // This will pass "enable_bar,enable_baz" as the parameter to the generator.
+ void RegisterGenerator(const string& flag_name,
+ const string& option_flag_name,
+ CodeGenerator* generator,
+ const string& help_text);
+
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
// but does not match any registered generator, the compiler will attempt to
// find a "plugin" to implement the generator. Plugins are just executables.
@@ -186,8 +199,15 @@ class LIBPROTOC_EXPORT CommandLineInterface {
bool MakeInputsBeProtoPathRelative(
DiskSourceTree* source_tree);
+ // Return status for ParseArguments() and InterpretArgument().
+ enum ParseArgumentStatus {
+ PARSE_ARGUMENT_DONE_AND_CONTINUE,
+ PARSE_ARGUMENT_DONE_AND_EXIT,
+ PARSE_ARGUMENT_FAIL
+ };
+
// Parse all command-line arguments.
- bool ParseArguments(int argc, const char* const argv[]);
+ ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
// Parses a command-line argument into a name/value pair. Returns
// true if the next argument in the argv should be used as the value,
@@ -203,7 +223,8 @@ class LIBPROTOC_EXPORT CommandLineInterface {
bool ParseArgument(const char* arg, string* name, string* value);
// Interprets arguments parsed with ParseArgument.
- bool InterpretArgument(const string& name, const string& value);
+ ParseArgumentStatus InterpretArgument(const string& name,
+ const string& value);
// Print the --help text to stderr.
void PrintHelpText();
@@ -230,9 +251,11 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// protos will be ordered such that every file is listed before any file that
// depends on it, so that you can call DescriptorPool::BuildFile() on them
// in order. Any files in *already_seen will not be added, and each file
- // added will be inserted into *already_seen.
+ // added will be inserted into *already_seen. If include_source_code_info is
+ // true then include the source code information in the FileDescriptorProtos.
static void GetTransitiveDependencies(
const FileDescriptor* file,
+ bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output);
@@ -244,13 +267,21 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Version info set with SetVersionInfo().
string version_info_;
- // Map from flag names to registered generators.
+ // Registered generators.
struct GeneratorInfo {
+ string flag_name;
+ string option_flag_name;
CodeGenerator* generator;
string help_text;
};
typedef map<string, GeneratorInfo> GeneratorMap;
- GeneratorMap generators_;
+ GeneratorMap generators_by_flag_name_;
+ GeneratorMap generators_by_option_name_;
+ // A map from generator names to the parameters specified using the option
+ // flag. For example, if the user invokes the compiler with:
+ // protoc --foo_out=outputdir --foo_opt=enable_bar ...
+ // Then there will be an entry ("--foo_out", "enable_bar") in this map.
+ map<string, string> generator_parameters_;
// See AllowPlugins(). If this is empty, plugins aren't allowed.
string plugin_prefix_;
@@ -302,6 +333,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// the .proto files listed on the command-line are added.
bool imports_in_descriptor_set_;
+ // True if --include_source_info was given, meaning that we should not strip
+ // SourceCodeInfo from the DescriptorSet.
+ bool source_info_in_descriptor_set_;
+
// Was the --disallow_services flag used?
bool disallow_services_;
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index d5b3a1dc..16559923 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -122,6 +122,10 @@ class CommandLineInterfaceTest : public testing::Test {
// substring.
void ExpectErrorSubstring(const string& expected_substring);
+ // Like ExpectErrorSubstring, but checks that Run() returned zero.
+ void ExpectErrorSubstringWithZeroReturnCode(
+ const string& expected_substring);
+
// Returns true if ExpectErrorSubstring(expected_substring) would pass, but
// does not fail otherwise.
bool HasAlternateErrorSubstring(const string& expected_substring);
@@ -225,7 +229,7 @@ void CommandLineInterfaceTest::SetUp() {
// Register generators.
CodeGenerator* generator = new MockCodeGenerator("test_generator");
mock_generators_to_delete_.push_back(generator);
- cli_.RegisterGenerator("--test_out", generator, "Test output.");
+ cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output.");
cli_.RegisterGenerator("-t", generator, "Test output.");
generator = new MockCodeGenerator("alt_generator");
@@ -345,6 +349,12 @@ void CommandLineInterfaceTest::ExpectErrorSubstring(
EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
}
+void CommandLineInterfaceTest::ExpectErrorSubstringWithZeroReturnCode(
+ const string& expected_substring) {
+ EXPECT_EQ(0, return_code_);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+}
+
bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
const string& expected_substring) {
EXPECT_NE(0, return_code_);
@@ -544,6 +554,32 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo");
}
+TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
+ // Test that generator parameters specified with the option flag are
+ // correctly passed to the code generator.
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ // Create the "a" and "b" sub-directories.
+ CreateTempDir("a");
+ CreateTempDir("b");
+
+ Run("protocol_compiler "
+ "--test_opt=foo1 "
+ "--test_out=bar:$tmpdir/a "
+ "--test_opt=foo2 "
+ "--test_out=baz:$tmpdir/b "
+ "--test_opt=foo3 "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated(
+ "test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
+ ExpectGenerated(
+ "test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
+}
+
TEST_F(CommandLineInterfaceTest, Insert) {
// Test running a generator that inserts code into another's output.
@@ -779,6 +815,33 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
if (HasFatalFailure()) return;
ASSERT_EQ(1, descriptor_set.file_size());
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());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+ "--include_source_info --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+ if (HasFatalFailure()) return;
+ ASSERT_EQ(1, descriptor_set.file_size());
+ EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
+ // Source code info included.
+ EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
}
TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
@@ -807,6 +870,40 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
}
EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+ // Descriptor set should not have source code info.
+ EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+ EXPECT_FALSE(descriptor_set.file(1).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+ "--include_imports --include_source_info --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+ if (HasFatalFailure()) return;
+ ASSERT_EQ(2, descriptor_set.file_size());
+ if (descriptor_set.file(0).name() == "bar.proto") {
+ std::swap(descriptor_set.mutable_file()->mutable_data()[0],
+ descriptor_set.mutable_file()->mutable_data()[1]);
+ }
+ EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+ EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+ // Source code info included.
+ EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+ EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
}
// -------------------------------------------------------------------
@@ -1129,6 +1226,17 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
#endif
}
+TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message MockCodeGenerator_HasSourceCodeInfo {}\n");
+
+ Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+ ExpectErrorSubstring(
+ "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
+}
+
TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
// Test what happens if the plugin isn't found.
@@ -1171,11 +1279,11 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) {
TEST_F(CommandLineInterfaceTest, HelpText) {
Run("test_exec_name --help");
- ExpectErrorSubstring("Usage: test_exec_name ");
- ExpectErrorSubstring("--test_out=OUT_DIR");
- ExpectErrorSubstring("Test output.");
- ExpectErrorSubstring("--alt_out=OUT_DIR");
- ExpectErrorSubstring("Alt output.");
+ ExpectErrorSubstringWithZeroReturnCode("Usage: test_exec_name ");
+ ExpectErrorSubstringWithZeroReturnCode("--test_out=OUT_DIR");
+ ExpectErrorSubstringWithZeroReturnCode("Test output.");
+ ExpectErrorSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
+ ExpectErrorSubstringWithZeroReturnCode("Alt output.");
}
TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index bcfa5020..b7c1766b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -48,8 +48,8 @@
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 76d2b798..67c12d7a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -46,10 +46,10 @@ namespace compiler {
namespace cpp {
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor),
classname_(ClassName(descriptor, false)),
- dllexport_decl_(dllexport_decl) {
+ options_(options) {
}
EnumGenerator::~EnumGenerator() {}
@@ -88,10 +88,10 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
vars["min_name"] = min_value->name();
vars["max_name"] = max_value->name();
- if (dllexport_decl_.empty()) {
+ if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
} else {
- vars["dllexport"] = dllexport_decl_ + " ";
+ vars["dllexport"] = options_.dllexport_decl + " ";
}
printer->Print(vars,
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 58f7721e..2e85a0bd 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -36,8 +36,10 @@
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
#include <string>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
+
namespace google {
namespace protobuf {
namespace io {
@@ -53,7 +55,7 @@ class EnumGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit EnumGenerator(const EnumDescriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~EnumGenerator();
// Header stuff.
@@ -86,7 +88,7 @@ class EnumGenerator {
private:
const EnumDescriptor* descriptor_;
string classname_;
- string dllexport_decl_;
+ Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index a369f417..6e1620d4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -46,8 +46,9 @@ namespace cpp {
namespace {
void SetEnumVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
(*variables)["default"] = SimpleItoa(default_value->number());
@@ -58,9 +59,10 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
// ===================================================================
EnumFieldGenerator::
-EnumFieldGenerator(const FieldDescriptor* descriptor)
+EnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetEnumVariables(descriptor, &variables_);
+ SetEnumVariables(descriptor, &variables_, options);
}
EnumFieldGenerator::~EnumFieldGenerator() {}
@@ -84,7 +86,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return static_cast< $type$ >($name$_);\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n"
- " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " assert($type$_IsValid(value));\n"
" set_has_$name$();\n"
" $name$_ = value;\n"
"}\n");
@@ -152,9 +154,10 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
RepeatedEnumFieldGenerator::
-RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetEnumVariables(descriptor, &variables_);
+ SetEnumVariables(descriptor, &variables_, options);
}
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
@@ -187,11 +190,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return static_cast< $type$ >($name$_.Get(index));\n"
"}\n"
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
- " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " assert($type$_IsValid(value));\n"
" $name$_.Set(index, value);\n"
"}\n"
"inline void $classname$::add_$name$($type$ value) {\n"
- " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " assert($type$_IsValid(value));\n"
" $name$_.Add(value);\n"
"}\n");
printer->Print(variables_,
@@ -345,7 +348,9 @@ GenerateByteSize(io::Printer* printer) const {
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = data_size;\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index 0793430c..65770083 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -46,7 +46,8 @@ namespace cpp {
class EnumFieldGenerator : public FieldGenerator {
public:
- explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+ explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~EnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -71,7 +72,8 @@ class EnumFieldGenerator : public FieldGenerator {
class RepeatedEnumFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedEnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 658a7077..ef56b5e5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -57,9 +57,9 @@ string ExtendeeClassName(const FieldDescriptor* descriptor) {
} // anonymous namespace
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor),
- dllexport_decl_(dllexport_decl) {
+ options_(options) {
// Construct type_traits_.
if (descriptor_->is_repeated()) {
type_traits_ = "Repeated";
@@ -106,8 +106,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
// export/import specifier.
if (descriptor_->extension_scope() == NULL) {
vars["qualifier"] = "extern";
- if (!dllexport_decl_.empty()) {
- vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
+ if (!options_.dllexport_decl.empty()) {
+ vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
}
} else {
vars["qualifier"] = "static";
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
index 3068b091..50ad035b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -37,6 +37,7 @@
#include <string>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -56,8 +57,8 @@ namespace cpp {
class ExtensionGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
- explicit ExtensionGenerator(const FieldDescriptor* descriptor,
- const string& dllexport_decl);
+ explicit ExtensionGenerator(const FieldDescriptor* desycriptor,
+ const Options& options);
~ExtensionGenerator();
// Header stuff.
@@ -72,7 +73,7 @@ class ExtensionGenerator {
private:
const FieldDescriptor* descriptor_;
string type_traits_;
- string dllexport_decl_;
+ Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 103cac4a..0786176b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -52,7 +52,8 @@ namespace cpp {
using internal::WireFormat;
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
+ map<string, string>* variables,
+ const Options& options) {
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
@@ -64,6 +65,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
(*variables)["deprecation"] = descriptor->options().deprecated()
? " PROTOBUF_DEPRECATED" : "";
+ (*variables)["cppget"] = "Get";
}
FieldGenerator::~FieldGenerator() {}
@@ -80,46 +82,47 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
}
-FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor),
- field_generators_(
- new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+ field_generators_(new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
// Construct all the FieldGenerators.
for (int i = 0; i < descriptor->field_count(); i++) {
- field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
+ field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
}
}
-FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
+ const Options& options) {
if (field->is_repeated()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- return new RepeatedMessageFieldGenerator(field);
+ return new RepeatedMessageFieldGenerator(field, options);
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // RepeatedStringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
- return new RepeatedStringFieldGenerator(field);
+ return new RepeatedStringFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
- return new RepeatedEnumFieldGenerator(field);
+ return new RepeatedEnumFieldGenerator(field, options);
default:
- return new RepeatedPrimitiveFieldGenerator(field);
+ return new RepeatedPrimitiveFieldGenerator(field, options);
}
} else {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- return new MessageFieldGenerator(field);
+ return new MessageFieldGenerator(field, options);
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // StringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
- return new StringFieldGenerator(field);
+ return new StringFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
- return new EnumFieldGenerator(field);
+ return new EnumFieldGenerator(field, options);
default:
- return new PrimitiveFieldGenerator(field);
+ return new PrimitiveFieldGenerator(field, options);
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index c303a337..f7d99b15 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -40,6 +40,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -57,7 +58,8 @@ namespace cpp {
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables);
+ map<string, string>* variables,
+ const Options& options);
class FieldGenerator {
public:
@@ -114,6 +116,13 @@ class FieldGenerator {
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateDestructorCode(io::Printer* printer) const {}
+ // Generate code that allocates the fields's default instance.
+ virtual void GenerateDefaultInstanceAllocator(io::Printer* printer) const {}
+
+ // Generate code that should be run when ShutdownProtobufLibrary() is called,
+ // to delete all dynamically-allocated objects.
+ virtual void GenerateShutdownCode(io::Printer* printer) const {}
+
// Generate lines to decode this field, which will be placed inside the
// message's MergeFromCodedStream() method.
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
@@ -144,7 +153,7 @@ class FieldGenerator {
// Convenience class which constructs FieldGenerators for a Descriptor.
class FieldGeneratorMap {
public:
- explicit FieldGeneratorMap(const Descriptor* descriptor);
+ explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
~FieldGeneratorMap();
const FieldGenerator& get(const FieldDescriptor* field) const;
@@ -153,7 +162,8 @@ class FieldGeneratorMap {
const Descriptor* descriptor_;
scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
- static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+ const Options& options);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index b8e7708f..1bbc89c4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -51,7 +51,7 @@ namespace cpp {
// ===================================================================
FileGenerator::FileGenerator(const FileDescriptor* file,
- const string& dllexport_decl)
+ const Options& options)
: file_(file),
message_generators_(
new scoped_ptr<MessageGenerator>[file->message_type_count()]),
@@ -61,26 +61,26 @@ FileGenerator::FileGenerator(const FileDescriptor* file,
new scoped_ptr<ServiceGenerator>[file->service_count()]),
extension_generators_(
new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
- dllexport_decl_(dllexport_decl) {
+ options_(options) {
for (int i = 0; i < file->message_type_count(); i++) {
message_generators_[i].reset(
- new MessageGenerator(file->message_type(i), dllexport_decl));
+ new MessageGenerator(file->message_type(i), options));
}
for (int i = 0; i < file->enum_type_count(); i++) {
enum_generators_[i].reset(
- new EnumGenerator(file->enum_type(i), dllexport_decl));
+ new EnumGenerator(file->enum_type(i), options));
}
for (int i = 0; i < file->service_count(); i++) {
service_generators_[i].reset(
- new ServiceGenerator(file->service(i), dllexport_decl));
+ new ServiceGenerator(file->service(i), options));
}
for (int i = 0; i < file->extension_count(); i++) {
extension_generators_[i].reset(
- new ExtensionGenerator(file->extension(i), dllexport_decl));
+ new ExtensionGenerator(file->extension(i), options));
}
SplitStringUsing(file_->package(), ".", &package_parts_);
@@ -104,6 +104,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"filename", file_->name(),
"filename_identifier", filename_identifier);
+
printer->Print(
"#include <google/protobuf/stubs/common.h>\n"
"\n");
@@ -128,13 +129,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// OK, it's now safe to #include other files.
printer->Print(
- "#include <google/protobuf/generated_message_util.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n");
+ if (file_->message_type_count() > 0) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/message.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/message_lite.h>\n");
+ }
+ }
+ printer->Print(
"#include <google/protobuf/repeated_field.h>\n"
"#include <google/protobuf/extension_set.h>\n");
- if (HasDescriptorMethods(file_)) {
+ if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
printer->Print(
- "#include <google/protobuf/generated_message_reflection.h>\n");
+ "#include <google/protobuf/generated_enum_reflection.h>\n");
}
if (HasGenericServices(file_)) {
@@ -142,6 +153,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"#include <google/protobuf/service.h>\n");
}
+ if (HasUnknownFields(file_) && file_->message_type_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/unknown_field_set.h>\n");
+ }
+
for (int i = 0; i < file_->dependency_count(); i++) {
printer->Print(
@@ -149,9 +165,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"dependency", StripProto(file_->dependency(i)->name()));
}
+
printer->Print(
"// @@protoc_insertion_point(includes)\n");
+
// Open namespace.
GenerateNamespaceOpeners(printer);
@@ -162,7 +180,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"// Internal implementation detail -- do not call these.\n"
"void $dllexport_decl$ $adddescriptorsname$();\n",
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
- "dllexport_decl", dllexport_decl_);
+ "dllexport_decl", options_.dllexport_decl);
printer->Print(
// Note that we don't put dllexport_decl on these because they are only
@@ -282,6 +300,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
void FileGenerator::GenerateSource(io::Printer* printer) {
printer->Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
"\n"
// The generated code calls accessors that might be deprecated. We don't
@@ -294,11 +313,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"#include <google/protobuf/stubs/once.h>\n"
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/wire_format_lite_inl.h>\n",
+ "filename", file_->name(),
"basename", StripProto(file_->name()));
if (HasDescriptorMethods(file_)) {
printer->Print(
"#include <google/protobuf/descriptor.h>\n"
+ "#include <google/protobuf/generated_message_reflection.h>\n"
"#include <google/protobuf/reflection_ops.h>\n"
"#include <google/protobuf/wire_format.h>\n");
}
@@ -504,10 +525,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
" static bool already_here = false;\n"
" if (already_here) return;\n"
" already_here = true;\n"
- " GOOGLE_PROTOBUF_VERIFY_VERSION;\n",
+ " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+ "\n",
// Without.
"void $adddescriptorsname$_impl() {\n"
- " GOOGLE_PROTOBUF_VERIFY_VERSION;\n",
+ " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+ "\n",
// Vars.
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
@@ -521,9 +544,9 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
vector<string> dependency_package_parts;
SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
printer->Print("::");
- for (int i = 0; i < dependency_package_parts.size(); i++) {
+ for (int j = 0; j < dependency_package_parts.size(); j++) {
printer->Print("$name$::",
- "name", dependency_package_parts[i]);
+ "name", dependency_package_parts[j]);
}
// Call its AddDescriptors function.
printer->Print(
@@ -547,10 +570,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
static const int kBytesPerLine = 40;
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
printer->Print("\n \"$data$\"",
- "data", EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+ "data",
+ EscapeTrigraphs(
+ CEscape(file_data.substr(i, kBytesPerLine))));
}
printer->Print(
- ", $size$);\n",
+ ", $size$);\n",
"size", SimpleItoa(file_data.size()));
// Call MessageFactory::InternalRegisterGeneratedFile().
@@ -594,7 +619,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// Without.
"GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n"
"void $adddescriptorsname$() {\n"
- " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
+ " ::google::protobuf::::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
" &$adddescriptorsname$_impl);\n"
"}\n",
// Vars.
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index b4e01285..2deefaa8 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -39,6 +39,7 @@
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -61,7 +62,7 @@ class FileGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit FileGenerator(const FileDescriptor* file,
- const string& dllexport_decl);
+ const Options& options);
~FileGenerator();
void GenerateHeader(io::Printer* printer);
@@ -85,7 +86,7 @@ class FileGenerator {
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
vector<string> package_parts_;
- string dllexport_decl_;
+ const Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index bb84e2ab..1813510b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -78,11 +78,13 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// }
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
// __declspec(dllimport) depending on what is being compiled.
- string dllexport_decl;
+ Options file_options;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "dllexport_decl") {
- dllexport_decl = options[i].second;
+ file_options.dllexport_decl = options[i].second;
+ } else if (options[i].first == "safe_boundary_check") {
+ file_options.safe_boundary_check = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
@@ -95,7 +97,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
string basename = StripProto(file->name());
basename.append(".pb");
- FileGenerator file_generator(file, dllexport_decl);
+ FileGenerator file_generator(file, file_options);
// Generate header.
{
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index c4b868c2..28911ab0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -148,7 +148,7 @@ string ClassName(const Descriptor* descriptor, bool qualified) {
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
if (enum_descriptor->containing_type() == NULL) {
if (qualified) {
- return DotsToColons(enum_descriptor->full_name());
+ return "::" + DotsToColons(enum_descriptor->full_name());
} else {
return enum_descriptor->name();
}
@@ -259,10 +259,23 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
string DefaultValue(const FieldDescriptor* field) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
+ // gcc rejects the decimal form of kint32min and kint64min.
+ if (field->default_value_int32() == kint32min) {
+ // Make sure we are in a 2's complement system.
+ GOOGLE_COMPILE_ASSERT(kint32min == -0x80000000, kint32min_value_error);
+ return "-0x80000000";
+ }
return SimpleItoa(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
return SimpleItoa(field->default_value_uint32()) + "u";
case FieldDescriptor::CPPTYPE_INT64:
+ // See the comments for CPPTYPE_INT32.
+ if (field->default_value_int64() == kint64min) {
+ // Make sure we are in a 2's complement system.
+ GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000),
+ kint64min_value_error);
+ return "GOOGLE_LONGLONG(-0x8000000000000000)";
+ }
return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
case FieldDescriptor::CPPTYPE_UINT64:
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
@@ -308,8 +321,9 @@ string DefaultValue(const FieldDescriptor* field) {
ClassName(field->enum_type(), true),
field->default_value_enum()->number());
case FieldDescriptor::CPPTYPE_STRING:
- return "\"" + EscapeTrigraphs(CEscape(field->default_value_string())) +
- "\"";
+ return "\"" + EscapeTrigraphs(
+ CEscape(field->default_value_string())) +
+ "\"";
case FieldDescriptor::CPPTYPE_MESSAGE:
return FieldMessageTypeName(field) + "::default_instance()";
}
@@ -401,6 +415,23 @@ void PrintHandlingOptionalStaticInitializers(
}
}
+
+static bool HasEnumDefinitions(const Descriptor* message_type) {
+ if (message_type->enum_type_count() > 0) return true;
+ for (int i = 0; i < message_type->nested_type_count(); ++i) {
+ if (HasEnumDefinitions(message_type->nested_type(i))) return true;
+ }
+ return false;
+}
+
+bool HasEnumDefinitions(const FileDescriptor* file) {
+ if (file->enum_type_count() > 0) return true;
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ if (HasEnumDefinitions(file->message_type(i))) return true;
+ }
+ return false;
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 662a7c31..526e19cc 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -122,23 +122,27 @@ string GlobalShutdownFileName(const string& filename);
string EscapeTrigraphs(const string& to_escape);
// Do message classes in this file keep track of unknown fields?
-inline bool HasUnknownFields(const FileDescriptor *file) {
+inline bool HasUnknownFields(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
+
+// Does this file have any enum type definitions?
+bool HasEnumDefinitions(const FileDescriptor* file);
+
// Does this file have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const FileDescriptor *file) {
+inline bool HasGeneratedMethods(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::CODE_SIZE;
}
-// Do message classes in this file have descriptor and refelction methods?
-inline bool HasDescriptorMethods(const FileDescriptor *file) {
+// Do message classes in this file have descriptor and reflection methods?
+inline bool HasDescriptorMethods(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor *file) {
+inline bool HasGenericServices(const FileDescriptor* file) {
return file->service_count() > 0 &&
file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
file->options().cc_generic_services();
@@ -173,6 +177,7 @@ void PrintHandlingOptionalStaticInitializers(
io::Printer* printer, const char* with_static_init,
const char* without_static_init);
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 1c158be0..1ea4f13d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -48,6 +48,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
+
namespace google {
namespace protobuf {
namespace compiler {
@@ -103,6 +104,13 @@ struct ExtensionRangeSorter {
}
};
+// Returns true if the "required" restriction check should be ignored for the
+// given field.
+inline static bool ShouldIgnoreRequiredFieldCheck(
+ const FieldDescriptor* field) {
+ return false;
+}
+
// Returns true if the message type has any required fields. If it doesn't,
// we can optimize out calls to its IsInitialized() method.
//
@@ -129,7 +137,8 @@ static bool HasRequiredFields(
if (field->is_required()) {
return true;
}
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !ShouldIgnoreRequiredFieldCheck(field)) {
if (HasRequiredFields(field->message_type(), already_seen)) {
return true;
}
@@ -280,11 +289,11 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor),
classname_(ClassName(descriptor, false)),
- dllexport_decl_(dllexport_decl),
- field_generators_(descriptor),
+ options_(options),
+ field_generators_(descriptor, options),
nested_generators_(new scoped_ptr<MessageGenerator>[
descriptor->nested_type_count()]),
enum_generators_(new scoped_ptr<EnumGenerator>[
@@ -294,17 +303,17 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
for (int i = 0; i < descriptor->nested_type_count(); i++) {
nested_generators_[i].reset(
- new MessageGenerator(descriptor->nested_type(i), dllexport_decl));
+ new MessageGenerator(descriptor->nested_type(i), options));
}
for (int i = 0; i < descriptor->enum_type_count(); i++) {
enum_generators_[i].reset(
- new EnumGenerator(descriptor->enum_type(i), dllexport_decl));
+ new EnumGenerator(descriptor->enum_type(i), options));
}
for (int i = 0; i < descriptor->extension_count(); i++) {
extension_generators_[i].reset(
- new ExtensionGenerator(descriptor->extension(i), dllexport_decl));
+ new ExtensionGenerator(descriptor->extension(i), options));
}
}
@@ -349,7 +358,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
- SetCommonFieldVariables(field, &vars);
+ SetCommonFieldVariables(field, &vars, options_);
vars["constant_name"] = FieldConstantName(field);
if (field->is_repeated()) {
@@ -386,7 +395,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
- SetCommonFieldVariables(field, &vars);
+ SetCommonFieldVariables(field, &vars, options_);
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
@@ -446,10 +455,10 @@ GenerateClassDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
vars["field_count"] = SimpleItoa(descriptor_->field_count());
- if (dllexport_decl_.empty()) {
+ if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
} else {
- vars["dllexport"] = dllexport_decl_ + " ";
+ vars["dllexport"] = options_.dllexport_decl + " ";
}
vars["superclass"] = SuperClassName(descriptor_);
@@ -507,6 +516,7 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+
printer->Print(vars,
"void Swap($classname$* other);\n"
"\n"
@@ -605,6 +615,7 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(" private:\n");
printer->Indent();
+
for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->is_repeated()) {
printer->Print(
@@ -680,7 +691,7 @@ GenerateClassDefinition(io::Printer* printer) {
// Without.
"friend void $dllexport_decl$ $adddescriptorsname$_impl();\n",
// Vars.
- "dllexport_decl", dllexport_decl_,
+ "dllexport_decl", options_.dllexport_decl,
"adddescriptorsname",
GlobalAddDescriptorsName(descriptor_->file()->name()));
@@ -772,9 +783,11 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
printer->Print(vars,
" -1,\n");
}
+ printer->Print(
+ " ::google::protobuf::DescriptorPool::generated_pool(),\n");
+ printer->Print(vars,
+ " ::google::protobuf::MessageFactory::generated_factory(),\n");
printer->Print(vars,
- " ::google::protobuf::DescriptorPool::generated_pool(),\n"
- " ::google::protobuf::MessageFactory::generated_factory(),\n"
" sizeof($classname$));\n");
// Handle nested types.
@@ -803,6 +816,13 @@ GenerateTypeRegistrations(io::Printer* printer) {
void MessageGenerator::
GenerateDefaultInstanceAllocator(io::Printer* printer) {
+ // Construct the default instances of all fields, as they will be used
+ // when creating the default instance of the entire message.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateDefaultInstanceAllocator(printer);
+ }
+
// Construct the default instance. We can't call InitAsDefaultInstance() yet
// because we need to make sure all default instances that this one might
// depend on are constructed first.
@@ -846,6 +866,12 @@ GenerateShutdownCode(io::Printer* printer) {
"classname", classname_);
}
+ // Handle default instances of fields.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateShutdownCode(printer);
+ }
+
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateShutdownCode(printer);
@@ -1957,6 +1983,7 @@ GenerateIsInitialized(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !ShouldIgnoreRequiredFieldCheck(field) &&
HasRequiredFields(field->message_type())) {
if (field->is_repeated()) {
printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 04778f6d..a7e43d9c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -38,6 +38,7 @@
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -57,7 +58,7 @@ class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit MessageGenerator(const Descriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~MessageGenerator();
// Header stuff.
@@ -153,7 +154,7 @@ class MessageGenerator {
const Descriptor* descriptor_;
string classname_;
- string dllexport_decl_;
+ Options options_;
FieldGeneratorMap field_generators_;
scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 7c785e7e..447f975f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -45,8 +45,9 @@ namespace cpp {
namespace {
void SetMessageVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
(*variables)["stream_writer"] = (*variables)["declared_type"] +
(HasFastArraySerialization(descriptor->message_type()->file()) ?
@@ -59,9 +60,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// ===================================================================
MessageFieldGenerator::
-MessageFieldGenerator(const FieldDescriptor* descriptor)
+MessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetMessageVariables(descriptor, &variables_);
+ SetMessageVariables(descriptor, &variables_, options);
}
MessageFieldGenerator::~MessageFieldGenerator() {}
@@ -76,7 +78,8 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const $type$& $name$() const$deprecation$;\n"
"inline $type$* mutable_$name$()$deprecation$;\n"
- "inline $type$* release_$name$()$deprecation$;\n");
+ "inline $type$* release_$name$()$deprecation$;\n"
+ "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
}
void MessageFieldGenerator::
@@ -103,6 +106,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $type$* temp = $name$_;\n"
" $name$_ = NULL;\n"
" return temp;\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " delete $name$_;\n"
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " set_has_$name$();\n"
+ " } else {\n"
+ " clear_has_$name$();\n"
+ " }\n"
"}\n");
}
@@ -167,9 +179,10 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetMessageVariables(descriptor, &variables_);
+ SetMessageVariables(descriptor, &variables_, options);
}
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
@@ -197,7 +210,7 @@ void RepeatedMessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline const $type$& $classname$::$name$(int index) const {\n"
- " return $name$_.Get(index);\n"
+ " return $name$_.$cppget$(index);\n"
"}\n"
"inline $type$* $classname$::mutable_$name$(int index) {\n"
" return $name$_.Mutable(index);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index f5147278..a5ed68a5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -46,7 +46,8 @@ namespace cpp {
class MessageFieldGenerator : public FieldGenerator {
public:
- explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+ explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~MessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -71,7 +72,8 @@ class MessageFieldGenerator : public FieldGenerator {
class RepeatedMessageFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedMessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
new file mode 100644
index 00000000..78770662
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: rennie@google.com (Jeffrey Rennie)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Generator options:
+struct Options {
+ Options() : safe_boundary_check(false) {
+ }
+ string dllexport_decl;
+ bool safe_boundary_check;
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 5e8df0f4..1c35fefa 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -80,8 +80,9 @@ int FixedSize(FieldDescriptor::Type type) {
}
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
@@ -99,9 +100,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// ===================================================================
PrimitiveFieldGenerator::
-PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetPrimitiveVariables(descriptor, &variables_);
+ SetPrimitiveVariables(descriptor, &variables_, options);
}
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
@@ -190,9 +192,10 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetPrimitiveVariables(descriptor, &variables_);
+ SetPrimitiveVariables(descriptor, &variables_, options);
if (descriptor->options().packed()) {
variables_["packed_reader"] = "ReadPackedPrimitive";
@@ -366,7 +369,9 @@ GenerateByteSize(io::Printer* printer) const {
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = data_size;\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 8fcd74ae..48249c40 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -46,7 +46,8 @@ namespace cpp {
class PrimitiveFieldGenerator : public FieldGenerator {
public:
- explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~PrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -71,7 +72,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedPrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index c2825683..d20018ea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -43,14 +43,14 @@ namespace compiler {
namespace cpp {
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor) {
vars_["classname"] = descriptor_->name();
vars_["full_name"] = descriptor_->full_name();
- if (dllexport_decl.empty()) {
+ if (options.dllexport_decl.empty()) {
vars_["dllexport"] = "";
} else {
- vars_["dllexport"] = dllexport_decl + " ";
+ vars_["dllexport"] = options.dllexport_decl + " ";
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h
index 10e9dd3c..820f9f5f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.h
+++ b/src/google/protobuf/compiler/cpp/cpp_service.h
@@ -38,6 +38,7 @@
#include <map>
#include <string>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
@@ -55,7 +56,7 @@ class ServiceGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ServiceGenerator(const ServiceDescriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~ServiceGenerator();
// Header stuff.
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 3cec2b6b..9c0911ac 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -46,11 +46,14 @@ namespace cpp {
namespace {
void SetStringVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["default"] = DefaultValue(descriptor);
+ (*variables)["default_length"] =
+ SimpleItoa(descriptor->default_value_string().length());
(*variables)["default_variable"] = descriptor->default_value_string().empty()
- ? "::google::protobuf::internal::kEmptyString"
+ ? "&::google::protobuf::internal::kEmptyString"
: "_default_" + FieldName(descriptor) + "_";
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
@@ -61,9 +64,10 @@ void SetStringVariables(const FieldDescriptor* descriptor,
// ===================================================================
StringFieldGenerator::
-StringFieldGenerator(const FieldDescriptor* descriptor)
+StringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetStringVariables(descriptor, &variables_);
+ SetStringVariables(descriptor, &variables_, options);
}
StringFieldGenerator::~StringFieldGenerator() {}
@@ -72,7 +76,7 @@ void StringFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_, "::std::string* $name$_;\n");
if (!descriptor_->default_value_string().empty()) {
- printer->Print(variables_, "static const ::std::string $default_variable$;\n");
+ printer->Print(variables_, "static ::std::string* $default_variable$;\n");
}
}
@@ -109,7 +113,9 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"inline void set_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
"inline ::std::string* mutable_$name$()$deprecation$;\n"
- "inline ::std::string* release_$name$()$deprecation$;\n");
+ "inline ::std::string* release_$name$()$deprecation$;\n"
+ "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+
if (descriptor_->options().ctype() != FieldOptions::STRING) {
printer->Outdent();
@@ -126,14 +132,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"}\n"
"inline void $classname$::set_$name$(const ::std::string& value) {\n"
" set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n"
+ " if ($name$_ == $default_variable$) {\n"
" $name$_ = new ::std::string;\n"
" }\n"
" $name$_->assign(value);\n"
"}\n"
"inline void $classname$::set_$name$(const char* value) {\n"
" set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n"
+ " if ($name$_ == $default_variable$) {\n"
" $name$_ = new ::std::string;\n"
" }\n"
" $name$_->assign(value);\n"
@@ -141,20 +147,20 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"inline "
"void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
" set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n"
+ " if ($name$_ == $default_variable$) {\n"
" $name$_ = new ::std::string;\n"
" }\n"
" $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
"}\n"
"inline ::std::string* $classname$::mutable_$name$() {\n"
" set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n");
+ " if ($name$_ == $default_variable$) {\n");
if (descriptor_->default_value_string().empty()) {
printer->Print(variables_,
" $name$_ = new ::std::string;\n");
} else {
printer->Print(variables_,
- " $name$_ = new ::std::string($default_variable$);\n");
+ " $name$_ = new ::std::string(*$default_variable$);\n");
}
printer->Print(variables_,
" }\n"
@@ -162,21 +168,34 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"}\n"
"inline ::std::string* $classname$::release_$name$() {\n"
" clear_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n"
+ " if ($name$_ == $default_variable$) {\n"
" return NULL;\n"
" } else {\n"
" ::std::string* temp = $name$_;\n"
- " $name$_ = const_cast< ::std::string*>(&$default_variable$);\n"
+ " $name$_ = const_cast< ::std::string*>($default_variable$);\n"
" return temp;\n"
" }\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if ($name$_ != $default_variable$) {\n"
+ " delete $name$_;\n"
+ " }\n"
+ " if ($name$) {\n"
+ " set_has_$name$();\n"
+ " $name$_ = $name$;\n"
+ " } else {\n"
+ " clear_has_$name$();\n"
+ " $name$_ = const_cast< ::std::string*>($default_variable$);\n"
+ " }\n"
"}\n");
}
void StringFieldGenerator::
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
if (!descriptor_->default_value_string().empty()) {
+ // Initialized in GenerateDefaultInstanceAllocator.
printer->Print(variables_,
- "const ::std::string $classname$::$default_variable$($default$);\n");
+ "::std::string* $classname$::$default_variable$ = NULL;\n");
}
}
@@ -184,13 +203,13 @@ void StringFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
if (descriptor_->default_value_string().empty()) {
printer->Print(variables_,
- "if ($name$_ != &$default_variable$) {\n"
+ "if ($name$_ != $default_variable$) {\n"
" $name$_->clear();\n"
"}\n");
} else {
printer->Print(variables_,
- "if ($name$_ != &$default_variable$) {\n"
- " $name$_->assign($default_variable$);\n"
+ "if ($name$_ != $default_variable$) {\n"
+ " $name$_->assign(*$default_variable$);\n"
"}\n");
}
}
@@ -208,18 +227,35 @@ GenerateSwappingCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_,
- "$name$_ = const_cast< ::std::string*>(&$default_variable$);\n");
+ "$name$_ = const_cast< ::std::string*>($default_variable$);\n");
}
void StringFieldGenerator::
GenerateDestructorCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($name$_ != &$default_variable$) {\n"
+ "if ($name$_ != $default_variable$) {\n"
" delete $name$_;\n"
"}\n");
}
void StringFieldGenerator::
+GenerateDefaultInstanceAllocator(io::Printer* printer) const {
+ if (!descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "$classname$::$default_variable$ =\n"
+ " new ::std::string($default$, $default_length$);\n");
+ }
+}
+
+void StringFieldGenerator::
+GenerateShutdownCode(io::Printer* printer) const {
+ if (!descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "delete $classname$::$default_variable$;\n");
+ }
+}
+
+void StringFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
@@ -273,9 +309,10 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
RepeatedStringFieldGenerator::
-RepeatedStringFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetStringVariables(descriptor, &variables_);
+ SetStringVariables(descriptor, &variables_, options);
}
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
@@ -328,7 +365,7 @@ void RepeatedStringFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::std::string& $classname$::$name$(int index) const {\n"
- " return $name$_.Get(index);\n"
+ " return $name$_.$cppget$(index);\n"
"}\n"
"inline ::std::string* $classname$::mutable_$name$(int index) {\n"
" return $name$_.Mutable(index);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 7f45107d..3264134a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -46,7 +46,8 @@ namespace cpp {
class StringFieldGenerator : public FieldGenerator {
public:
- explicit StringFieldGenerator(const FieldDescriptor* descriptor);
+ explicit StringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~StringFieldGenerator();
// implements FieldGenerator ---------------------------------------
@@ -59,6 +60,8 @@ class StringFieldGenerator : public FieldGenerator {
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
+ void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
+ void GenerateShutdownCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
@@ -73,7 +76,8 @@ class StringFieldGenerator : public FieldGenerator {
class RepeatedStringFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedStringFieldGenerator();
// implements FieldGenerator ---------------------------------------
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 54d830fc..e14a818c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -103,9 +103,19 @@ message TestConflictingSymbolNames {
message DO {}
optional DO do = 32;
+ // Some template parameter names for extensions.
+ optional int32 field_type = 33;
+ optional bool is_packed = 34;
+
extensions 1000 to max;
}
+message TestConflictingSymbolNamesExtension {
+ extend TestConflictingSymbolNames {
+ repeated int32 repeated_int32_ext = 20423638 [packed=true];
+ }
+}
+
message DummyMessage {}
service TestConflictingMethodNames {
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 301a7ce6..b5f9ab58 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -44,6 +44,8 @@
// correctly and produces the interfaces we expect, which is why this test
// is written this way.
+#include <google/protobuf/compiler/cpp/cpp_unittest.h>
+
#include <vector>
#include <google/protobuf/unittest.pb.h>
@@ -64,7 +66,7 @@
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -74,6 +76,8 @@ namespace cpp {
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
namespace cpp_unittest {
+namespace protobuf_unittest = ::protobuf_unittest;
+
class MockErrorCollector : public MultiFileErrorCollector {
public:
@@ -174,6 +178,15 @@ TEST(GeneratedMessageTest, Trigraph) {
EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph());
}
+TEST(GeneratedMessageTest, ExtremeSmallIntegerDefault) {
+ const unittest::TestExtremeDefaultValues& extreme_default =
+ unittest::TestExtremeDefaultValues::default_instance();
+ EXPECT_EQ(-0x80000000, kint32min);
+ EXPECT_EQ(GOOGLE_LONGLONG(-0x8000000000000000), kint64min);
+ EXPECT_EQ(kint32min, extreme_default.really_small_int32());
+ EXPECT_EQ(kint64min, extreme_default.really_small_int64());
+}
+
TEST(GeneratedMessageTest, Accessors) {
// Set every field to a unique value then go back and check all those
// values.
@@ -202,6 +215,13 @@ TEST(GeneratedMessageTest, MutableStringDefault) {
EXPECT_EQ("hello", *message.mutable_default_string());
}
+TEST(GeneratedMessageTest, StringDefaults) {
+ unittest::TestExtremeDefaultValues message;
+ // Check if '\000' can be used in default string value.
+ EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero());
+ EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero());
+}
+
TEST(GeneratedMessageTest, ReleaseString) {
// Check that release_foo() starts out NULL, and gives us a value
// that we can delete after it's been set.
@@ -244,6 +264,49 @@ TEST(GeneratedMessageTest, ReleaseMessage) {
EXPECT_FALSE(message.has_optional_nested_message());
}
+TEST(GeneratedMessageTest, SetAllocatedString) {
+ // Check that set_allocated_foo() works for strings.
+ unittest::TestAllTypes message;
+
+ EXPECT_FALSE(message.has_optional_string());
+ const string kHello("hello");
+ message.set_optional_string(kHello);
+ EXPECT_TRUE(message.has_optional_string());
+
+ message.set_allocated_optional_string(NULL);
+ EXPECT_FALSE(message.has_optional_string());
+ EXPECT_EQ("", message.optional_string());
+
+ message.set_allocated_optional_string(new string(kHello));
+ EXPECT_TRUE(message.has_optional_string());
+ EXPECT_EQ(kHello, message.optional_string());
+}
+
+TEST(GeneratedMessageTest, SetAllocatedMessage) {
+ // Check that set_allocated_foo() can be called in all cases.
+ unittest::TestAllTypes message;
+
+ EXPECT_FALSE(message.has_optional_nested_message());
+
+ message.mutable_optional_nested_message()->set_bb(1);
+ EXPECT_TRUE(message.has_optional_nested_message());
+
+ message.set_allocated_optional_nested_message(NULL);
+ EXPECT_FALSE(message.has_optional_nested_message());
+ EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
+ &message.optional_nested_message());
+
+ message.mutable_optional_nested_message()->set_bb(1);
+ unittest::TestAllTypes::NestedMessage* nest =
+ message.release_optional_nested_message();
+ ASSERT_TRUE(nest != NULL);
+ EXPECT_FALSE(message.has_optional_nested_message());
+
+ message.set_allocated_optional_nested_message(nest);
+ EXPECT_TRUE(message.has_optional_nested_message());
+ EXPECT_EQ(1, message.optional_nested_message().bb());
+}
+
TEST(GeneratedMessageTest, Clear) {
// Set every field to a unique value, clear the message, then check that
// it is cleared.
@@ -695,6 +758,13 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) {
message.set_friend_(5);
EXPECT_EQ(5, message.friend_());
+
+ // Instantiate extension template functions to test conflicting template
+ // parameter names.
+ typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
+ message.AddExtension(ExtensionMessage::repeated_int32_ext, 123);
+ EXPECT_EQ(123,
+ message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
}
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
@@ -869,11 +939,10 @@ TEST(GeneratedEnumTest, MinAndMax) {
EXPECT_NE(null_pointer, &unittest::ForeignEnum_MAX);
EXPECT_NE(null_pointer, &unittest::ForeignEnum_ARRAYSIZE);
- // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases.
+ // Make sure we can use _MIN and _MAX as switch cases.
switch (unittest::SPARSE_A) {
case unittest::TestSparseEnum_MIN:
case unittest::TestSparseEnum_MAX:
- case unittest::TestSparseEnum_ARRAYSIZE:
break;
default:
break;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.h b/src/google/protobuf/compiler/cpp/cpp_unittest.h
new file mode 100644
index 00000000..a3a1d1ba
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.h
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This header declares the namespace google::protobuf::protobuf_unittest in order to expose
+// any problems with the generated class names. We use this header to ensure
+// unittest.cc will declare the namespace prior to other includes, while obeying
+// normal include ordering.
+//
+// When generating a class name of "foo.Bar" we must ensure we prefix the class
+// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
+// trigger that case here by declaring google::protobuf::protobuf_unittest.
+//
+// See ClassName in helpers.h for more details.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+
+namespace google {
+namespace protobuf {
+namespace protobuf_unittest {}
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index 7a2efc29..7a62fa0e 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -280,8 +280,9 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
string virtual_path;
string disk_path;
- inline Mapping(const string& virtual_path, const string& disk_path)
- : virtual_path(virtual_path), disk_path(disk_path) {}
+ inline Mapping(const string& virtual_path_param,
+ const string& disk_path_param)
+ : virtual_path(virtual_path_param), disk_path(disk_path_param) {}
};
vector<Mapping> mappings_;
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc
new file mode 100644
index 00000000..60b4f2ac
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_doc_comment.cc
@@ -0,0 +1,236 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+
+#include <vector>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+string EscapeJavadoc(const string& input) {
+ string result;
+ result.reserve(input.size() * 2);
+
+ char prev = '*';
+
+ for (string::size_type i = 0; i < input.size(); i++) {
+ char c = input[i];
+ switch (c) {
+ case '*':
+ // Avoid "/*".
+ if (prev == '/') {
+ result.append("&#42;");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '/':
+ // Avoid "*/".
+ if (prev == '*') {
+ result.append("&#47;");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '@':
+ // "{@" starts Javadoc markup.
+ if (prev == '{') {
+ result.append("&#64;");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '<':
+ // Avoid interpretation as HTML.
+ result.append("&lt;");
+ break;
+ case '>':
+ // Avoid interpretation as HTML.
+ result.append("&gt;");
+ break;
+ case '&':
+ // Avoid interpretation as HTML.
+ result.append("&amp;");
+ break;
+ case '\\':
+ // Java interprets Unicode escape sequences anywhere!
+ result.append("&#92;");
+ break;
+ default:
+ result.push_back(c);
+ break;
+ }
+
+ prev = c;
+ }
+
+ return result;
+}
+
+static void WriteDocCommentBodyForLocation(
+ io::Printer* printer, const SourceLocation& location) {
+ string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (!comments.empty()) {
+ // TODO(kenton): Ideally we should parse the comment text as Markdown and
+ // write it back as HTML, but this requires a Markdown parser. For now
+ // we just use <pre> to get fixed-width text formatting.
+
+ // If the comment itself contains block comment start or end markers,
+ // HTML-escape them so that they don't accidentally close the doc comment.
+ comments = EscapeJavadoc(comments);
+
+ vector<string> lines;
+ SplitStringAllowEmpty(comments, "\n", &lines);
+ while (!lines.empty() && lines.back().empty()) {
+ lines.pop_back();
+ }
+
+ printer->Print(
+ " *\n"
+ " * <pre>\n");
+ for (int i = 0; i < lines.size(); i++) {
+ // Most lines should start with a space. Watch out for lines that start
+ // with a /, since putting that right after the leading asterisk will
+ // close the comment.
+ if (!lines[i].empty() && lines[i][0] == '/') {
+ printer->Print(" * $line$\n", "line", lines[i]);
+ } else {
+ printer->Print(" *$line$\n", "line", lines[i]);
+ }
+ }
+ printer->Print(" * </pre>\n");
+ }
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(
+ io::Printer* printer, const DescriptorType* descriptor) {
+ SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ WriteDocCommentBodyForLocation(printer, location);
+ }
+}
+
+static string FirstLineOf(const string& value) {
+ string result = value;
+
+ string::size_type pos = result.find_first_of('\n');
+ if (pos != string::npos) {
+ result.erase(pos);
+ }
+
+ // If line ends in an opening brace, make it "{ ... }" so it looks nice.
+ if (!result.empty() && result[result.size() - 1] == '{') {
+ result.append(" ... }");
+ }
+
+ return result;
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf type {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(message->full_name()));
+ WriteDocCommentBody(printer, message);
+ printer->Print(" */\n");
+}
+
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
+ // In theory we should have slightly different comments for setters, getters,
+ // etc., but in practice everyone already knows the difference between these
+ // so it's redundant information.
+
+ // We use the field declaration as the first line of the comment, e.g.:
+ // optional string foo = 5;
+ // This communicates a lot of information about the field in a small space.
+ // If the field is a group, the debug string might end with {.
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(field->DebugString())));
+ WriteDocCommentBody(printer, field);
+ printer->Print(" */\n");
+}
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf enum {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(enum_->full_name()));
+ WriteDocCommentBody(printer, enum_);
+ printer->Print(" */\n");
+}
+
+void WriteEnumValueDocComment(io::Printer* printer,
+ const EnumValueDescriptor* value) {
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(value->DebugString())));
+ WriteDocCommentBody(printer, value);
+ printer->Print(" */\n");
+}
+
+void WriteServiceDocComment(io::Printer* printer,
+ const ServiceDescriptor* service) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf service {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(service->full_name()));
+ WriteDocCommentBody(printer, service);
+ printer->Print(" */\n");
+}
+
+void WriteMethodDocComment(io::Printer* printer,
+ const MethodDescriptor* method) {
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(method->DebugString())));
+ WriteDocCommentBody(printer, method);
+ printer->Print(" */\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.h b/src/google/protobuf/compiler/java/java_doc_comment.h
new file mode 100644
index 00000000..f77720b6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_doc_comment.h
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field);
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_);
+void WriteEnumValueDocComment(io::Printer* printer,
+ const EnumValueDescriptor* value);
+void WriteServiceDocComment(io::Printer* printer,
+ const ServiceDescriptor* service);
+void WriteMethodDocComment(io::Printer* printer,
+ const MethodDescriptor* method);
+
+// Exposed for testing only.
+string EscapeJavadoc(const string& input);
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
new file mode 100644
index 00000000..28b6d8b4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
@@ -0,0 +1,66 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+namespace {
+
+TEST(JavaDocCommentTest, Escaping) {
+ EXPECT_EQ("foo /&#42; bar *&#47; baz", EscapeJavadoc("foo /* bar */ baz"));
+ EXPECT_EQ("foo /&#42;&#47; baz", EscapeJavadoc("foo /*/ baz"));
+ EXPECT_EQ("{&#64;foo}", EscapeJavadoc("{@foo}"));
+ EXPECT_EQ("&lt;i&gt;&amp;&lt;/i&gt;", EscapeJavadoc("<i>&</i>"));
+ EXPECT_EQ("foo&#92;u1234bar", EscapeJavadoc("foo\\u1234bar"));
+}
+
+// TODO(kenton): It's hard to write a robust test of the doc comments -- we
+// can only really compare the output against a golden value, which is a
+// fairly tedious and fragile testing strategy. If we want to go that route,
+// it probably makes sense to bite the bullet and write a test that compares
+// the whole generated output for unittest.proto against a golden value, with
+// a very simple script that can be run to regenerate it with the latest code.
+// This would mean that updates to the golden file would have to be included
+// in any change to the code generator, which would actually be fairly useful
+// as it allows the reviewer to see clearly how the generated code is
+// changing.
+
+} // namespace
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 9d7bcab6..cfed815f 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -36,6 +36,7 @@
#include <string>
#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
@@ -67,6 +68,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
EnumGenerator::~EnumGenerator() {}
void EnumGenerator::Generate(io::Printer* printer) {
+ WriteEnumDocComment(printer, descriptor_);
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public enum $classname$\n"
@@ -85,6 +87,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
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]);
printer->Print(vars,
"$name$($index$, $number$),\n");
}
@@ -100,6 +103,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
vars["classname"] = descriptor_->name();
vars["name"] = aliases_[i].value->name();
vars["canonical_name"] = aliases_[i].canonical_value->name();
+ WriteEnumValueDocComment(printer, aliases_[i].value);
printer->Print(vars,
"public static final $classname$ $name$ = $canonical_name$;\n");
}
@@ -108,6 +112,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
map<string, string> vars;
vars["name"] = descriptor_->value(i)->name();
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+ WriteEnumValueDocComment(printer, descriptor_->value(i));
printer->Print(vars,
"public static final int $name$_VALUE = $number$;\n");
}
@@ -187,19 +192,30 @@ void EnumGenerator::Generate(io::Printer* printer) {
printer->Print(
"}\n"
"\n"
- "private static final $classname$[] VALUES = {\n"
- " ",
+ "private static final $classname$[] VALUES = ",
"classname", descriptor_->name());
- for (int i = 0; i < descriptor_->value_count(); i++) {
- printer->Print("$name$, ",
- "name", descriptor_->value(i)->name());
+ if (CanUseEnumValues()) {
+ // If the constants we are going to output are exactly the ones we
+ // have declared in the Java enum in the same order, then we can use
+ // the values() method that the Java compiler automatically generates
+ // for every enum.
+ printer->Print("values();\n");
+ } else {
+ printer->Print(
+ "{\n"
+ " ");
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ printer->Print("$name$, ",
+ "name", descriptor_->value(i)->name());
+ }
+ printer->Print(
+ "\n"
+ "};\n");
}
printer->Print(
"\n"
- "};\n"
- "\n"
"public static $classname$ valueOf(\n"
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
" if (desc.getType() != getDescriptor()) {\n"
@@ -237,6 +253,18 @@ void EnumGenerator::Generate(io::Printer* printer) {
printer->Print("}\n\n");
}
+bool EnumGenerator::CanUseEnumValues() {
+ if (canonical_values_.size() != descriptor_->value_count()) {
+ return false;
+ }
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ if (descriptor_->value(i)->name() != canonical_values_[i]->name()) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h
index 05ece1f1..9a9e5742 100644
--- a/src/google/protobuf/compiler/java/java_enum.h
+++ b/src/google/protobuf/compiler/java/java_enum.h
@@ -73,6 +73,8 @@ class EnumGenerator {
};
vector<Alias> aliases_;
+ bool CanUseEnumValues();
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 72caa10b..ec0b067e 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -36,6 +36,7 @@
#include <string>
#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
@@ -75,6 +76,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
@@ -86,6 +88,13 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // For repeated fields, one bit is used for whether the array is immutable
+ // in the parsing constructor.
+ (*variables)["get_mutable_bit_parser"] =
+ GenerateGetBitMutableLocal(builderBitIndex);
+ (*variables)["set_mutable_bit_parser"] =
+ GenerateSetBitMutableLocal(builderBitIndex);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -117,18 +126,25 @@ int EnumFieldGenerator::GetNumBitsForBuilder() const {
void EnumFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
}
void EnumFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_;\n"
+ "private $type$ $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_message$;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n");
@@ -137,13 +153,19 @@ GenerateMembers(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_ = $default$;\n"
+ "private $type$ $name$_ = $default$;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_builder$;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
" if (value == null) {\n"
" throw new NullPointerException();\n"
@@ -152,7 +174,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_ = value;\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $clear_has_field_bit_builder$;\n"
" $name$_ = $default$;\n"
@@ -210,12 +234,17 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value != null) {\n");
}
printer->Print(variables_,
- " $set_has_field_bit_builder$;\n"
+ " $set_has_field_bit_message$;\n"
" $name$_ = value;\n"
"}\n");
}
void EnumFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for enums
+}
+
+void EnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
"if ($get_has_field_bit_message$) {\n"
@@ -273,22 +302,33 @@ int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const {
void RepeatedEnumFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
"$deprecation$$type$ get$capitalized_name$(int index);\n");
}
void RepeatedEnumFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.util.List<$type$> $name$_;\n"
+ "private java.util.List<$type$> $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
@@ -320,21 +360,29 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
" $set_mutable_bit_builder$;\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value) {\n"
" if (value == null) {\n"
@@ -344,7 +392,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.set(index, value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
" if (value == null) {\n"
" throw new NullPointerException();\n"
@@ -353,14 +403,18 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.add(value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" super.addAll(values, $name$_);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = java.util.Collections.emptyList();\n"
" $clear_mutable_bit_builder$;\n"
@@ -434,7 +488,11 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value != null) {\n");
}
printer->Print(variables_,
- " add$capitalized_name$(value);\n"
+ " if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<$type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ " }\n"
+ " $name$_.add(value);\n"
"}\n");
}
@@ -457,6 +515,14 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const {
}
void RepeatedEnumFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 0cad6be0..90fae639 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -61,6 +61,7 @@ class EnumFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
@@ -96,6 +97,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
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;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 9b147c77..921fe658 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -33,6 +33,7 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
@@ -130,6 +131,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
printer->Print(vars,
"public static final int $constant_name$ = $number$;\n");
+ WriteFieldDocComment(printer, descriptor_);
if (HasDescriptorMethods(descriptor_->file())) {
// Non-lite extensions
if (descriptor_->extension_scope() == NULL) {
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index 6097f357..4dd0efd6 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -66,6 +66,7 @@ class FieldGenerator {
virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
virtual void GenerateParsingCode(io::Printer* printer) const = 0;
virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+ virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0;
virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 8968069f..f43e5500 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/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -51,18 +52,24 @@ namespace java {
namespace {
-// Recursively searches the given message to see if it contains any extensions.
-bool UsesExtensions(const Message& message) {
+
+// Recursively searches the given message to collect extensions.
+// Returns true if all the extensions can be recognized. The extensions will be
+// appended in to the extensions parameter.
+// Returns false when there are unknown fields, in which case the data in the
+// extensions output parameter is not reliable and should be discarded.
+bool CollectExtensions(const Message& message,
+ vector<const FieldDescriptor*>* extensions) {
const Reflection* reflection = message.GetReflection();
- // We conservatively assume that unknown fields are extensions.
- if (reflection->GetUnknownFields(message).field_count() > 0) return true;
+ // There are unknown fields that could be extensions, thus this call fails.
+ if (reflection->GetUnknownFields(message).field_count() > 0) return false;
vector<const FieldDescriptor*> fields;
reflection->ListFields(message, &fields);
for (int i = 0; i < fields.size(); i++) {
- if (fields[i]->is_extension()) return true;
+ if (fields[i]->is_extension()) extensions->push_back(fields[i]);
if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
if (fields[i]->is_repeated()) {
@@ -70,16 +77,56 @@ bool UsesExtensions(const Message& message) {
for (int j = 0; j < size; j++) {
const Message& sub_message =
reflection->GetRepeatedMessage(message, fields[i], j);
- if (UsesExtensions(sub_message)) return true;
+ if (!CollectExtensions(sub_message, extensions)) return false;
}
} else {
const Message& sub_message = reflection->GetMessage(message, fields[i]);
- if (UsesExtensions(sub_message)) return true;
+ if (!CollectExtensions(sub_message, extensions)) return false;
}
}
}
- return false;
+ return true;
+}
+
+// Finds all extensions in the given message and its sub-messages. If the
+// message contains unknown fields (which could be extensions), then those
+// extensions are defined in alternate_pool.
+// The message will be converted to a DynamicMessage backed by alternate_pool
+// in order to handle this case.
+void CollectExtensions(const FileDescriptorProto& file_proto,
+ const DescriptorPool& alternate_pool,
+ vector<const FieldDescriptor*>* extensions,
+ const string& file_data) {
+ if (!CollectExtensions(file_proto, extensions)) {
+ // There are unknown fields in the file_proto, which are probably
+ // extensions. We need to parse the data into a dynamic message based on the
+ // builder-pool to find out all extensions.
+ const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
+ file_proto.GetDescriptor()->full_name());
+ GOOGLE_CHECK(file_proto_desc)
+ << "Find unknown fields in FileDescriptorProto when building "
+ << file_proto.name()
+ << ". It's likely that those fields are custom options, however, "
+ "descriptor.proto is not in the transitive dependencies. "
+ "This normally should not happen. Please report a bug.";
+ DynamicMessageFactory factory;
+ scoped_ptr<Message> dynamic_file_proto(
+ factory.GetPrototype(file_proto_desc)->New());
+ GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
+ GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
+
+ // Collect the extensions again from the dynamic message. There should be no
+ // more unknown fields this time, i.e. all the custom options should be
+ // parsed as extensions now.
+ extensions->clear();
+ GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
+ << "Find unknown fields in FileDescriptorProto when building "
+ << file_proto.name()
+ << ". It's likely that those fields are custom options, however, "
+ "those options cannot be recognized in the builder pool. "
+ "This normally should not happen. Please report a bug.";
+ }
}
@@ -306,19 +353,32 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
.GenerateNonNestedInitializationCode(printer);
}
- if (UsesExtensions(file_proto)) {
- // Must construct an ExtensionRegistry containing all possible extensions
+ // Proto compiler builds a DescriptorPool, which holds all the descriptors to
+ // generate, when processing the ".proto" files. We call this DescriptorPool
+ // the parsed pool (a.k.a. file_->pool()).
+ //
+ // Note that when users try to extend the (.*)DescriptorProto in their
+ // ".proto" files, it does not affect the pre-built FileDescriptorProto class
+ // in proto compiler. When we put the descriptor data in the file_proto, those
+ // extensions become unknown fields.
+ //
+ // Now we need to find out all the extension value to the (.*)DescriptorProto
+ // in the file_proto message, and prepare an ExtensionRegistry to return.
+ //
+ // To find those extensions, we need to parse the data into a dynamic message
+ // of the FileDescriptor based on the builder-pool, then we can use
+ // reflections to find all extension fields
+ vector<const FieldDescriptor*> extensions;
+ CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
+
+ if (extensions.size() > 0) {
+ // Must construct an ExtensionRegistry containing all existing extensions
// and return it.
printer->Print(
"com.google.protobuf.ExtensionRegistry registry =\n"
- " com.google.protobuf.ExtensionRegistry.newInstance();\n"
- "registerAllExtensions(registry);\n");
- for (int i = 0; i < file_->dependency_count(); i++) {
- if (ShouldIncludeDependency(file_->dependency(i))) {
- printer->Print(
- "$dependency$.registerAllExtensions(registry);\n",
- "dependency", ClassName(file_->dependency(i)));
- }
+ " com.google.protobuf.ExtensionRegistry.newInstance();\n");
+ for (int i = 0; i < extensions.size(); i++) {
+ ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer);
}
printer->Print(
"return registry;\n");
@@ -375,7 +435,9 @@ static void GenerateSibling(const string& package_dir,
printer.Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "\n");
+ "// source: $filename$\n"
+ "\n",
+ "filename", descriptor->file()->name());
if (!java_package.empty()) {
printer.Print(
"package $package$;\n"
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 1b6f1653..cf241b8a 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -177,6 +177,18 @@ string ToJavaName(const string& full_name, const FileDescriptor* file) {
return result;
}
+string ClassName(const Descriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+
+string ClassName(const EnumDescriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+
+string ClassName(const ServiceDescriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+
string ClassName(const FileDescriptor* descriptor) {
string result = FileJavaPackage(descriptor);
if (!result.empty()) result += '.';
@@ -326,14 +338,14 @@ string DefaultValue(const FieldDescriptor* field) {
} else {
// See comments in Internal.java for gory details.
return strings::Substitute(
- "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
- CEscape(field->default_value_string()));
+ "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
+ CEscape(field->default_value_string()));
}
}
case FieldDescriptor::CPPTYPE_ENUM:
return ClassName(field->enum_type()) + "." +
- field->default_value_enum()->name();
+ field->default_value_enum()->name();
case FieldDescriptor::CPPTYPE_MESSAGE:
return ClassName(field->message_type()) + ".getDefaultInstance()";
@@ -427,8 +439,10 @@ string GetBitFieldNameForBit(int bitIndex) {
return GetBitFieldName(bitIndex / 32);
}
-string GenerateGetBit(int bitIndex) {
- string varName = GetBitFieldNameForBit(bitIndex);
+namespace {
+
+string GenerateGetBitInternal(const string& prefix, int bitIndex) {
+ string varName = prefix + GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
string mask = bit_masks[bitInVarIndex];
@@ -436,8 +450,8 @@ string GenerateGetBit(int bitIndex) {
return result;
}
-string GenerateSetBit(int bitIndex) {
- string varName = GetBitFieldNameForBit(bitIndex);
+string GenerateSetBitInternal(const string& prefix, int bitIndex) {
+ string varName = prefix + GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
string mask = bit_masks[bitInVarIndex];
@@ -445,6 +459,16 @@ string GenerateSetBit(int bitIndex) {
return result;
}
+} // namespace
+
+string GenerateGetBit(int bitIndex) {
+ return GenerateGetBitInternal("", bitIndex);
+}
+
+string GenerateSetBit(int bitIndex) {
+ return GenerateSetBitInternal("", bitIndex);
+}
+
string GenerateClearBit(int bitIndex) {
string varName = GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
@@ -455,21 +479,19 @@ string GenerateClearBit(int bitIndex) {
}
string GenerateGetBitFromLocal(int bitIndex) {
- string varName = "from_" + GetBitFieldNameForBit(bitIndex);
- int bitInVarIndex = bitIndex % 32;
-
- string mask = bit_masks[bitInVarIndex];
- string result = "((" + varName + " & " + mask + ") == " + mask + ")";
- return result;
+ return GenerateGetBitInternal("from_", bitIndex);
}
string GenerateSetBitToLocal(int bitIndex) {
- string varName = "to_" + GetBitFieldNameForBit(bitIndex);
- int bitInVarIndex = bitIndex % 32;
+ return GenerateSetBitInternal("to_", bitIndex);
+}
- string mask = bit_masks[bitInVarIndex];
- string result = varName + " |= " + mask;
- return result;
+string GenerateGetBitMutableLocal(int bitIndex) {
+ return GenerateGetBitInternal("mutable_", bitIndex);
+}
+
+string GenerateSetBitMutableLocal(int bitIndex) {
+ return GenerateSetBitInternal("mutable_", bitIndex);
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 4ae07f15..3937f069 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -78,19 +78,14 @@ string ToJavaName(const string& full_name, const FileDescriptor* file);
// These return the fully-qualified class name corresponding to the given
// descriptor.
-inline string ClassName(const Descriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
-}
-inline string ClassName(const EnumDescriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
-}
-inline string ClassName(const ServiceDescriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
-}
+string ClassName(const Descriptor* descriptor);
+string ClassName(const EnumDescriptor* descriptor);
+string ClassName(const ServiceDescriptor* descriptor);
+string ClassName(const FileDescriptor* descriptor);
+
inline string ExtensionIdentifierName(const FieldDescriptor* descriptor) {
return ToJavaName(descriptor->full_name(), descriptor->file());
}
-string ClassName(const FileDescriptor* descriptor);
// Get the unqualified name that should be used for a field's field
// number constant.
@@ -205,6 +200,18 @@ string GenerateGetBitFromLocal(int bitIndex);
// Example: "to_bitField1_ = (to_bitField1_ | 0x04)"
string GenerateSetBitToLocal(int bitIndex);
+// Does the same as GenerateGetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "((mutable_bitField1_ & 0x04) == 0x04)"
+string GenerateGetBitMutableLocal(int bitIndex);
+
+// Does the same as GenerateSetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)"
+string GenerateSetBitMutableLocal(int bitIndex);
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 4c087db5..9322e242 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -32,17 +32,23 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/java/java_message.h>
+
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
-#include <google/protobuf/compiler/java/java_message.h>
+#include <map>
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_enum.h>
#include <google/protobuf/compiler/java/java_extension.h>
#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
namespace google {
namespace protobuf {
@@ -233,10 +239,8 @@ void MessageGenerator::GenerateStaticVariableInitializers(
"field_name",
UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
}
- printer->Print("},\n"
- " $classname$.class,\n"
- " $classname$.Builder.class);\n",
- "classname", ClassName(descriptor_));
+ printer->Print(
+ "});\n");
}
// Generate static member initializers for all nested types.
@@ -250,7 +254,6 @@ void MessageGenerator::GenerateStaticVariableInitializers(
// ===================================================================
void MessageGenerator::GenerateInterface(io::Printer* printer) {
-
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
@@ -298,6 +301,10 @@ void MessageGenerator::Generate(io::Printer* printer) {
descriptor_->containing_type() == NULL &&
descriptor_->file()->options().java_multiple_files();
+ WriteMessageDocComment(printer, descriptor_);
+
+ // The builder_type stores the super type name of the nested Builder class.
+ string builder_type;
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
@@ -306,6 +313,9 @@ void MessageGenerator::Generate(io::Printer* printer) {
" $classname$> implements $classname$OrBuilder {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
+ builder_type = strings::Substitute(
+ "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
+ ClassName(descriptor_));
} else {
printer->Print(
"public $static$ final class $classname$ extends\n"
@@ -313,6 +323,9 @@ void MessageGenerator::Generate(io::Printer* printer) {
" $classname$> implements $classname$OrBuilder {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
+ builder_type = strings::Substitute(
+ "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>",
+ ClassName(descriptor_));
}
} else {
if (HasDescriptorMethods(descriptor_)) {
@@ -322,6 +335,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
" implements $classname$OrBuilder {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
+ builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>";
} else {
printer->Print(
"public $static$ final class $classname$ extends\n"
@@ -329,17 +343,28 @@ void MessageGenerator::Generate(io::Printer* printer) {
" implements $classname$OrBuilder {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
+ builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
}
}
printer->Indent();
+ // Using builder_type, instead of Builder, prevents the Builder class from
+ // being loaded into PermGen space when the default instance is created.
+ // This optimizes the PermGen space usage for clients that do not modify
+ // messages.
printer->Print(
"// Use $classname$.newBuilder() to construct.\n"
- "private $classname$(Builder builder) {\n"
+ "private $classname$($buildertype$ builder) {\n"
" super(builder);\n"
- "}\n"
+ "$set_unknown_fields$\n"
+ "}\n",
+ "classname", descriptor_->name(),
+ "buildertype", builder_type,
+ "set_unknown_fields", HasUnknownFields(descriptor_)
+ ? " this.unknownFields = builder.getUnknownFields();" : "");
+ printer->Print(
// Used when constructing the default instance, which cannot be initialized
// immediately because it may cyclically refer to other default instances.
- "private $classname$(boolean noInit) {}\n"
+ "private $classname$(boolean noInit) {$set_default_unknown_fields$}\n"
"\n"
"private static final $classname$ defaultInstance;\n"
"public static $classname$ getDefaultInstance() {\n"
@@ -350,9 +375,28 @@ void MessageGenerator::Generate(io::Printer* printer) {
" return defaultInstance;\n"
"}\n"
"\n",
- "classname", descriptor_->name());
+ "classname", descriptor_->name(),
+ "set_default_unknown_fields", HasUnknownFields(descriptor_)
+ ? " this.unknownFields ="
+ " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " : "");
+
+ if (HasUnknownFields(descriptor_)) {
+ printer->Print(
+ "private final com.google.protobuf.UnknownFieldSet unknownFields;\n"
+ ""
+ "@java.lang.Override\n"
+ "public final com.google.protobuf.UnknownFieldSet\n"
+ " getUnknownFields() {\n"
+ " return this.unknownFields;\n"
+ "}\n");
+ }
+
+ if (HasGeneratedMethods(descriptor_)) {
+ GenerateParsingConstructor(printer);
+ }
GenerateDescriptorMethods(printer);
+ GenerateParser(printer);
// Nested types
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -567,68 +611,54 @@ GenerateParseFromMethods(io::Printer* printer) {
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data).buildParsed();\n"
+ " return PARSER.parseFrom(data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(byte[] data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data).buildParsed();\n"
+ " return PARSER.parseFrom(data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" byte[] data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input).buildParsed();\n"
+ " return PARSER.parseFrom(input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " Builder builder = newBuilder();\n"
- " if (builder.mergeDelimitedFrom(input)) {\n"
- " return builder.buildParsed();\n"
- " } else {\n"
- " return null;\n"
- " }\n"
+ " return PARSER.parseDelimitedFrom(input);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " Builder builder = newBuilder();\n"
- " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n"
- " return builder.buildParsed();\n"
- " } else {\n"
- " return null;\n"
- " }\n"
+ " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input).buildParsed();\n"
+ " return PARSER.parseFrom(input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(input, extensionRegistry);\n"
"}\n"
"\n",
"classname", ClassName(descriptor_));
@@ -669,6 +699,8 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
"}\n");
}
+ WriteMessageDocComment(printer, descriptor_);
+
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
@@ -739,17 +771,25 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_)) {
+ if (!descriptor_->options().no_standard_descriptor_accessor()) {
+ printer->Print(
+ "public static final com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptor() {\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
+ "}\n"
+ "\n",
+ "fileclass", ClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+ }
printer->Print(
- "public static final com.google.protobuf.Descriptors.Descriptor\n"
- " getDescriptor() {\n"
- " return $fileclass$.internal_$identifier$_descriptor;\n"
- "}\n"
- "\n"
"protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internalGetFieldAccessorTable() {\n"
- " return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
+ " return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+ " .ensureFieldAccessorsInitialized(\n"
+ " $classname$.class, $classname$.Builder.class);\n"
"}\n"
"\n",
+ "classname", ClassName(descriptor_),
"fileclass", ClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
}
@@ -768,7 +808,8 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
- "private Builder(BuilderParent parent) {\n"
+ "private Builder(\n"
+ " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
" super(parent);\n"
" maybeForceBuilderInitialization();\n"
"}\n",
@@ -830,10 +871,11 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Print(
"public com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptorForType() {\n"
- " return $classname$.getDescriptor();\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
"}\n"
"\n",
- "classname", ClassName(descriptor_));
+ "fileclass", ClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
}
printer->Print(
"public $classname$ getDefaultInstanceForType() {\n"
@@ -853,16 +895,6 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" return result;\n"
"}\n"
"\n"
- "private $classname$ buildParsed()\n"
- " throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " $classname$ result = buildPartial();\n"
- " if (!result.isInitialized()) {\n"
- " throw newUninitializedMessageException(\n"
- " result).asInvalidProtocolBufferException();\n"
- " }\n"
- " return result;\n"
- "}\n"
- "\n"
"public $classname$ buildPartial() {\n"
" $classname$ result = new $classname$(this);\n",
"classname", ClassName(descriptor_));
@@ -969,108 +1001,25 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
// ===================================================================
void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
- scoped_array<const FieldDescriptor*> sorted_fields(
- SortFieldsByNumber(descriptor_));
-
printer->Print(
"public Builder mergeFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
- " throws java.io.IOException {\n");
- printer->Indent();
-
- if (HasUnknownFields(descriptor_)) {
- printer->Print(
- "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
- " com.google.protobuf.UnknownFieldSet.newBuilder(\n"
- " this.getUnknownFields());\n");
- }
-
- printer->Print(
- "while (true) {\n");
- printer->Indent();
-
- printer->Print(
- "int tag = input.readTag();\n"
- "switch (tag) {\n");
- printer->Indent();
-
- if (HasUnknownFields(descriptor_)) {
- printer->Print(
- "case 0:\n" // zero signals EOF / limit reached
- " this.setUnknownFields(unknownFields.build());\n"
- " $on_changed$\n"
- " return this;\n"
- "default: {\n"
- " if (!parseUnknownField(input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
- " this.setUnknownFields(unknownFields.build());\n"
- " $on_changed$\n"
- " return this;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
- "}\n",
- "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
- } else {
- printer->Print(
- "case 0:\n" // zero signals EOF / limit reached
- " $on_changed$\n"
- " return this;\n"
- "default: {\n"
- " if (!parseUnknownField(input, extensionRegistry, tag)) {\n"
- " $on_changed$\n"
- " return this;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
- "}\n",
- "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
- }
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldDescriptor* field = sorted_fields[i];
- uint32 tag = WireFormatLite::MakeTag(field->number(),
- WireFormat::WireTypeForFieldType(field->type()));
-
- printer->Print(
- "case $tag$: {\n",
- "tag", SimpleItoa(tag));
- printer->Indent();
-
- field_generators_.get(field).GenerateParsingCode(printer);
-
- printer->Outdent();
- printer->Print(
- " break;\n"
- "}\n");
-
- if (field->is_packable()) {
- // To make packed = true wire compatible, we generate parsing code from a
- // packed version of this field regardless of field->options().packed().
- uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
- printer->Print(
- "case $tag$: {\n",
- "tag", SimpleItoa(packed_tag));
- printer->Indent();
-
- field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
-
- printer->Outdent();
- printer->Print(
- " break;\n"
- "}\n");
- }
- }
-
- printer->Outdent();
- printer->Outdent();
- printer->Outdent();
- printer->Print(
- " }\n" // switch (tag)
- " }\n" // while (true)
- "}\n"
-
- "\n");
+ " throws java.io.IOException {\n"
+ " $classname$ parsedMessage = null;\n"
+ " try {\n"
+ " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
+ " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+ " parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
+ " throw e;\n"
+ " } finally {\n"
+ " if (parsedMessage != null) {\n"
+ " mergeFrom(parsedMessage);\n"
+ " }\n"
+ " }\n"
+ " return this;\n"
+ "}\n",
+ "classname", ClassName(descriptor_));
}
// ===================================================================
@@ -1232,10 +1181,19 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
"\n");
printer->Print(
+ "private int memoizedHashCode = 0;\n");
+ printer->Print(
"@java.lang.Override\n"
"public int hashCode() {\n");
printer->Indent();
printer->Print(
+ "if (memoizedHashCode != 0) {\n");
+ printer->Indent();
+ printer->Print(
+ "return memoizedHashCode;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n"
"int hash = 41;\n"
"hash = (19 * hash) + getDescriptorForType().hashCode();\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1260,6 +1218,7 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
}
printer->Print(
"hash = (29 * hash) + getUnknownFields().hashCode();\n"
+ "memoizedHashCode = hash;\n"
"return hash;\n");
printer->Outdent();
printer->Print(
@@ -1281,6 +1240,195 @@ void MessageGenerator::GenerateExtensionRegistrationCode(io::Printer* printer) {
}
}
+// ===================================================================
+void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "private $classname$(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Initialize all fields to default.
+ printer->Print(
+ "initFields();\n");
+
+ // Use builder bits to track mutable repeated fields.
+ int totalBuilderBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldGenerator& field = field_generators_.get(descriptor_->field(i));
+ totalBuilderBits += field.GetNumBitsForBuilder();
+ }
+ int totalBuilderInts = (totalBuilderBits + 31) / 32;
+ for (int i = 0; i < totalBuilderInts; i++) {
+ printer->Print("int mutable_$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+
+ if (HasUnknownFields(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+ " com.google.protobuf.UnknownFieldSet.newBuilder();\n");
+ }
+
+ printer->Print(
+ "try {\n");
+ printer->Indent();
+
+ printer->Print(
+ "boolean done = false;\n"
+ "while (!done) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "int tag = input.readTag();\n"
+ "switch (tag) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "case 0:\n" // zero signals EOF / limit reached
+ " done = true;\n"
+ " break;\n"
+ "default: {\n"
+ " if (!parseUnknownField(input,$unknown_fields$\n"
+ " extensionRegistry, tag)) {\n"
+ " done = true;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n",
+ "unknown_fields", HasUnknownFields(descriptor_)
+ ? " unknownFields," : "");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ uint32 tag = WireFormatLite::MakeTag(field->number(),
+ WireFormat::WireTypeForFieldType(field->type()));
+
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateParsingCode(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+
+ if (field->is_packable()) {
+ // To make packed = true wire compatible, we generate parsing code from a
+ // packed version of this field regardless of field->options().packed().
+ uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(packed_tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+ }
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // switch (tag)
+ "}\n"); // while (!done)
+
+ printer->Outdent();
+ printer->Print(
+ "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+ " throw e.setUnfinishedMessage(this);\n"
+ "} catch (java.io.IOException e) {\n"
+ " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(this);\n"
+ "} finally {\n");
+ printer->Indent();
+
+ // Make repeated field list immutable.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ field_generators_.get(field).GenerateParsingDoneCode(printer);
+ }
+
+ // Make unknown fields immutable.
+ if (HasUnknownFields(descriptor_)) {
+ printer->Print(
+ "this.unknownFields = unknownFields.build();\n");
+ }
+
+ // Make extensions immutable.
+ printer->Print(
+ "makeExtensionsImmutable();\n");
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // finally
+ "}\n");
+}
+
+// ===================================================================
+void MessageGenerator::GenerateParser(io::Printer* printer) {
+ printer->Print(
+ "public static com.google.protobuf.Parser<$classname$> PARSER =\n"
+ " new com.google.protobuf.AbstractParser<$classname$>() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Print(
+ "public $classname$ parsePartialFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n",
+ "classname", descriptor_->name());
+ if (HasGeneratedMethods(descriptor_)) {
+ printer->Print(
+ " return new $classname$(input, extensionRegistry);\n",
+ "classname", descriptor_->name());
+ } else {
+ // When parsing constructor isn't generated, use builder to parse messages.
+ // Note, will fallback to use reflection based mergeFieldFrom() in
+ // AbstractMessage.Builder.
+ printer->Indent();
+ printer->Print(
+ "Builder builder = newBuilder();\n"
+ "try {\n"
+ " builder.mergeFrom(input, extensionRegistry);\n"
+ "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+ " throw e.setUnfinishedMessage(builder.buildPartial());\n"
+ "} catch (java.io.IOException e) {\n"
+ " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n"
+ "}\n"
+ "return builder.buildPartial();\n");
+ printer->Outdent();
+ }
+ printer->Print(
+ "}\n");
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+
+ printer->Print(
+ "@java.lang.Override\n"
+ "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
+ " return PARSER;\n"
+ "}\n"
+ "\n",
+ "classname", descriptor_->name());
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 4c6fbbe5..a30f0202 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -95,6 +95,9 @@ class MessageGenerator {
UseMemoization useMemoization);
void GenerateEqualsAndHashCode(io::Printer* printer);
+ void GenerateParser(io::Printer* printer);
+ void GenerateParsingConstructor(io::Printer* printer);
+
const Descriptor* descriptor_;
FieldGeneratorMap field_generators_;
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 251945af..b0b284f7 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -36,6 +36,7 @@
#include <string>
#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
@@ -73,6 +74,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
@@ -84,6 +86,13 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // For repeated fields, one bit is used for whether the array is immutable
+ // in the parsing constructor.
+ (*variables)["get_mutable_bit_parser"] =
+ GenerateGetBitMutableLocal(builderBitIndex);
+ (*variables)["set_mutable_bit_parser"] =
+ GenerateSetBitMutableLocal(builderBitIndex);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -120,11 +129,15 @@ GenerateInterfaceMembers(io::Printer* printer) const {
// interface so that builders can choose dynamically to either return a
// message or a nested builder, so that asking for the interface doesn't
// cause a message to ever be built.
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
}
@@ -133,15 +146,20 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_;\n"
+ "private $type$ $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_message$;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
" return $name$_;\n"
@@ -208,12 +226,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
// field of type "Field" called "Field".
// boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_builder$;\n"
"}\n");
// Field getField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public $type$ get$capitalized_name$()",
@@ -224,6 +244,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$($type$ value)",
@@ -239,6 +260,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" $type$.Builder builderForValue)",
@@ -252,6 +274,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder merge$capitalized_name$($type$ value)",
@@ -270,6 +293,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder clear$capitalized_name$()",
@@ -282,19 +306,24 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
" $set_has_field_bit_builder$;\n"
" $on_changed$\n"
" return get$capitalized_name$FieldBuilder().getBuilder();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
" if ($name$Builder_ != null) {\n"
" return $name$Builder_.getMessageOrBuilder();\n"
" } else {\n"
" return $name$_;\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"private com.google.protobuf.SingleFieldBuilder<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
@@ -357,21 +386,32 @@ GenerateBuildingCode(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$type$.Builder subBuilder = $type$.newBuilder();\n"
- "if (has$capitalized_name$()) {\n"
- " subBuilder.mergeFrom(get$capitalized_name$());\n"
+ "$type$.Builder subBuilder = null;\n"
+ "if ($get_has_field_bit_message$) {\n"
+ " subBuilder = $name$_.toBuilder();\n"
"}\n");
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ "$name$_ = input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry);\n");
} else {
printer->Print(variables_,
- "input.readMessage(subBuilder, extensionRegistry);\n");
+ "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
}
printer->Print(variables_,
- "set$capitalized_name$(subBuilder.buildPartial());\n");
+ "if (subBuilder != null) {\n"
+ " subBuilder.mergeFrom($name$_);\n"
+ " $name$_ = subBuilder.buildPartial();\n"
+ "}\n");
+ printer->Print(variables_,
+ "$set_has_field_bit_message$;\n");
+}
+
+void MessageFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for messages.
}
void MessageFieldGenerator::
@@ -437,15 +477,23 @@ GenerateInterfaceMembers(io::Printer* printer) const {
// interface so that builders can choose dynamically to either return a
// message or a nested builder, so that asking for the interface doesn't
// cause a message to ever be built.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$java.util.List<$type$> \n"
- " get$capitalized_name$List();\n"
- "$deprecation$$type$ get$capitalized_name$(int index);\n"
+ " get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$ get$capitalized_name$(int index);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$int get$capitalized_name$Count();\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$java.util.List<? extends $type$OrBuilder> \n"
- " get$capitalized_name$OrBuilderList();\n"
+ " get$capitalized_name$OrBuilderList();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index);\n");
}
@@ -454,20 +502,30 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.util.List<$type$> $name$_;\n"
+ "private java.util.List<$type$> $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
" get$capitalized_name$OrBuilderList() {\n"
" return $name$_;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index) {\n"
" return $name$_.get(index);\n"
@@ -552,6 +610,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
// repeated field of type "Field" called "RepeatedField".
// List<Field> getRepeatedFieldList()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public java.util.List<$type$> get$capitalized_name$List()",
@@ -561,6 +620,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// int getRepeatedFieldCount()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public int get$capitalized_name$Count()",
@@ -570,6 +630,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// Field getRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public $type$ get$capitalized_name$(int index)",
@@ -580,6 +641,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value)",
@@ -593,6 +655,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$.Builder builderForValue)",
@@ -606,6 +669,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$($type$ value)",
@@ -622,6 +686,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" int index, $type$ value)",
@@ -638,6 +703,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" $type$.Builder builderForValue)",
@@ -651,6 +717,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" int index, $type$.Builder builderForValue)",
@@ -664,6 +731,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $type$> values)",
@@ -677,6 +745,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder clear$capitalized_name$()",
@@ -689,6 +758,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder remove$capitalized_name$(int index)",
@@ -701,12 +771,15 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
" int index) {\n"
" return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index) {\n"
" if ($name$Builder_ == null) {\n"
@@ -714,8 +787,10 @@ GenerateBuilderMembers(io::Printer* printer) const {
" } else {\n"
" return $name$Builder_.getMessageOrBuilder(index);\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
" get$capitalized_name$OrBuilderList() {\n"
" if ($name$Builder_ != null) {\n"
@@ -723,17 +798,23 @@ GenerateBuilderMembers(io::Printer* printer) const {
" } else {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
" return get$capitalized_name$FieldBuilder().addBuilder(\n"
" $type$.getDefaultInstance());\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
" int index) {\n"
" return get$capitalized_name$FieldBuilder().addBuilder(\n"
" index, $type$.getDefaultInstance());\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$type$.Builder> \n"
" get$capitalized_name$BuilderList() {\n"
" return get$capitalized_name$FieldBuilder().getBuilderList();\n"
@@ -827,18 +908,27 @@ GenerateBuildingCode(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$type$.Builder subBuilder = $type$.newBuilder();\n");
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<$type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n");
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ "$name$_.add(input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry));\n");
} else {
printer->Print(variables_,
- "input.readMessage(subBuilder, extensionRegistry);\n");
+ "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
}
+}
+void RepeatedMessageFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
printer->Print(variables_,
- "add$capitalized_name$(subBuilder.buildPartial());\n");
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
}
void RepeatedMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 2efbcd97..5c8078a1 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -61,6 +61,7 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
@@ -102,6 +103,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 712e047a..0140e23f 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -36,6 +36,7 @@
#include <string>
#include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
@@ -197,6 +198,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
@@ -208,6 +210,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // For repeated fields, one bit is used for whether the array is immutable
+ // in the parsing constructor.
+ (*variables)["get_mutable_bit_parser"] =
+ GenerateGetBitMutableLocal(builderBitIndex);
+ (*variables)["set_mutable_bit_parser"] =
+ GenerateSetBitMutableLocal(builderBitIndex);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -240,19 +249,26 @@ int PrimitiveFieldGenerator::GetNumBitsForBuilder() const {
void PrimitiveFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
}
void PrimitiveFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_type$ $name$_;\n"
+ "private $field_type$ $name$_;\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_message$;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
@@ -262,16 +278,21 @@ GenerateMembers(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_type$ $name$_ $default_init$;\n"
+ "private $field_type$ $name$_ $default_init$;\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_builder$;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
"$null_check$"
@@ -279,7 +300,10 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_ = value;\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $clear_has_field_bit_builder$;\n");
JavaType type = GetJavaType(descriptor_);
@@ -335,11 +359,16 @@ GenerateBuildingCode(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_message$;\n"
"$name$_ = input.read$capitalized_type$();\n");
}
void PrimitiveFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for primitives.
+}
+
+void PrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
"if ($get_has_field_bit_message$) {\n"
@@ -468,9 +497,14 @@ int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const {
void RepeatedPrimitiveFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
"$deprecation$$type$ get$capitalized_name$(int index);\n");
}
@@ -478,14 +512,20 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_list_type$ $name$_;\n"
+ "private $field_list_type$ $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$boxed_type$>\n"
" get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
@@ -523,17 +563,24 @@ GenerateBuilderMembers(io::Printer* printer) const {
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public java.util.List<$boxed_type$>\n"
" get$capitalized_name$List() {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value) {\n"
"$null_check$"
@@ -541,21 +588,27 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.set(index, value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
"$null_check$"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $boxed_type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" super.addAll(values, $name$_);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_mutable_bit_builder$;\n"
@@ -616,7 +669,10 @@ GenerateBuildingCode(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "ensure$capitalized_name$IsMutable();\n"
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
"$name$_.add(input.read$capitalized_type$());\n");
}
@@ -625,13 +681,25 @@ 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 java.util.ArrayList<$boxed_type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
"while (input.getBytesUntilLimit() > 0) {\n"
- " add$capitalized_name$(input.read$capitalized_type$());\n"
+ " $name$_.add(input.read$capitalized_type$());\n"
"}\n"
"input.popLimit(limit);\n");
}
void RepeatedPrimitiveFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index 7900fac5..1b5b6d95 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -61,6 +61,7 @@ class PrimitiveFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
@@ -96,6 +97,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
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;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 1ae4f461..bbd24806 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -33,6 +33,7 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_service.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
@@ -50,6 +51,7 @@ ServiceGenerator::~ServiceGenerator() {}
void ServiceGenerator::Generate(io::Printer* printer) {
bool is_own_file = descriptor_->file()->options().java_multiple_files();
+ WriteServiceDocComment(printer, descriptor_);
printer->Print(
"public $static$ abstract class $classname$\n"
" implements com.google.protobuf.Service {\n",
@@ -157,6 +159,7 @@ void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
+ WriteMethodDocComment(printer, method);
GenerateMethodSignature(printer, method, IS_ABSTRACT);
printer->Print(";\n\n");
}
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 222285bd..4815663b 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -37,6 +37,7 @@
#include <string>
#include <google/protobuf/compiler/java/java_string_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
@@ -85,6 +86,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
@@ -96,6 +98,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // For repeated fields, one bit is used for whether the array is immutable
+ // in the parsing constructor.
+ (*variables)["get_mutable_bit_parser"] =
+ GenerateGetBitMutableLocal(builderBitIndex);
+ (*variables)["set_mutable_bit_parser"] =
+ GenerateSetBitMutableLocal(builderBitIndex);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -160,19 +169,29 @@ int StringFieldGenerator::GetNumBitsForBuilder() const {
// UnmodifiableLazyStringList.
void StringFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$java.lang.String get$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes();\n");
}
void StringFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.lang.Object $name$_;\n"
+ "private java.lang.Object $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_message$;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public java.lang.String get$capitalized_name$() {\n"
" java.lang.Object ref = $name$_;\n"
@@ -182,13 +201,16 @@ GenerateMembers(io::Printer* printer) const {
" com.google.protobuf.ByteString bs = \n"
" (com.google.protobuf.ByteString) ref;\n"
" java.lang.String s = bs.toStringUtf8();\n"
- " if (com.google.protobuf.Internal.isValidUtf8(bs)) {\n"
+ " if (bs.isValidUtf8()) {\n"
" $name$_ = s;\n"
" }\n"
" return s;\n"
" }\n"
- "}\n"
- "private com.google.protobuf.ByteString get$capitalized_name$Bytes() {\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
" java.lang.Object ref = $name$_;\n"
" if (ref instanceof java.lang.String) {\n"
" com.google.protobuf.ByteString b = \n"
@@ -205,11 +227,14 @@ GenerateMembers(io::Printer* printer) const {
void StringFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.lang.Object $name$_ $default_init$;\n"
+ "private java.lang.Object $name$_ $default_init$;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public boolean has$capitalized_name$() {\n"
" return $get_has_field_bit_builder$;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public java.lang.String get$capitalized_name$() {\n"
" java.lang.Object ref = $name$_;\n"
@@ -223,6 +248,23 @@ GenerateBuilderMembers(io::Printer* printer) const {
" }\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " java.lang.Object ref = $name$_;\n"
+ " if (ref instanceof String) {\n"
+ " com.google.protobuf.ByteString b = \n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
+ " $name$_ = b;\n"
+ " return b;\n"
+ " } else {\n"
+ " return (com.google.protobuf.ByteString) ref;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" java.lang.String value) {\n"
@@ -231,7 +273,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_ = value;\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $clear_has_field_bit_builder$;\n");
// The default value is not a simple literal so we want to avoid executing
@@ -243,11 +287,15 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "void set$capitalized_name$(com.google.protobuf.ByteString value) {\n"
+ "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$"
" $set_has_field_bit_builder$;\n"
" $name$_ = value;\n"
" $on_changed$\n"
+ " return this;\n"
"}\n");
}
@@ -270,9 +318,13 @@ GenerateBuilderClearCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
+ // Allow a slight breach of abstraction here in order to avoid forcing
+ // all string fields to Strings when copying fields from a Message.
printer->Print(variables_,
"if (other.has$capitalized_name$()) {\n"
- " set$capitalized_name$(other.get$capitalized_name$());\n"
+ " $set_has_field_bit_builder$;\n"
+ " $name$_ = other.$name$_;\n"
+ " $on_changed$\n"
"}\n");
}
@@ -288,11 +340,16 @@ GenerateBuildingCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_message$;\n"
"$name$_ = input.readBytes();\n");
}
void StringFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for strings.
+}
+
+void StringFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
"if ($get_has_field_bit_message$) {\n"
@@ -353,28 +410,49 @@ int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const {
void RepeatedStringFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$java.util.List<java.lang.String>\n"
- " get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
+ "get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index);\n");
}
void RepeatedStringFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private com.google.protobuf.LazyStringList $name$_;\n"
+ "private com.google.protobuf.LazyStringList $name$_;\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<java.lang.String>\n"
" get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index) {\n"
+ " return $name$_.getByteString(index);\n"
+ "}\n");
if (descriptor_->options().packed() &&
HasGeneratedMethods(descriptor_->containing_type())) {
@@ -409,17 +487,30 @@ GenerateBuilderMembers(io::Printer* printer) const {
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public java.util.List<java.lang.String>\n"
" get$capitalized_name$List() {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index) {\n"
+ " return $name$_.getByteString(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, java.lang.String value) {\n"
"$null_check$"
@@ -427,7 +518,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.set(index, value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder add$capitalized_name$(\n"
" java.lang.String value) {\n"
"$null_check$"
@@ -435,14 +528,18 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.add(value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<java.lang.String> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" super.addAll(values, $name$_);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_mutable_bit_builder$;\n"
@@ -450,11 +547,15 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "void add$capitalized_name$(com.google.protobuf.ByteString value) {\n"
+ "$deprecation$public Builder add$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $on_changed$\n"
+ " return this;\n"
"}\n");
}
@@ -512,7 +613,10 @@ GenerateBuildingCode(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "ensure$capitalized_name$IsMutable();\n"
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
"$name$_.add(input.readBytes());\n");
}
@@ -521,13 +625,25 @@ 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"
- " add$capitalized_name$(input.read$capitalized_type$());\n"
+ " $name$.add(input.read$capitalized_type$());\n"
"}\n"
"input.popLimit(limit);\n");
}
void RepeatedStringFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = new com.google.protobuf.UnmodifiableLazyStringList($name$_);\n"
+ "}\n");
+}
+
+void RepeatedStringFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 8cb41469..4f7532f4 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -62,6 +62,7 @@ class StringFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
@@ -96,6 +97,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
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;
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index d9b0c3f9..1afc5d61 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -43,7 +43,7 @@ int main(int argc, char* argv[]) {
// Proto2 C++
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
- cli.RegisterGenerator("--cpp_out", &cpp_generator,
+ cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
"Generate C++ header and source.");
// Proto2 Java
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 5b76af25..0e35ed19 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -33,13 +33,14 @@
#include <google/protobuf/compiler/mock_code_generator.h>
#include <google/protobuf/testing/file.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -132,6 +133,15 @@ bool MockCodeGenerator::Generate(
} else if (command == "Abort") {
cerr << "Saw message type MockCodeGenerator_Abort." << endl;
abort();
+ } else if (command == "HasSourceCodeInfo") {
+ FileDescriptorProto file_descriptor_proto;
+ file->CopySourceCodeInfoTo(&file_descriptor_proto);
+ bool has_source_code_info =
+ file_descriptor_proto.has_source_code_info() &&
+ file_descriptor_proto.source_code_info().location_size() > 0;
+ cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
+ << has_source_code_info << "." << endl;
+ abort();
} else {
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
}
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 5c7942bd..506fd207 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -59,6 +59,10 @@ namespace compiler {
// MockCodeGenerator_Exit." to stderr and then calls exit(123).
// MockCodeGenerator_Abort: Generate() prints "Saw message type
// MockCodeGenerator_Abort." to stderr and then calls abort().
+// MockCodeGenerator_HasSourceCodeInfo: Causes Generate() to abort after
+// printing "Saw message type MockCodeGenerator_HasSourceCodeInfo: FOO." to
+// stderr, where FOO is "1" if the supplied FileDescriptorProto has source
+// code info, and "0" otherwise.
class MockCodeGenerator : public CodeGenerator {
public:
MockCodeGenerator(const string& name);
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 34317b1f..23aa01ce 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -174,6 +174,20 @@ bool Parser::ConsumeInteger(int* output, const char* error) {
}
}
+bool Parser::ConsumeSignedInteger(int* output, const char* error) {
+ bool is_negative = false;
+ uint64 max_value = kint32max;
+ if (TryConsume("-")) {
+ is_negative = true;
+ max_value += 1;
+ }
+ uint64 value = 0;
+ DO(ConsumeInteger64(max_value, &value, error));
+ if (is_negative) value *= -1;
+ *output = value;
+ return true;
+}
+
bool Parser::ConsumeInteger64(uint64 max_value, uint64* output,
const char* error) {
if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
@@ -237,6 +251,35 @@ bool Parser::ConsumeString(string* output, const char* error) {
}
}
+bool Parser::TryConsumeEndOfDeclaration(const char* text,
+ const LocationRecorder* location) {
+ if (LookingAt(text)) {
+ string leading, trailing;
+ input_->NextWithComments(&trailing, NULL, &leading);
+
+ // Save the leading comments for next time, and recall the leading comments
+ // from last time.
+ leading.swap(upcoming_doc_comments_);
+
+ if (location != NULL) {
+ location->AttachComments(&leading, &trailing);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Parser::ConsumeEndOfDeclaration(const char* text,
+ const LocationRecorder* location) {
+ if (TryConsumeEndOfDeclaration(text, location)) {
+ return true;
+ } else {
+ AddError("Expected \"" + string(text) + "\".");
+ return false;
+ }
+}
+
// -------------------------------------------------------------------
void Parser::AddError(int line, int column, const string& error) {
@@ -315,6 +358,19 @@ void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
}
}
+void Parser::LocationRecorder::AttachComments(
+ string* leading, string* trailing) const {
+ GOOGLE_CHECK(!location_->has_leading_comments());
+ GOOGLE_CHECK(!location_->has_trailing_comments());
+
+ if (!leading->empty()) {
+ location_->mutable_leading_comments()->swap(*leading);
+ }
+ if (!trailing->empty()) {
+ location_->mutable_trailing_comments()->swap(*trailing);
+ }
+}
+
// -------------------------------------------------------------------
void Parser::SkipStatement() {
@@ -322,7 +378,7 @@ void Parser::SkipStatement() {
if (AtEnd()) {
return;
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
return;
} else if (TryConsume("{")) {
SkipRestOfBlock();
@@ -340,7 +396,7 @@ void Parser::SkipRestOfBlock() {
if (AtEnd()) {
return;
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
- if (TryConsume("}")) {
+ if (TryConsumeEndOfDeclaration("}", NULL)) {
return;
} else if (TryConsume("{")) {
SkipRestOfBlock();
@@ -366,7 +422,7 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
if (LookingAtType(io::Tokenizer::TYPE_START)) {
// Advance to first token.
- input_->Next();
+ input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
}
{
@@ -393,7 +449,7 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
if (LookingAt("}")) {
AddError("Unmatched \"}\".");
- input_->Next();
+ input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
}
}
}
@@ -411,7 +467,7 @@ bool Parser::ParseSyntaxIdentifier() {
io::Tokenizer::Token syntax_token = input_->current();
string syntax;
DO(ConsumeString(&syntax, "Expected syntax identifier."));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", NULL));
syntax_identifier_ = syntax;
@@ -427,7 +483,7 @@ bool Parser::ParseSyntaxIdentifier() {
bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
const LocationRecorder& root_location) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("message")) {
@@ -451,14 +507,16 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
FileDescriptorProto::kMessageTypeFieldNumber,
location);
} else if (LookingAt("import")) {
- int index = file->dependency_size();
- return ParseImport(file->add_dependency(), root_location, index);
+ return ParseImport(file->mutable_dependency(),
+ file->mutable_public_dependency(),
+ file->mutable_weak_dependency(),
+ root_location);
} else if (LookingAt("package")) {
return ParsePackage(file, root_location);
} else if (LookingAt("option")) {
LocationRecorder location(root_location,
FileDescriptorProto::kOptionsFieldNumber);
- return ParseOption(file->mutable_options(), location);
+ return ParseOption(file->mutable_options(), location, OPTION_STATEMENT);
} else {
AddError("Expected top-level statement (e.g. \"message\").");
return false;
@@ -482,11 +540,45 @@ bool Parser::ParseMessageDefinition(DescriptorProto* message,
return true;
}
+namespace {
+
+const int kMaxExtensionRangeSentinel = -1;
+
+bool IsMessageSetWireFormatMessage(const DescriptorProto& message) {
+ const MessageOptions& options = message.options();
+ for (int i = 0; i < options.uninterpreted_option_size(); ++i) {
+ const UninterpretedOption& uninterpreted = options.uninterpreted_option(i);
+ if (uninterpreted.name_size() == 1 &&
+ uninterpreted.name(0).name_part() == "message_set_wire_format" &&
+ uninterpreted.identifier_value() == "true") {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Modifies any extension ranges that specified 'max' as the end of the
+// extension range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) {
+ const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+ const int max_extension_number = is_message_set ?
+ kint32max :
+ FieldDescriptor::kMaxNumber + 1;
+ for (int i = 0; i < message->extension_range_size(); ++i) {
+ if (message->extension_range(i).end() == kMaxExtensionRangeSentinel) {
+ message->mutable_extension_range(i)->set_end(max_extension_number);
+ }
+ }
+}
+
+} // namespace
+
bool Parser::ParseMessageBlock(DescriptorProto* message,
const LocationRecorder& message_location) {
- DO(Consume("{"));
+ DO(ConsumeEndOfDeclaration("{", &message_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in message definition (missing '}').");
return false;
@@ -499,12 +591,15 @@ bool Parser::ParseMessageBlock(DescriptorProto* message,
}
}
+ if (message->extension_range_size() > 0) {
+ AdjustExtensionRangesWithMaxEndNumber(message);
+ }
return true;
}
bool Parser::ParseMessageStatement(DescriptorProto* message,
const LocationRecorder& message_location) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("message")) {
@@ -532,7 +627,7 @@ bool Parser::ParseMessageStatement(DescriptorProto* message,
} else if (LookingAt("option")) {
LocationRecorder location(message_location,
DescriptorProto::kOptionsFieldNumber);
- return ParseOption(message->mutable_options(), location);
+ return ParseOption(message->mutable_options(), location, OPTION_STATEMENT);
} else {
LocationRecorder location(message_location,
DescriptorProto::kFieldFieldNumber,
@@ -647,7 +742,7 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field,
return false;
}
} else {
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &field_location));
}
return true;
@@ -669,7 +764,7 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
// the default value is not actually an option.
DO(ParseDefaultAssignment(field, field_location));
} else {
- DO(ParseOptionAssignment(field->mutable_options(), location));
+ DO(ParseOption(field->mutable_options(), location, OPTION_ASSIGNMENT));
}
} while (TryConsume(","));
@@ -835,6 +930,8 @@ bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
bool Parser::ParseUninterpretedBlock(string* value) {
// Note that enclosing braces are not added to *value.
+ // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting
+ // an expression, not a block of statements.
DO(Consume("{"));
int brace_depth = 1;
while (!AtEnd()) {
@@ -858,8 +955,9 @@ bool Parser::ParseUninterpretedBlock(string* value) {
// We don't interpret the option here. Instead we store it in an
// UninterpretedOption, to be interpreted later.
-bool Parser::ParseOptionAssignment(Message* options,
- const LocationRecorder& options_location) {
+bool Parser::ParseOption(Message* options,
+ const LocationRecorder& options_location,
+ OptionStyle style) {
// Create an entry in the uninterpreted_option field.
const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()->
FindFieldByName("uninterpreted_option");
@@ -872,6 +970,10 @@ bool Parser::ParseOptionAssignment(Message* options,
options_location, uninterpreted_option_field->number(),
reflection->FieldSize(*options, uninterpreted_option_field));
+ if (style == OPTION_STATEMENT) {
+ DO(Consume("option"));
+ }
+
UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
options->GetReflection()->AddMessage(options,
uninterpreted_option_field));
@@ -899,82 +1001,91 @@ bool Parser::ParseOptionAssignment(Message* options,
DO(Consume("="));
- LocationRecorder value_location(location);
- value_location.RecordLegacyLocation(
- uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
-
- // All values are a single token, except for negative numbers, which consist
- // of a single '-' symbol, followed by a positive number.
- bool is_negative = TryConsume("-");
+ {
+ LocationRecorder value_location(location);
+ value_location.RecordLegacyLocation(
+ uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
- switch (input_->current().type) {
- case io::Tokenizer::TYPE_START:
- GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
- return false;
+ // All values are a single token, except for negative numbers, which consist
+ // of a single '-' symbol, followed by a positive number.
+ bool is_negative = TryConsume("-");
- case io::Tokenizer::TYPE_END:
- AddError("Unexpected end of stream while parsing option value.");
- return false;
+ switch (input_->current().type) {
+ case io::Tokenizer::TYPE_START:
+ GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
+ return false;
- case io::Tokenizer::TYPE_IDENTIFIER: {
- value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber);
- if (is_negative) {
- AddError("Invalid '-' symbol before identifier.");
+ case io::Tokenizer::TYPE_END:
+ AddError("Unexpected end of stream while parsing option value.");
return false;
- }
- string value;
- DO(ConsumeIdentifier(&value, "Expected identifier."));
- uninterpreted_option->set_identifier_value(value);
- break;
- }
- case io::Tokenizer::TYPE_INTEGER: {
- uint64 value;
- uint64 max_value =
- is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
- DO(ConsumeInteger64(max_value, &value, "Expected integer."));
- if (is_negative) {
+ case io::Tokenizer::TYPE_IDENTIFIER: {
value_location.AddPath(
- UninterpretedOption::kNegativeIntValueFieldNumber);
- uninterpreted_option->set_negative_int_value(-static_cast<int64>(value));
- } else {
- value_location.AddPath(
- UninterpretedOption::kPositiveIntValueFieldNumber);
- uninterpreted_option->set_positive_int_value(value);
+ UninterpretedOption::kIdentifierValueFieldNumber);
+ if (is_negative) {
+ AddError("Invalid '-' symbol before identifier.");
+ return false;
+ }
+ string value;
+ DO(ConsumeIdentifier(&value, "Expected identifier."));
+ uninterpreted_option->set_identifier_value(value);
+ break;
}
- break;
- }
- case io::Tokenizer::TYPE_FLOAT: {
- value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
- double value;
- DO(ConsumeNumber(&value, "Expected number."));
- uninterpreted_option->set_double_value(is_negative ? -value : value);
- break;
- }
+ case io::Tokenizer::TYPE_INTEGER: {
+ uint64 value;
+ uint64 max_value =
+ is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ if (is_negative) {
+ value_location.AddPath(
+ UninterpretedOption::kNegativeIntValueFieldNumber);
+ uninterpreted_option->set_negative_int_value(
+ -static_cast<int64>(value));
+ } else {
+ value_location.AddPath(
+ UninterpretedOption::kPositiveIntValueFieldNumber);
+ uninterpreted_option->set_positive_int_value(value);
+ }
+ break;
+ }
- case io::Tokenizer::TYPE_STRING: {
- value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
- if (is_negative) {
- AddError("Invalid '-' symbol before string.");
- return false;
+ case io::Tokenizer::TYPE_FLOAT: {
+ value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
+ double value;
+ DO(ConsumeNumber(&value, "Expected number."));
+ uninterpreted_option->set_double_value(is_negative ? -value : value);
+ break;
}
- string value;
- DO(ConsumeString(&value, "Expected string."));
- uninterpreted_option->set_string_value(value);
- break;
- }
- case io::Tokenizer::TYPE_SYMBOL:
- if (LookingAt("{")) {
- value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber);
- DO(ParseUninterpretedBlock(
- uninterpreted_option->mutable_aggregate_value()));
- } else {
- AddError("Expected option value.");
- return false;
+ case io::Tokenizer::TYPE_STRING: {
+ value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
+ if (is_negative) {
+ AddError("Invalid '-' symbol before string.");
+ return false;
+ }
+ string value;
+ DO(ConsumeString(&value, "Expected string."));
+ uninterpreted_option->set_string_value(value);
+ break;
}
- break;
+
+ case io::Tokenizer::TYPE_SYMBOL:
+ if (LookingAt("{")) {
+ value_location.AddPath(
+ UninterpretedOption::kAggregateValueFieldNumber);
+ DO(ParseUninterpretedBlock(
+ uninterpreted_option->mutable_aggregate_value()));
+ } else {
+ AddError("Expected option value.");
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (style == OPTION_STATEMENT) {
+ DO(ConsumeEndOfDeclaration(";", &location));
}
return true;
@@ -1008,7 +1119,10 @@ bool Parser::ParseExtensions(DescriptorProto* message,
LocationRecorder end_location(
location, DescriptorProto::ExtensionRange::kEndFieldNumber);
if (TryConsume("max")) {
- end = FieldDescriptor::kMaxNumber;
+ // Set to the sentinel value - 1 since we increment the value below.
+ // The actual value of the end of the range should be set with
+ // AdjustExtensionRangesWithMaxEndNumber.
+ end = kMaxExtensionRangeSentinel - 1;
} else {
DO(ConsumeInteger(&end, "Expected integer."));
}
@@ -1028,7 +1142,7 @@ bool Parser::ParseExtensions(DescriptorProto* message,
range->set_end(end);
} while (TryConsume(","));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &extensions_location));
return true;
}
@@ -1046,7 +1160,7 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
io::Tokenizer::Token extendee_end = input_->previous();
// Parse the block.
- DO(Consume("{"));
+ DO(ConsumeEndOfDeclaration("{", &extend_location));
bool is_first = true;
@@ -1083,7 +1197,7 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
// other statements.
SkipStatement();
}
- } while(!TryConsume("}"));
+ } while (!TryConsumeEndOfDeclaration("}", NULL));
return true;
}
@@ -1109,9 +1223,9 @@ bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
const LocationRecorder& enum_location) {
- DO(Consume("{"));
+ DO(ConsumeEndOfDeclaration("{", &enum_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in enum definition (missing '}').");
return false;
@@ -1129,13 +1243,14 @@ bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
const LocationRecorder& enum_location) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("option")) {
LocationRecorder location(enum_location,
EnumDescriptorProto::kOptionsFieldNumber);
- return ParseOption(enum_type->mutable_options(), location);
+ return ParseOption(enum_type->mutable_options(), location,
+ OPTION_STATEMENT);
} else {
LocationRecorder location(enum_location,
EnumDescriptorProto::kValueFieldNumber, enum_type->value_size());
@@ -1164,16 +1279,14 @@ bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
location.RecordLegacyLocation(
enum_value, DescriptorPool::ErrorCollector::NUMBER);
- bool is_negative = TryConsume("-");
int number;
- DO(ConsumeInteger(&number, "Expected integer."));
- if (is_negative) number *= -1;
+ DO(ConsumeSignedInteger(&number, "Expected integer."));
enum_value->set_number(number);
}
DO(ParseEnumConstantOptions(enum_value, enum_value_location));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &enum_value_location));
return true;
}
@@ -1189,7 +1302,7 @@ bool Parser::ParseEnumConstantOptions(
DO(Consume("["));
do {
- DO(ParseOptionAssignment(value->mutable_options(), location));
+ DO(ParseOption(value->mutable_options(), location, OPTION_ASSIGNMENT));
} while (TryConsume(","));
DO(Consume("]"));
@@ -1217,9 +1330,9 @@ bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service,
bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
const LocationRecorder& service_location) {
- DO(Consume("{"));
+ DO(ConsumeEndOfDeclaration("{", &service_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in service definition (missing '}').");
return false;
@@ -1237,13 +1350,13 @@ bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
const LocationRecorder& service_location) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("option")) {
LocationRecorder location(
service_location, ServiceDescriptorProto::kOptionsFieldNumber);
- return ParseOption(service->mutable_options(), location);
+ return ParseOption(service->mutable_options(), location, OPTION_STATEMENT);
} else {
LocationRecorder location(service_location,
ServiceDescriptorProto::kMethodFieldNumber, service->method_size());
@@ -1286,28 +1399,41 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
}
DO(Consume(")"));
- if (TryConsume("{")) {
+ if (LookingAt("{")) {
// Options!
- while (!TryConsume("}")) {
- if (AtEnd()) {
- AddError("Reached end of input in method options (missing '}').");
- return false;
- }
+ DO(ParseOptions(method_location,
+ MethodDescriptorProto::kOptionsFieldNumber,
+ method->mutable_options()));
+ } else {
+ DO(ConsumeEndOfDeclaration(";", &method_location));
+ }
- if (TryConsume(";")) {
- // empty statement; ignore
- } else {
- LocationRecorder location(method_location,
- MethodDescriptorProto::kOptionsFieldNumber);
- if (!ParseOption(method->mutable_options(), location)) {
- // This statement failed to parse. Skip it, but keep looping to
- // parse other statements.
- SkipStatement();
- }
+ return true;
+}
+
+
+bool Parser::ParseOptions(const LocationRecorder& parent_location,
+ const int optionsFieldNumber,
+ Message* mutable_options) {
+ // Options!
+ ConsumeEndOfDeclaration("{", &parent_location);
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
+ if (AtEnd()) {
+ AddError("Reached end of input in method options (missing '}').");
+ return false;
+ }
+
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
+ // empty statement; ignore
+ } else {
+ LocationRecorder location(parent_location,
+ optionsFieldNumber);
+ if (!ParseOption(mutable_options, location, OPTION_STATEMENT)) {
+ // This statement failed to parse. Skip it, but keep looping to
+ // parse other statements.
+ SkipStatement();
}
}
- } else {
- DO(Consume(";"));
}
return true;
@@ -1406,32 +1532,44 @@ bool Parser::ParsePackage(FileDescriptorProto* file,
if (!TryConsume(".")) break;
file->mutable_package()->append(".");
}
+
+ location.EndAt(input_->previous());
+
+ DO(ConsumeEndOfDeclaration(";", &location));
}
- DO(Consume(";"));
return true;
}
-bool Parser::ParseImport(string* import_filename,
- const LocationRecorder& root_location,
- int index) {
+bool Parser::ParseImport(RepeatedPtrField<string>* dependency,
+ RepeatedField<int32>* public_dependency,
+ RepeatedField<int32>* weak_dependency,
+ const LocationRecorder& root_location) {
DO(Consume("import"));
+ if (LookingAt("public")) {
+ LocationRecorder location(
+ root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
+ public_dependency->size());
+ DO(Consume("public"));
+ *public_dependency->Add() = dependency->size();
+ } else if (LookingAt("weak")) {
+ LocationRecorder location(
+ root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
+ weak_dependency->size());
+ DO(Consume("weak"));
+ *weak_dependency->Add() = dependency->size();
+ }
{
LocationRecorder location(root_location,
FileDescriptorProto::kDependencyFieldNumber,
- index);
- DO(ConsumeString(import_filename,
+ dependency->size());
+ DO(ConsumeString(dependency->Add(),
"Expected a string naming the file to import."));
- }
- DO(Consume(";"));
- return true;
-}
-bool Parser::ParseOption(Message* options,
- const LocationRecorder& options_location) {
- DO(Consume("option"));
- DO(ParseOptionAssignment(options, options_location));
- DO(Consume(";"));
+ location.EndAt(input_->previous());
+
+ DO(ConsumeEndOfDeclaration(";", &location));
+ }
return true;
}
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 4cc90a29..cfd3649b 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -116,6 +116,8 @@ class LIBPROTOBUF_EXPORT Parser {
}
private:
+ class LocationRecorder;
+
// =================================================================
// Error recovery helpers
@@ -164,6 +166,8 @@ class LIBPROTOBUF_EXPORT Parser {
bool ConsumeIdentifier(string* output, const char* error);
// Consume an integer and store its value in "output".
bool ConsumeInteger(int* output, const char* error);
+ // Consume a signed integer and store its value in "output".
+ bool ConsumeSignedInteger(int* output, const char* error);
// Consume a 64-bit integer and store its value in "output". If the value
// is greater than max_value, an error will be reported.
bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error);
@@ -173,6 +177,20 @@ class LIBPROTOBUF_EXPORT Parser {
// Consume a string literal and store its (unescaped) value in "output".
bool ConsumeString(string* output, const char* error);
+ // Consume a token representing the end of the statement. Comments between
+ // this token and the next will be harvested for documentation. The given
+ // LocationRecorder should refer to the declaration that was just parsed;
+ // it will be populated with these comments.
+ //
+ // TODO(kenton): The LocationRecorder is const because historically locations
+ // have been passed around by const reference, for no particularly good
+ // reason. We should probably go through and change them all to mutable
+ // pointer to make this more intuitive.
+ bool TryConsumeEndOfDeclaration(const char* text,
+ const LocationRecorder* location);
+ bool ConsumeEndOfDeclaration(const char* text,
+ const LocationRecorder* location);
+
// -----------------------------------------------------------------
// Error logging helpers
@@ -227,6 +245,14 @@ class LIBPROTOBUF_EXPORT Parser {
void RecordLegacyLocation(const Message* descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location);
+ // Attaches leading and trailing comments to the location. The two strings
+ // will be swapped into place, so after this is called *leading and
+ // *trailing will be empty.
+ //
+ // TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for
+ // why this is const.
+ void AttachComments(string* leading, string* trailing) const;
+
private:
Parser* parser_;
SourceCodeInfo::Location* location_;
@@ -265,9 +291,10 @@ class LIBPROTOBUF_EXPORT Parser {
const LocationRecorder& service_location);
bool ParsePackage(FileDescriptorProto* file,
const LocationRecorder& root_location);
- bool ParseImport(string* import_filename,
- const LocationRecorder& root_location,
- int index);
+ bool ParseImport(RepeatedPtrField<string>* dependency,
+ RepeatedField<int32>* public_dependency,
+ RepeatedField<int32>* weak_dependency,
+ const LocationRecorder& root_location);
bool ParseOption(Message* options,
const LocationRecorder& options_location);
@@ -329,6 +356,12 @@ class LIBPROTOBUF_EXPORT Parser {
bool ParseServiceMethod(MethodDescriptorProto* method,
const LocationRecorder& method_location);
+
+ // Parse options of a single method or stream.
+ bool ParseOptions(const LocationRecorder& parent_location,
+ const int optionsFieldNumber,
+ Message* mutable_options);
+
// Parse "required", "optional", or "repeated" and fill in "label"
// with the value.
bool ParseLabel(FieldDescriptorProto::Label* label);
@@ -351,11 +384,17 @@ class LIBPROTOBUF_EXPORT Parser {
bool ParseDefaultAssignment(FieldDescriptorProto* field,
const LocationRecorder& field_location);
+ enum OptionStyle {
+ OPTION_ASSIGNMENT, // just "name = value"
+ OPTION_STATEMENT // "option name = value;"
+ };
+
// Parse a single option name/value pair, e.g. "ctype = CORD". The name
// identifies a field of the given Message, and the value of that field
// is set to the parsed value.
- bool ParseOptionAssignment(Message* options,
- const LocationRecorder& options_location);
+ bool ParseOption(Message* options,
+ const LocationRecorder& options_location,
+ OptionStyle style);
// Parses a single part of a multipart option name. A multipart name consists
// of names separated by dots. Each name is either an identifier or a series
@@ -387,6 +426,10 @@ class LIBPROTOBUF_EXPORT Parser {
bool stop_after_syntax_identifier_;
string syntax_identifier_;
+ // Leading doc comments for the next declaration. These are not complete
+ // yet; use ConsumeEndOfDeclaration() to get the complete comments.
+ string upcoming_doc_comments_;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
};
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 156c0dc3..c61ac60e 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -44,6 +44,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map-util.h>
@@ -509,6 +510,31 @@ TEST_F(ParseMessageTest, CompoundExtensionRange) {
"}");
}
+TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
+ // Messages using the message_set_wire_format option can accept larger
+ // extension numbers, as the numbers are not encoded as int32 field values
+ // rather than tags.
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " extensions 4 to max;\n"
+ " option message_set_wire_format = true;\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " extension_range { start:4 end: 0x7fffffff }"
+ " options {\n"
+ " uninterpreted_option { \n"
+ " name {\n"
+ " name_part: \"message_set_wire_format\"\n"
+ " is_extension: false\n"
+ " }\n"
+ " identifier_value: \"true\"\n"
+ " }\n"
+ " }\n"
+ "}");
+}
+
TEST_F(ParseMessageTest, Extensions) {
ExpectParsesTo(
"extend Extendee1 { optional int32 foo = 12; }\n"
@@ -571,6 +597,10 @@ TEST_F(ParseEnumTest, Values) {
" FOO = 13;\n"
" BAR = -10;\n"
" BAZ = 500;\n"
+ " HEX_MAX = 0x7FFFFFFF;\n"
+ " HEX_MIN = -0x80000000;\n"
+ " INT_MAX = 2147483647;\n"
+ " INT_MIN = -2147483648;\n"
"}\n",
"enum_type {"
@@ -578,6 +608,10 @@ TEST_F(ParseEnumTest, Values) {
" value { name:\"FOO\" number:13 }"
" value { name:\"BAR\" number:-10 }"
" value { name:\"BAZ\" number:500 }"
+ " value { name:\"HEX_MAX\" number:2147483647 }"
+ " value { name:\"HEX_MIN\" number:-2147483648 }"
+ " value { name:\"INT_MAX\" number:2147483647 }"
+ " value { name:\"INT_MIN\" number:-2147483648 }"
"}");
}
@@ -631,7 +665,7 @@ TEST_F(ParseServiceTest, SimpleService) {
"}");
}
-TEST_F(ParseServiceTest, Methods) {
+TEST_F(ParseServiceTest, MethodsAndStreams) {
ExpectParsesTo(
"service TestService {\n"
" rpc Foo(In1) returns (Out1);\n"
@@ -668,6 +702,20 @@ TEST_F(ParseMiscTest, ParseMultipleImports) {
"dependency: \"baz.proto\"");
}
+TEST_F(ParseMiscTest, ParsePublicImports) {
+ ExpectParsesTo(
+ "import \"foo.proto\";\n"
+ "import public \"bar.proto\";\n"
+ "import \"baz.proto\";\n"
+ "import public \"qux.proto\";\n",
+ "dependency: \"foo.proto\""
+ "dependency: \"bar.proto\""
+ "dependency: \"baz.proto\""
+ "dependency: \"qux.proto\""
+ "public_dependency: 1 "
+ "public_dependency: 3 ");
+}
+
TEST_F(ParseMiscTest, ParsePackage) {
ExpectParsesTo(
"package foo.bar.baz;\n",
@@ -867,6 +915,20 @@ TEST_F(ParseErrorTest, DefaultValueTooLarge) {
"6:36: Integer out of range.\n");
}
+TEST_F(ParseErrorTest, EnumValueOutOfRange) {
+ ExpectHasErrors(
+ "enum TestEnum {\n"
+ " HEX_TOO_BIG = 0x80000000;\n"
+ " HEX_TOO_SMALL = -0x80000001;\n"
+ " INT_TOO_BIG = 2147483648;\n"
+ " INT_TOO_SMALL = -2147483649;\n"
+ "}\n",
+ "1:19: Integer out of range.\n"
+ "2:19: Integer out of range.\n"
+ "3:19: Integer out of range.\n"
+ "4:19: Integer out of range.\n");
+}
+
TEST_F(ParseErrorTest, DefaultValueMissing) {
ExpectHasErrors(
"message TestMessage {\n"
@@ -976,6 +1038,7 @@ TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
"1:26: Expected message type.\n");
}
+
TEST_F(ParseErrorTest, EofInMethodOptions) {
ExpectHasErrors(
"service TestService {\n"
@@ -984,6 +1047,7 @@ TEST_F(ParseErrorTest, EofInMethodOptions) {
"1:29: Reached end of input in service definition (missing '}').\n");
}
+
TEST_F(ParseErrorTest, PrimitiveMethodInput) {
ExpectHasErrors(
"service TestService {\n"
@@ -992,6 +1056,7 @@ TEST_F(ParseErrorTest, PrimitiveMethodInput) {
"1:10: Expected message type.\n");
}
+
TEST_F(ParseErrorTest, MethodOptionTypeError) {
// This used to cause an infinite loop.
ExpectHasErrors(
@@ -1002,6 +1067,7 @@ TEST_F(ParseErrorTest, MethodOptionTypeError) {
"2:45: Expected \"=\".\n");
}
+
// -------------------------------------------------------------------
// Import and package errors
@@ -1157,6 +1223,7 @@ TEST_F(ParserValidationErrorTest, MethodNameError) {
"3:6: \"Bar\" is already defined in \"Foo\".\n");
}
+
TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
ExpectHasValidationErrors(
"message Baz {}\n"
@@ -1166,6 +1233,7 @@ TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
"2:10: \"Qux\" is not defined.\n");
}
+
TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
ExpectHasValidationErrors(
"message Baz {}\n"
@@ -1175,6 +1243,7 @@ TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
"2:23: \"Qux\" is not defined.\n");
}
+
// ===================================================================
// Test that the output from FileDescriptor::DebugString() (and all other
// descriptor types) is parseable, and results in the same Descriptor
@@ -1236,6 +1305,11 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
// also need to give it the same name as the original.
parsed.set_name("google/protobuf/unittest.proto");
// We need the imported dependency before we can build our parsed proto
+ const FileDescriptor* public_import =
+ protobuf_unittest_import::PublicImportMessage::descriptor()->file();
+ FileDescriptorProto public_import_proto;
+ public_import->CopyTo(&public_import_proto);
+ ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL);
const FileDescriptor* import =
protobuf_unittest_import::ImportMessage::descriptor()->file();
FileDescriptorProto import_proto;
@@ -1258,6 +1332,45 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
EXPECT_EQ(expected.DebugString(), parsed.DebugString());
}
+TEST_F(ParseDecriptorDebugTest, TestCustomOptions) {
+ const FileDescriptor* original_file =
+ protobuf_unittest::AggregateMessage::descriptor()->file();
+ FileDescriptorProto expected;
+ original_file->CopyTo(&expected);
+
+ string debug_string = original_file->DebugString();
+
+ // Parse the debug string
+ 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_);
+
+ // We now have a FileDescriptorProto, but to compare with the expected we
+ // need to link to a FileDecriptor, then output back to a proto. We'll
+ // also need to give it the same name as the original.
+ parsed.set_name(original_file->name());
+
+ // unittest_custom_options.proto depends on descriptor.proto.
+ const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
+ FileDescriptorProto import_proto;
+ import->CopyTo(&import_proto);
+ ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+ const FileDescriptor* actual = pool_.BuildFile(parsed);
+ ASSERT_TRUE(actual != NULL);
+ parsed.Clear();
+ actual->CopyTo(&parsed);
+
+ // The messages might be in different orders, making them hard to compare.
+ // So, sort the messages in the descriptor protos (including nested messages,
+ // recursively).
+ SortMessages(&expected);
+ SortMessages(&parsed);
+
+ EXPECT_EQ(expected.DebugString(), parsed.DebugString());
+}
+
// ===================================================================
// SourceCodeInfo tests.
@@ -1353,67 +1466,6 @@ bool FollowPath(const Message& root,
}
}
-// Split some text on line breaks. The line breaks are retained in the output,
-// so each line (except the last) ends with a '\n', and the lines can be
-// concatenated to produce the original text.
-//
-// I couldn't find the proper string utility function for this. Our
-// split-on-delimiter functions don't include the delimiter in the output.
-void SplitLines(const string& text, vector<string>* lines) {
- string::size_type pos = 0;
-
- while (pos != string::npos) {
- string::size_type last_pos = pos;
- pos = text.find_first_of('\n', pos);
- if (pos != string::npos) ++pos;
- lines->push_back(text.substr(last_pos, pos - last_pos));
- }
-}
-
-// Look for the given tags in the given text and construct a span (as defined
-// by SourceCodeInfo.Location.span) from them. E.g. for text like:
-// /*a*/message /*b*/Foo/*c*/ {}/*d*/
-// There are four tags: "a", "b", "c", and "d". The constructed span starts
-// immediately after the start tag's trailing '/' and ends immediately before
-// the end tags leading '/'.
-void MakeExpectedSpan(const vector<string>& lines,
- const string& start_tag, const string& end_tag,
- RepeatedField<int>* output) {
- string start_comment = "/*" + start_tag + "*/";
- string end_comment = "/*" + end_tag + "*/";
-
- int start_line = -1;
- int start_column = -1;
- for (int i = 0; i < lines.size(); i++) {
- string::size_type pos = lines[i].find(start_comment);
- if (pos != string::npos) {
- start_line = i;
- start_column = pos + start_comment.size();
- break;
- }
- }
- ASSERT_NE(start_line, -1)
- << "Tag \"" << start_comment << "\" not found in text.";
-
- int end_line = -1;
- int end_column = -1;
- for (int i = start_line; i < lines.size(); i++) {
- string::size_type pos = lines[i].find(end_comment);
- if (pos != string::npos) {
- end_line = i;
- end_column = pos;
- break;
- }
- }
- ASSERT_NE(end_line, -1)
- << "Tag \"" << end_comment << "\" not found in text.";
-
- output->Add(start_line);
- output->Add(start_column);
- if (end_line != start_line) output->Add(end_line);
- output->Add(end_column);
-}
-
// Check if two spans are equal.
bool CompareSpans(const RepeatedField<int>& span1,
const RepeatedField<int>& span2) {
@@ -1434,8 +1486,8 @@ class SourceInfoTest : public ParserTest {
// Parse the given text as a .proto file and populate the spans_ map with
// all the source location spans in its SourceCodeInfo table.
bool Parse(const char* text) {
- SetupParser(text);
- SplitLines(text, &lines_);
+ ExtractMarkers(text);
+ SetupParser(text_without_markers_.c_str());
if (!parser_->Parse(input_.get(), &file_)) {
return false;
}
@@ -1470,19 +1522,38 @@ class SourceInfoTest : public ParserTest {
// part of the FileDescriptorProto. (If unclear, look at the actual tests;
// it should quickly become obvious.)
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto) {
- return HasSpan(start_tag, end_tag, descriptor_proto, NULL, -1);
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpanWithComment(char start_marker, char end_marker,
+ const Message& descriptor_proto,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments) {
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, NULL, -1,
+ expected_leading_comments, expected_trailing_comments);
+ }
+
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto, const string& field_name) {
- return HasSpan(start_tag, end_tag, descriptor_proto, field_name, -1);
+ return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto, const string& field_name,
int index) {
+ return HasSpan(start_marker, end_marker, descriptor_proto,
+ field_name, index, NULL, NULL);
+ }
+
+ bool HasSpan(char start_marker, char end_marker,
+ const Message& descriptor_proto,
+ const string& field_name, int index,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments) {
const FieldDescriptor* field =
descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
if (field == NULL) {
@@ -1491,29 +1562,34 @@ class SourceInfoTest : public ParserTest {
return false;
}
- return HasSpan(start_tag, end_tag, descriptor_proto, field, index);
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, field, index,
+ expected_leading_comments, expected_trailing_comments);
}
bool HasSpan(const Message& descriptor_proto) {
- return HasSpan(NULL, NULL, descriptor_proto, NULL, -1);
+ return HasSpanWithComment(
+ '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL);
}
bool HasSpan(const Message& descriptor_proto, const string& field_name) {
- return HasSpan(NULL, NULL, descriptor_proto, field_name, -1);
+ return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
}
bool HasSpan(const Message& descriptor_proto, const string& field_name,
int index) {
- return HasSpan(NULL, NULL, descriptor_proto, field_name, index);
+ return HasSpan('\0', '\0', descriptor_proto, field_name, index);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
- const Message& descriptor_proto, const FieldDescriptor* field,
- int index) {
+ bool HasSpanWithComment(char start_marker, char end_marker,
+ const Message& descriptor_proto,
+ const FieldDescriptor* field, int index,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments) {
pair<SpanMap::iterator, SpanMap::iterator> range =
spans_.equal_range(SpanKey(descriptor_proto, field, index));
- if (start_tag == NULL) {
+ if (start_marker == '\0') {
if (range.first == range.second) {
return false;
} else {
@@ -1521,11 +1597,34 @@ class SourceInfoTest : public ParserTest {
return true;
}
} else {
+ pair<int, int> start_pos = FindOrDie(markers_, start_marker);
+ pair<int, int> end_pos = FindOrDie(markers_, end_marker);
+
RepeatedField<int> expected_span;
- MakeExpectedSpan(lines_, start_tag, end_tag, &expected_span);
+ expected_span.Add(start_pos.first);
+ expected_span.Add(start_pos.second);
+ if (end_pos.first != start_pos.first) {
+ expected_span.Add(end_pos.first);
+ }
+ expected_span.Add(end_pos.second);
for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
if (CompareSpans(expected_span, iter->second->span())) {
+ if (expected_leading_comments == NULL) {
+ EXPECT_FALSE(iter->second->has_leading_comments());
+ } else {
+ EXPECT_TRUE(iter->second->has_leading_comments());
+ EXPECT_EQ(expected_leading_comments,
+ iter->second->leading_comments());
+ }
+ if (expected_trailing_comments == NULL) {
+ EXPECT_FALSE(iter->second->has_trailing_comments());
+ } else {
+ EXPECT_TRUE(iter->second->has_trailing_comments());
+ EXPECT_EQ(expected_trailing_comments,
+ iter->second->trailing_comments());
+ }
+
spans_.erase(iter);
return true;
}
@@ -1542,10 +1641,11 @@ class SourceInfoTest : public ParserTest {
int index;
inline SpanKey() {}
- inline SpanKey(const Message& descriptor_proto,
- const FieldDescriptor* field,
- int index)
- : descriptor_proto(&descriptor_proto), field(field), index(index) {}
+ inline SpanKey(const Message& descriptor_proto_param,
+ const FieldDescriptor* field_param,
+ int index_param)
+ : descriptor_proto(&descriptor_proto_param), field(field_param),
+ index(index_param) {}
inline bool operator<(const SpanKey& other) const {
if (descriptor_proto < other.descriptor_proto) return true;
@@ -1558,32 +1658,63 @@ class SourceInfoTest : public ParserTest {
typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
SpanMap spans_;
- vector<string> lines_;
+ map<char, pair<int, int> > markers_;
+ string text_without_markers_;
+
+ void ExtractMarkers(const char* text) {
+ markers_.clear();
+ text_without_markers_.clear();
+ int line = 0;
+ int column = 0;
+ while (*text != '\0') {
+ if (*text == '$') {
+ ++text;
+ GOOGLE_CHECK_NE('\0', *text);
+ if (*text == '$') {
+ text_without_markers_ += '$';
+ ++column;
+ } else {
+ markers_[*text] = make_pair(line, column);
+ ++text;
+ GOOGLE_CHECK_EQ('$', *text);
+ }
+ } else if (*text == '\n') {
+ ++line;
+ column = 0;
+ text_without_markers_ += *text;
+ } else {
+ text_without_markers_ += *text;
+ ++column;
+ }
+ ++text;
+ }
+ }
};
TEST_F(SourceInfoTest, BasicFileDecls) {
EXPECT_TRUE(Parse(
- "/*a*/syntax = \"proto2\";\n"
- "package /*b*/foo.bar/*c*/;\n"
- "import /*d*/\"baz.proto\"/*e*/;\n"
- "import /*f*/\"qux.proto\"/*g*/;/*h*/\n"
+ "$a$syntax = \"proto2\";\n"
+ "package $b$foo.bar$c$;\n"
+ "import $d$\"baz.proto\"$e$;\n"
+ "import $f$\"qux.proto\"$g$;$h$\n"
+ "\n"
"// comment ignored\n"));
- EXPECT_TRUE(HasSpan("a", "h", file_));
- EXPECT_TRUE(HasSpan("b", "c", file_, "package"));
- EXPECT_TRUE(HasSpan("d", "e", file_, "dependency", 0));
- EXPECT_TRUE(HasSpan("f", "g", file_, "dependency", 1));
+ EXPECT_TRUE(HasSpan('a', 'h', file_));
+ EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
+ EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
+ EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
}
TEST_F(SourceInfoTest, Messages) {
EXPECT_TRUE(Parse(
- "/*a*/message /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/message /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$message $b$Foo$c$ {}$d$\n"
+ "$e$message $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.message_type(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.message_type(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.message_type(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.message_type(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1592,24 +1723,24 @@ TEST_F(SourceInfoTest, Messages) {
TEST_F(SourceInfoTest, Fields) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/optional/*b*/ /*c*/int32/*d*/ /*e*/bar/*f*/ = /*g*/1/*h*/;/*i*/\n"
- " /*j*/repeated/*k*/ /*l*/X.Y/*m*/ /*n*/baz/*o*/ = /*p*/2/*q*/;/*r*/\n"
+ " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
+ " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
"}\n"));
const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
- EXPECT_TRUE(HasSpan("a", "i", field1));
- EXPECT_TRUE(HasSpan("a", "b", field1, "label"));
- EXPECT_TRUE(HasSpan("c", "d", field1, "type"));
- EXPECT_TRUE(HasSpan("e", "f", field1, "name"));
- EXPECT_TRUE(HasSpan("g", "h", field1, "number"));
+ EXPECT_TRUE(HasSpan('a', 'i', field1));
+ EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
+ EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
+ EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
+ EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
- EXPECT_TRUE(HasSpan("j", "r", field2));
- EXPECT_TRUE(HasSpan("j", "k", field2, "label"));
- EXPECT_TRUE(HasSpan("l", "m", field2, "type_name"));
- EXPECT_TRUE(HasSpan("n", "o", field2, "name"));
- EXPECT_TRUE(HasSpan("p", "q", field2, "number"));
+ EXPECT_TRUE(HasSpan('j', 'r', field2));
+ EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
+ EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
+ EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
+ EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1619,31 +1750,31 @@ TEST_F(SourceInfoTest, Fields) {
TEST_F(SourceInfoTest, Extensions) {
EXPECT_TRUE(Parse(
- "/*a*/extend /*b*/Foo/*c*/ {\n"
- " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
- " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
- "}/*j*/\n"
- "/*k*/extend /*l*/Bar/*m*/ {\n"
- " /*n*/optional int32 qux = 1;/*o*/\n"
- "}/*p*/\n"));
+ "$a$extend $b$Foo$c$ {\n"
+ " $d$optional$e$ int32 bar = 1;$f$\n"
+ " $g$repeated$h$ X.Y baz = 2;$i$\n"
+ "}$j$\n"
+ "$k$extend $l$Bar$m$ {\n"
+ " $n$optional int32 qux = 1;$o$\n"
+ "}$p$\n"));
const FieldDescriptorProto& field1 = file_.extension(0);
const FieldDescriptorProto& field2 = file_.extension(1);
const FieldDescriptorProto& field3 = file_.extension(2);
- EXPECT_TRUE(HasSpan("a", "j", file_, "extension"));
- EXPECT_TRUE(HasSpan("k", "p", file_, "extension"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
+ EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
- EXPECT_TRUE(HasSpan("d", "f", field1));
- EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+ EXPECT_TRUE(HasSpan('d', 'f', field1));
+ EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
- EXPECT_TRUE(HasSpan("g", "i", field2));
- EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+ EXPECT_TRUE(HasSpan('g', 'i', field2));
+ EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
- EXPECT_TRUE(HasSpan("n", "o", field3));
- EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+ EXPECT_TRUE(HasSpan('n', 'o', field3));
+ EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1662,32 +1793,32 @@ TEST_F(SourceInfoTest, Extensions) {
TEST_F(SourceInfoTest, NestedExtensions) {
EXPECT_TRUE(Parse(
"message Message {\n"
- " /*a*/extend /*b*/Foo/*c*/ {\n"
- " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
- " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
- " }/*j*/\n"
- " /*k*/extend /*l*/Bar/*m*/ {\n"
- " /*n*/optional int32 qux = 1;/*o*/\n"
- " }/*p*/\n"
+ " $a$extend $b$Foo$c$ {\n"
+ " $d$optional$e$ int32 bar = 1;$f$\n"
+ " $g$repeated$h$ X.Y baz = 2;$i$\n"
+ " }$j$\n"
+ " $k$extend $l$Bar$m$ {\n"
+ " $n$optional int32 qux = 1;$o$\n"
+ " }$p$\n"
"}\n"));
const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
- EXPECT_TRUE(HasSpan("a", "j", file_.message_type(0), "extension"));
- EXPECT_TRUE(HasSpan("k", "p", file_.message_type(0), "extension"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
+ EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
- EXPECT_TRUE(HasSpan("d", "f", field1));
- EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+ EXPECT_TRUE(HasSpan('d', 'f', field1));
+ EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
- EXPECT_TRUE(HasSpan("g", "i", field2));
- EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+ EXPECT_TRUE(HasSpan('g', 'i', field2));
+ EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
- EXPECT_TRUE(HasSpan("n", "o", field3));
- EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+ EXPECT_TRUE(HasSpan('n', 'o', field3));
+ EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1708,8 +1839,8 @@ TEST_F(SourceInfoTest, NestedExtensions) {
TEST_F(SourceInfoTest, ExtensionRanges) {
EXPECT_TRUE(Parse(
"message Message {\n"
- " /*a*/extensions /*b*/1/*c*/ to /*d*/4/*e*/, /*f*/6/*g*/;/*h*/\n"
- " /*i*/extensions /*j*/8/*k*/ to /*l*/max/*m*/;/*n*/\n"
+ " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
+ " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
"}\n"));
const DescriptorProto::ExtensionRange& range1 =
@@ -1719,20 +1850,20 @@ TEST_F(SourceInfoTest, ExtensionRanges) {
const DescriptorProto::ExtensionRange& range3 =
file_.message_type(0).extension_range(2);
- EXPECT_TRUE(HasSpan("a", "h", file_.message_type(0), "extension_range"));
- EXPECT_TRUE(HasSpan("i", "n", file_.message_type(0), "extension_range"));
+ EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
+ EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
- EXPECT_TRUE(HasSpan("b", "e", range1));
- EXPECT_TRUE(HasSpan("b", "c", range1, "start"));
- EXPECT_TRUE(HasSpan("d", "e", range1, "end"));
+ EXPECT_TRUE(HasSpan('b', 'e', range1));
+ EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
+ EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
- EXPECT_TRUE(HasSpan("f", "g", range2));
- EXPECT_TRUE(HasSpan("f", "g", range2, "start"));
- EXPECT_TRUE(HasSpan("f", "g", range2, "end"));
+ EXPECT_TRUE(HasSpan('f', 'g', range2));
+ EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
+ EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
- EXPECT_TRUE(HasSpan("j", "m", range3));
- EXPECT_TRUE(HasSpan("j", "k", range3, "start"));
- EXPECT_TRUE(HasSpan("l", "m", range3, "end"));
+ EXPECT_TRUE(HasSpan('j', 'm', range3));
+ EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
+ EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1743,22 +1874,22 @@ TEST_F(SourceInfoTest, ExtensionRanges) {
TEST_F(SourceInfoTest, NestedMessages) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/message /*b*/Bar/*c*/ {\n"
- " /*d*/message /*e*/Baz/*f*/ {}/*g*/\n"
- " }/*h*/\n"
- " /*i*/message /*j*/Qux/*k*/ {}/*l*/\n"
+ " $a$message $b$Bar$c$ {\n"
+ " $d$message $e$Baz$f$ {}$g$\n"
+ " }$h$\n"
+ " $i$message $j$Qux$k$ {}$l$\n"
"}\n"));
const DescriptorProto& bar = file_.message_type(0).nested_type(0);
const DescriptorProto& baz = bar.nested_type(0);
const DescriptorProto& qux = file_.message_type(0).nested_type(1);
- EXPECT_TRUE(HasSpan("a", "h", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("d", "g", baz));
- EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
- EXPECT_TRUE(HasSpan("i", "l", qux));
- EXPECT_TRUE(HasSpan("j", "k", qux, "name"));
+ EXPECT_TRUE(HasSpan('a', 'h', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('d', 'g', baz));
+ EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+ EXPECT_TRUE(HasSpan('i', 'l', qux));
+ EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1770,9 +1901,9 @@ TEST_F(SourceInfoTest, Groups) {
EXPECT_TRUE(Parse(
"message Foo {\n"
" message Bar {}\n"
- " /*a*/optional/*b*/ /*c*/group/*d*/ /*e*/Baz/*f*/ = /*g*/1/*h*/ {\n"
- " /*i*/message Qux {}/*j*/\n"
- " }/*k*/\n"
+ " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
+ " $i$message Qux {}$j$\n"
+ " }$k$\n"
"}\n"));
const DescriptorProto& bar = file_.message_type(0).nested_type(0);
@@ -1780,16 +1911,16 @@ TEST_F(SourceInfoTest, Groups) {
const DescriptorProto& qux = baz.nested_type(0);
const FieldDescriptorProto& field = file_.message_type(0).field(0);
- EXPECT_TRUE(HasSpan("a", "k", field));
- EXPECT_TRUE(HasSpan("a", "b", field, "label"));
- EXPECT_TRUE(HasSpan("c", "d", field, "type"));
- EXPECT_TRUE(HasSpan("e", "f", field, "name"));
- EXPECT_TRUE(HasSpan("e", "f", field, "type_name"));
- EXPECT_TRUE(HasSpan("g", "h", field, "number"));
+ EXPECT_TRUE(HasSpan('a', 'k', field));
+ EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
+ EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
+ EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
+ EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
+ EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
- EXPECT_TRUE(HasSpan("a", "k", baz));
- EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
- EXPECT_TRUE(HasSpan("i", "j", qux));
+ EXPECT_TRUE(HasSpan('a', 'k', baz));
+ EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+ EXPECT_TRUE(HasSpan('i', 'j', qux));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1802,13 +1933,13 @@ TEST_F(SourceInfoTest, Groups) {
TEST_F(SourceInfoTest, Enums) {
EXPECT_TRUE(Parse(
- "/*a*/enum /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/enum /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$enum $b$Foo$c$ {}$d$\n"
+ "$e$enum $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.enum_type(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.enum_type(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.enum_type(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.enum_type(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1817,19 +1948,19 @@ TEST_F(SourceInfoTest, Enums) {
TEST_F(SourceInfoTest, EnumValues) {
EXPECT_TRUE(Parse(
"enum Foo {\n"
- " /*a*/BAR/*b*/ = /*c*/1/*d*/;/*e*/\n"
- " /*f*/BAZ/*g*/ = /*h*/2/*i*/;/*j*/\n"
+ " $a$BAR$b$ = $c$1$d$;$e$\n"
+ " $f$BAZ$g$ = $h$2$i$;$j$\n"
"}"));
const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
- EXPECT_TRUE(HasSpan("a", "e", bar));
- EXPECT_TRUE(HasSpan("a", "b", bar, "name"));
- EXPECT_TRUE(HasSpan("c", "d", bar, "number"));
- EXPECT_TRUE(HasSpan("f", "j", baz));
- EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
- EXPECT_TRUE(HasSpan("h", "i", baz, "number"));
+ EXPECT_TRUE(HasSpan('a', 'e', bar));
+ EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
+ EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
+ EXPECT_TRUE(HasSpan('f', 'j', baz));
+ EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
+ EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1840,17 +1971,17 @@ TEST_F(SourceInfoTest, EnumValues) {
TEST_F(SourceInfoTest, NestedEnums) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/enum /*b*/Bar/*c*/ {}/*d*/\n"
- " /*e*/enum /*f*/Baz/*g*/ {}/*h*/\n"
+ " $a$enum $b$Bar$c$ {}$d$\n"
+ " $e$enum $f$Baz$g$ {}$h$\n"
"}\n"));
const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
- EXPECT_TRUE(HasSpan("a", "d", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("e", "h", baz));
- EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', baz));
+ EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1860,37 +1991,37 @@ TEST_F(SourceInfoTest, NestedEnums) {
TEST_F(SourceInfoTest, Services) {
EXPECT_TRUE(Parse(
- "/*a*/service /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/service /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$service $b$Foo$c$ {}$d$\n"
+ "$e$service $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.service(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.service(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.service(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.service(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
}
-TEST_F(SourceInfoTest, Methods) {
+TEST_F(SourceInfoTest, MethodsAndStreams) {
EXPECT_TRUE(Parse(
"service Foo {\n"
- " /*a*/rpc /*b*/Bar/*c*/(/*d*/X/*e*/) returns(/*f*/Y/*g*/);/*h*/"
- " /*i*/rpc /*j*/Baz/*k*/(/*l*/Z/*m*/) returns(/*n*/W/*o*/);/*p*/"
+ " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
+ " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
"}"));
const MethodDescriptorProto& bar = file_.service(0).method(0);
const MethodDescriptorProto& baz = file_.service(0).method(1);
- EXPECT_TRUE(HasSpan("a", "h", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("d", "e", bar, "input_type"));
- EXPECT_TRUE(HasSpan("f", "g", bar, "output_type"));
+ EXPECT_TRUE(HasSpan('a', 'h', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
+ EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
- EXPECT_TRUE(HasSpan("i", "p", baz));
- EXPECT_TRUE(HasSpan("j", "k", baz, "name"));
- EXPECT_TRUE(HasSpan("l", "m", baz, "input_type"));
- EXPECT_TRUE(HasSpan("n", "o", baz, "output_type"));
+ EXPECT_TRUE(HasSpan('i', 'p', baz));
+ EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
+ EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
+ EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1900,13 +2031,13 @@ TEST_F(SourceInfoTest, Methods) {
TEST_F(SourceInfoTest, Options) {
EXPECT_TRUE(Parse(
- "/*a*/option /*b*/foo/*c*/./*d*/(/*e*/bar.baz/*f*/)/*g*/ = "
- "/*h*/123/*i*/;/*j*/\n"
- "/*k*/option qux = /*l*/-123/*m*/;/*n*/\n"
- "/*o*/option corge = /*p*/abc/*q*/;/*r*/\n"
- "/*s*/option grault = /*t*/'blah'/*u*/;/*v*/\n"
- "/*w*/option garply = /*x*/{ yadda yadda }/*y*/;/*z*/\n"
- "/*0*/option waldo = /*1*/123.0/*2*/;/*3*/\n"
+ "$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
+ "$h$123$i$;$j$\n"
+ "$k$option qux = $l$-123$m$;$n$\n"
+ "$o$option corge = $p$abc$q$;$r$\n"
+ "$s$option grault = $t$'blah'$u$;$v$\n"
+ "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
+ "$0$option waldo = $1$123.0$2$;$3$\n"
));
const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
@@ -1916,29 +2047,29 @@ TEST_F(SourceInfoTest, Options) {
const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
- EXPECT_TRUE(HasSpan("a", "j", file_.options()));
- EXPECT_TRUE(HasSpan("b", "i", option1));
- EXPECT_TRUE(HasSpan("b", "g", option1, "name"));
- EXPECT_TRUE(HasSpan("b", "c", option1.name(0)));
- EXPECT_TRUE(HasSpan("b", "c", option1.name(0), "name_part"));
- EXPECT_TRUE(HasSpan("d", "g", option1.name(1)));
- EXPECT_TRUE(HasSpan("e", "f", option1.name(1), "name_part"));
- EXPECT_TRUE(HasSpan("h", "i", option1, "positive_int_value"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
+ EXPECT_TRUE(HasSpan('a', 'j', option1));
+ EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
+ EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
+ EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
+ EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
+ EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
- EXPECT_TRUE(HasSpan("k", "n", file_.options()));
- EXPECT_TRUE(HasSpan("l", "m", option2, "negative_int_value"));
+ EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
+ EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
- EXPECT_TRUE(HasSpan("o", "r", file_.options()));
- EXPECT_TRUE(HasSpan("p", "q", option3, "identifier_value"));
+ EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
+ EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
- EXPECT_TRUE(HasSpan("s", "v", file_.options()));
- EXPECT_TRUE(HasSpan("t", "u", option4, "string_value"));
+ EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
+ EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
- EXPECT_TRUE(HasSpan("w", "z", file_.options()));
- EXPECT_TRUE(HasSpan("x", "y", option5, "aggregate_value"));
+ EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
+ EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
- EXPECT_TRUE(HasSpan("0", "3", file_.options()));
- EXPECT_TRUE(HasSpan("1", "2", option6, "double_value"));
+ EXPECT_TRUE(HasSpan('0', '3', file_.options()));
+ EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1967,22 +2098,22 @@ TEST_F(SourceInfoTest, Options) {
TEST_F(SourceInfoTest, ScopedOptions) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/option mopt = 1;/*b*/\n"
+ " $a$option mopt = 1;$b$\n"
"}\n"
"enum Bar {\n"
- " /*c*/option eopt = 1;/*d*/\n"
+ " $c$option eopt = 1;$d$\n"
"}\n"
"service Baz {\n"
- " /*e*/option sopt = 1;/*f*/\n"
+ " $e$option sopt = 1;$f$\n"
" rpc M(X) returns(Y) {\n"
- " /*g*/option mopt = 1;/*h*/\n"
+ " $g$option mopt = 1;$h$\n"
" }\n"
"}\n"));
- EXPECT_TRUE(HasSpan("a", "b", file_.message_type(0).options()));
- EXPECT_TRUE(HasSpan("c", "d", file_.enum_type(0).options()));
- EXPECT_TRUE(HasSpan("e", "f", file_.service(0).options()));
- EXPECT_TRUE(HasSpan("g", "h", file_.service(0).method(0).options()));
+ EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
+ EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
+ EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
+ EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2045,8 +2176,8 @@ TEST_F(SourceInfoTest, FieldOptions) {
EXPECT_TRUE(Parse(
"message Foo {"
" optional int32 bar = 1 "
- "/*a*/[default=/*b*/123/*c*/,/*d*/opt1=123/*e*/,"
- "/*f*/opt2='hi'/*g*/]/*h*/;"
+ "$a$[default=$b$123$c$,$d$opt1=123$e$,"
+ "$f$opt2='hi'$g$]$h$;"
"}\n"
));
@@ -2054,10 +2185,10 @@ TEST_F(SourceInfoTest, FieldOptions) {
const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
- EXPECT_TRUE(HasSpan("a", "h", field.options()));
- EXPECT_TRUE(HasSpan("b", "c", field, "default_value"));
- EXPECT_TRUE(HasSpan("d", "e", option1));
- EXPECT_TRUE(HasSpan("f", "g", option2));
+ EXPECT_TRUE(HasSpan('a', 'h', field.options()));
+ EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
+ EXPECT_TRUE(HasSpan('d', 'e', option1));
+ EXPECT_TRUE(HasSpan('f', 'g', option2));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2084,7 +2215,7 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
// syntax used for enum options is understood.
EXPECT_TRUE(Parse(
"enum Foo {"
- " BAR = 1 /*a*/[/*b*/opt1=123/*c*/,/*d*/opt2='hi'/*e*/]/*f*/;"
+ " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
"}\n"
));
@@ -2092,9 +2223,9 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
- EXPECT_TRUE(HasSpan("a", "f", value.options()));
- EXPECT_TRUE(HasSpan("b", "c", option1));
- EXPECT_TRUE(HasSpan("d", "e", option2));
+ EXPECT_TRUE(HasSpan('a', 'f', value.options()));
+ EXPECT_TRUE(HasSpan('b', 'c', option1));
+ EXPECT_TRUE(HasSpan('d', 'e', option2));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2113,6 +2244,127 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
EXPECT_TRUE(HasSpan(option2, "string_value"));
}
+TEST_F(SourceInfoTest, DocComments) {
+ EXPECT_TRUE(Parse(
+ "// Foo leading\n"
+ "// line 2\n"
+ "$a$message Foo {\n"
+ " // Foo trailing\n"
+ " // line 2\n"
+ "\n"
+ " // ignored\n"
+ "\n"
+ " // bar leading\n"
+ " $b$optional int32 bar = 1;$c$\n"
+ " // bar trailing\n"
+ "}$d$\n"
+ "// ignored\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+
+ EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
+ " Foo leading\n line 2\n",
+ " Foo trailing\n line 2\n"));
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+}
+
+TEST_F(SourceInfoTest, DocComments2) {
+ EXPECT_TRUE(Parse(
+ "// ignored\n"
+ "syntax = \"proto2\";\n"
+ "// Foo leading\n"
+ "// line 2\n"
+ "$a$message Foo {\n"
+ " /* Foo trailing\n"
+ " * line 2 */\n"
+ " // ignored\n"
+ " /* bar leading\n"
+ " */"
+ " $b$optional int32 bar = 1;$c$ // bar trailing\n"
+ " // ignored\n"
+ "}$d$\n"
+ "// ignored\n"
+ "\n"
+ "// option leading\n"
+ "$e$option baz = 123;$f$\n"
+ "// option trailing\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+ const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
+
+ EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
+ " Foo leading\n line 2\n",
+ " Foo trailing\n line 2 "));
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n"));
+ EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
+ " option leading\n",
+ " option trailing\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+ EXPECT_TRUE(HasSpan(file_.options()));
+ EXPECT_TRUE(HasSpan(baz, "name"));
+ EXPECT_TRUE(HasSpan(baz.name(0)));
+ EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
+}
+
+TEST_F(SourceInfoTest, DocComments3) {
+ EXPECT_TRUE(Parse(
+ "$a$message Foo {\n"
+ " // bar leading\n"
+ " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
+ " // bar trailing\n"
+ "}$d$\n"
+ "// ignored\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+ EXPECT_TRUE(HasSpan(bar.options()));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
+ EXPECT_TRUE(HasSpan(
+ bar.options().uninterpreted_option(0).name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(
+ bar.options().uninterpreted_option(0), "aggregate_value"));
+}
+
// ===================================================================
} // anonymous namespace
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 7c403332..6fa2de12 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -56,7 +56,6 @@
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
#include <google/protobuf/stubs/common.h>
-
namespace google {
namespace protobuf {
namespace compiler {
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 05ff2f04..bc0c1f17 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -1,4 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: google/protobuf/compiler/plugin.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "google/protobuf/compiler/plugin.pb.h"
@@ -9,6 +10,7 @@
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
@@ -124,6 +126,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
if (already_here) return;
already_here = true;
GOOGLE_PROTOBUF_VERIFY_VERSION;
+
::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
"\n%google/protobuf/compiler/plugin.proto\022"
@@ -253,7 +256,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_parameter;
break;
}
-
+
// optional string parameter = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -270,7 +273,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
if (input->ExpectTag(122)) goto parse_proto_file;
break;
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
case 15: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -285,7 +288,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -312,7 +315,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->file_to_generate(i), output);
}
-
+
// optional string parameter = 2;
if (has_parameter()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -321,13 +324,13 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->parameter(), output);
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
for (int i = 0; i < this->proto_file_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
15, this->proto_file(i), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -344,7 +347,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteStringToArray(1, this->file_to_generate(i), target);
}
-
+
// optional string parameter = 2;
if (has_parameter()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -354,14 +357,14 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->parameter(), target);
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
for (int i = 0; i < this->proto_file_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
15, this->proto_file(i), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -371,7 +374,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
int CodeGeneratorRequest::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
// optional string parameter = 2;
if (has_parameter()) {
@@ -379,7 +382,7 @@ int CodeGeneratorRequest::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->parameter());
}
-
+
}
// repeated string file_to_generate = 1;
total_size += 1 * this->file_to_generate_size();
@@ -387,7 +390,7 @@ int CodeGeneratorRequest::ByteSize() const {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->file_to_generate(i));
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
total_size += 1 * this->proto_file_size();
for (int i = 0; i < this->proto_file_size(); i++) {
@@ -395,7 +398,7 @@ int CodeGeneratorRequest::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->proto_file(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -444,7 +447,7 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
}
bool CodeGeneratorRequest::IsInitialized() const {
-
+
for (int i = 0; i < proto_file_size(); i++) {
if (!this->proto_file(i).IsInitialized()) return false;
}
@@ -583,7 +586,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_insertion_point;
break;
}
-
+
// optional string insertion_point = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -600,7 +603,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
if (input->ExpectTag(122)) goto parse_content;
break;
}
-
+
// optional string content = 15;
case 15: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -617,7 +620,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -644,7 +647,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -653,7 +656,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->insertion_point(), output);
}
-
+
// optional string content = 15;
if (has_content()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -662,7 +665,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
15, this->content(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -680,7 +683,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -690,7 +693,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->insertion_point(), target);
}
-
+
// optional string content = 15;
if (has_content()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -700,7 +703,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
15, this->content(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -710,7 +713,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
int CodeGeneratorResponse_File::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -718,21 +721,21 @@ int CodeGeneratorResponse_File::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->insertion_point());
}
-
+
// optional string content = 15;
if (has_content()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->content());
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -786,7 +789,7 @@ void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from
}
bool CodeGeneratorResponse_File::IsInitialized() const {
-
+
return true;
}
@@ -904,7 +907,7 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
if (input->ExpectTag(122)) goto parse_file;
break;
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
case 15: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -919,7 +922,7 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -946,13 +949,13 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->error(), output);
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
for (int i = 0; i < this->file_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
15, this->file(i), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -970,14 +973,14 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->error(), target);
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
for (int i = 0; i < this->file_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
15, this->file(i), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -987,7 +990,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
int CodeGeneratorResponse::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string error = 1;
if (has_error()) {
@@ -995,7 +998,7 @@ int CodeGeneratorResponse::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->error());
}
-
+
}
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
total_size += 1 * this->file_size();
@@ -1004,7 +1007,7 @@ int CodeGeneratorResponse::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->file(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -1052,7 +1055,7 @@ void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) {
}
bool CodeGeneratorResponse::IsInitialized() const {
-
+
return true;
}
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 1cf8a556..46478c73 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -20,9 +20,10 @@
#endif
#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
#include "google/protobuf/descriptor.pb.h"
// @@protoc_insertion_point(includes)
@@ -45,29 +46,29 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
public:
CodeGeneratorRequest();
virtual ~CodeGeneratorRequest();
-
+
CodeGeneratorRequest(const CodeGeneratorRequest& from);
-
+
inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorRequest& default_instance();
-
+
void Swap(CodeGeneratorRequest* other);
-
+
// implements Message ----------------------------------------------
-
+
CodeGeneratorRequest* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -75,7 +76,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
void MergeFrom(const CodeGeneratorRequest& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -88,13 +89,13 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated string file_to_generate = 1;
inline int file_to_generate_size() const;
inline void clear_file_to_generate();
@@ -110,7 +111,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
inline void add_file_to_generate(const char* value, size_t size);
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
-
+
// optional string parameter = 2;
inline bool has_parameter() const;
inline void clear_parameter();
@@ -121,7 +122,8 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
inline void set_parameter(const char* value, size_t size);
inline ::std::string* mutable_parameter();
inline ::std::string* release_parameter();
-
+ inline void set_allocated_parameter(::std::string* parameter);
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
inline int proto_file_size() const;
inline void clear_proto_file();
@@ -133,25 +135,25 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
proto_file() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
mutable_proto_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
private:
inline void set_has_parameter();
inline void clear_has_parameter();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_;
::std::string* parameter_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
-
+
void InitAsDefaultInstance();
static CodeGeneratorRequest* default_instance_;
};
@@ -161,29 +163,29 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
public:
CodeGeneratorResponse_File();
virtual ~CodeGeneratorResponse_File();
-
+
CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from);
-
+
inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorResponse_File& default_instance();
-
+
void Swap(CodeGeneratorResponse_File* other);
-
+
// implements Message ----------------------------------------------
-
+
CodeGeneratorResponse_File* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -191,7 +193,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
void MergeFrom(const CodeGeneratorResponse_File& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -204,13 +206,13 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -221,7 +223,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// optional string insertion_point = 2;
inline bool has_insertion_point() const;
inline void clear_insertion_point();
@@ -232,7 +235,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
inline void set_insertion_point(const char* value, size_t size);
inline ::std::string* mutable_insertion_point();
inline ::std::string* release_insertion_point();
-
+ inline void set_allocated_insertion_point(::std::string* insertion_point);
+
// optional string content = 15;
inline bool has_content() const;
inline void clear_content();
@@ -243,7 +247,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
inline void set_content(const char* value, size_t size);
inline ::std::string* mutable_content();
inline ::std::string* release_content();
-
+ inline void set_allocated_content(::std::string* content);
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
private:
inline void set_has_name();
@@ -252,20 +257,20 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
inline void clear_has_insertion_point();
inline void set_has_content();
inline void clear_has_content();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::std::string* insertion_point_;
::std::string* content_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
-
+
void InitAsDefaultInstance();
static CodeGeneratorResponse_File* default_instance_;
};
@@ -275,29 +280,29 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
public:
CodeGeneratorResponse();
virtual ~CodeGeneratorResponse();
-
+
CodeGeneratorResponse(const CodeGeneratorResponse& from);
-
+
inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorResponse& default_instance();
-
+
void Swap(CodeGeneratorResponse* other);
-
+
// implements Message ----------------------------------------------
-
+
CodeGeneratorResponse* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -305,7 +310,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
void MergeFrom(const CodeGeneratorResponse& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -318,15 +323,15 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef CodeGeneratorResponse_File File;
-
+
// accessors -------------------------------------------------------
-
+
// optional string error = 1;
inline bool has_error() const;
inline void clear_error();
@@ -337,7 +342,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
inline void set_error(const char* value, size_t size);
inline ::std::string* mutable_error();
inline ::std::string* release_error();
-
+ inline void set_allocated_error(::std::string* error);
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
inline int file_size() const;
inline void clear_file();
@@ -349,24 +355,24 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
file() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
mutable_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
private:
inline void set_has_error();
inline void clear_has_error();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* error_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
-
+
void InitAsDefaultInstance();
static CodeGeneratorResponse* default_instance_;
};
@@ -478,6 +484,18 @@ inline ::std::string* CodeGeneratorRequest::release_parameter() {
return temp;
}
}
+inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+ if (parameter_ != &::google::protobuf::internal::kEmptyString) {
+ delete parameter_;
+ }
+ if (parameter) {
+ set_has_parameter();
+ parameter_ = parameter;
+ } else {
+ clear_has_parameter();
+ parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
inline int CodeGeneratorRequest::proto_file_size() const {
@@ -565,6 +583,18 @@ inline ::std::string* CodeGeneratorResponse_File::release_name() {
return temp;
}
}
+inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string insertion_point = 2;
inline bool CodeGeneratorResponse_File::has_insertion_point() const {
@@ -623,6 +653,18 @@ inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
return temp;
}
}
+inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+ if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
+ delete insertion_point_;
+ }
+ if (insertion_point) {
+ set_has_insertion_point();
+ insertion_point_ = insertion_point;
+ } else {
+ clear_has_insertion_point();
+ insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string content = 15;
inline bool CodeGeneratorResponse_File::has_content() const {
@@ -681,6 +723,18 @@ inline ::std::string* CodeGeneratorResponse_File::release_content() {
return temp;
}
}
+inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+ if (content_ != &::google::protobuf::internal::kEmptyString) {
+ delete content_;
+ }
+ if (content) {
+ set_has_content();
+ content_ = content;
+ } else {
+ clear_has_content();
+ content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// -------------------------------------------------------------------
@@ -743,6 +797,18 @@ inline ::std::string* CodeGeneratorResponse::release_error() {
return temp;
}
}
+inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+ if (error_ != &::google::protobuf::internal::kEmptyString) {
+ delete error_;
+ }
+ if (error) {
+ set_has_error();
+ error_ = error;
+ } else {
+ clear_has_error();
+ error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
inline int CodeGeneratorResponse::file_size() const {
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 9b109378..211ac70c 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -52,6 +52,7 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -106,6 +107,12 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
const char kDescriptorKey[] = "DESCRIPTOR";
+// Does the file have top-level enums?
+inline bool HasTopLevelEnums(const FileDescriptor *file) {
+ return file->enum_type_count() > 0;
+}
+
+
// Should we generate generic services for this file?
inline bool HasGenericServices(const FileDescriptor *file) {
return file->service_count() > 0 &&
@@ -120,13 +127,21 @@ void PrintTopBoilerplate(
// TODO(robinson): Allow parameterization of Python version?
printer->Print(
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "\n"
- "from google.protobuf import descriptor\n"
- "from google.protobuf import message\n"
- "from google.protobuf import reflection\n");
+ "# source: $filename$\n"
+ "\n",
+ "filename", file->name());
+ if (HasTopLevelEnums(file)) {
+ printer->Print(
+ "from google.protobuf.internal import enum_type_wrapper\n");
+ }
+ printer->Print(
+ "from google.protobuf import descriptor as _descriptor\n"
+ "from google.protobuf import message as _message\n"
+ "from google.protobuf import reflection as _reflection\n"
+ );
if (HasGenericServices(file)) {
printer->Print(
- "from google.protobuf import service\n"
+ "from google.protobuf import service as _service\n"
"from google.protobuf import service_reflection\n");
}
@@ -204,12 +219,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_STRING:
if (field.type() == FieldDescriptor::TYPE_STRING) {
return "unicode(\"" + CEscape(field.default_value_string()) +
- "\", \"utf-8\")";
+ "\", \"utf-8\")";
} else {
return "\"" + CEscape(field.default_value_string()) + "\"";
}
- case FieldDescriptor::CPPTYPE_MESSAGE:
- return "None";
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return "None";
}
// (We could add a default case above but then we wouldn't get the nice
// compiler warning when a new type is added.)
@@ -270,6 +285,11 @@ bool Generator::Generate(const FileDescriptor* file,
// since they need to call static RegisterExtension() methods on these
// classes.
FixForeignFieldsInExtensions();
+ // Descriptor options may have custom extensions. These custom options
+ // can only be successfully parsed after we register corresponding
+ // extensions. Therefore we parse all options again here to recognize
+ // custom options that may be unknown when we define the descriptors.
+ FixAllDescriptorOptions();
if (HasGenericServices(file)) {
PrintServices();
}
@@ -288,6 +308,13 @@ void Generator::PrintImports() const {
module_name);
}
printer_->Print("\n");
+
+ // Print public imports.
+ for (int i = 0; i < file_->public_dependency_count(); ++i) {
+ string module_name = ModuleName(file_->public_dependency(i)->name());
+ printer_->Print("from $module$ import *\n", "module", module_name);
+ }
+ printer_->Print("\n");
}
// Prints the single file descriptor for this file.
@@ -297,7 +324,7 @@ void Generator::PrintFileDescriptor() const {
m["name"] = file_->name();
m["package"] = file_->package();
const char file_descriptor_template[] =
- "$descriptor_name$ = descriptor.FileDescriptor(\n"
+ "$descriptor_name$ = _descriptor.FileDescriptor(\n"
" name='$name$',\n"
" package='$package$',\n";
printer_->Print(m, file_descriptor_template);
@@ -321,6 +348,11 @@ void Generator::PrintTopLevelEnums() const {
for (int i = 0; i < file_->enum_type_count(); ++i) {
const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
PrintEnum(enum_descriptor);
+ printer_->Print("$name$ = "
+ "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)",
+ "name", enum_descriptor.name(),
+ "descriptor_name",
+ ModuleLevelDescriptorName(enum_descriptor));
printer_->Print("\n");
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
@@ -355,7 +387,7 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
m["full_name"] = enum_descriptor.full_name();
m["file"] = kDescriptorKey;
const char enum_descriptor_template[] =
- "$descriptor_name$ = descriptor.EnumDescriptor(\n"
+ "$descriptor_name$ = _descriptor.EnumDescriptor(\n"
" name='$name$',\n"
" full_name='$full_name$',\n"
" filename=None,\n"
@@ -436,7 +468,7 @@ void Generator::PrintServiceDescriptor(
descriptor.options().SerializeToString(&options_string);
printer_->Print(
- "$service_name$ = descriptor.ServiceDescriptor(\n",
+ "$service_name$ = _descriptor.ServiceDescriptor(\n",
"service_name", service_name);
printer_->Indent();
map<string, string> m;
@@ -459,7 +491,6 @@ void Generator::PrintServiceDescriptor(
printer_->Print("methods=[\n");
for (int i = 0; i < descriptor.method_count(); ++i) {
const MethodDescriptor* method = descriptor.method(i);
- string options_string;
method->options().SerializeToString(&options_string);
m.clear();
@@ -470,7 +501,7 @@ void Generator::PrintServiceDescriptor(
m["input_type"] = ModuleLevelDescriptorName(*(method->input_type()));
m["output_type"] = ModuleLevelDescriptorName(*(method->output_type()));
m["options_value"] = OptionsValue("MethodOptions", options_string);
- printer_->Print("descriptor.MethodDescriptor(\n");
+ printer_->Print("_descriptor.MethodDescriptor(\n");
printer_->Indent();
printer_->Print(
m,
@@ -491,7 +522,7 @@ void Generator::PrintServiceDescriptor(
void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
// Print the service.
- printer_->Print("class $class_name$(service.Service):\n",
+ printer_->Print("class $class_name$(_service.Service):\n",
"class_name", descriptor.name());
printer_->Indent();
printer_->Print(
@@ -523,7 +554,7 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
PrintNestedDescriptors(message_descriptor);
printer_->Print("\n");
- printer_->Print("$descriptor_name$ = descriptor.Descriptor(\n",
+ printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n",
"descriptor_name",
ModuleLevelDescriptorName(message_descriptor));
printer_->Indent();
@@ -618,10 +649,10 @@ void Generator::PrintMessages() const {
// Mutually recursive with PrintNestedMessages().
void Generator::PrintMessage(
const Descriptor& message_descriptor) const {
- printer_->Print("class $name$(message.Message):\n", "name",
+ printer_->Print("class $name$(_message.Message):\n", "name",
message_descriptor.name());
printer_->Indent();
- printer_->Print("__metaclass__ = reflection.GeneratedProtocolMessageType\n");
+ printer_->Print("__metaclass__ = _reflection.GeneratedProtocolMessageType\n");
PrintNestedMessages(message_descriptor);
map<string, string> m;
m["descriptor_key"] = kDescriptorKey;
@@ -779,6 +810,7 @@ void Generator::FixForeignFieldsInExtensions() const {
for (int i = 0; i < file_->message_type_count(); ++i) {
FixForeignFieldsInNestedExtensions(*file_->message_type(i));
}
+ printer_->Print("\n");
}
void Generator::FixForeignFieldsInExtension(
@@ -829,7 +861,7 @@ void Generator::PrintEnumValueDescriptor(
m["options"] = OptionsValue("EnumValueOptions", options_string);
printer_->Print(
m,
- "descriptor.EnumValueDescriptor(\n"
+ "_descriptor.EnumValueDescriptor(\n"
" name='$name$', index=$index$, number=$number$,\n"
" options=$options$,\n"
" type=None)");
@@ -843,7 +875,7 @@ string Generator::OptionsValue(
return "None";
} else {
string full_class_name = "descriptor_pb2." + class_name;
- return "descriptor._ParseOptions(" + full_class_name + "(), '"
+ return "_descriptor._ParseOptions(" + full_class_name + "(), '"
+ CEscape(serialized_options)+ "')";
}
}
@@ -869,7 +901,7 @@ void Generator::PrintFieldDescriptor(
// these fields in correctly after all referenced descriptors have been
// defined and/or imported (see FixForeignFieldsInDescriptors()).
const char field_descriptor_decl[] =
- "descriptor.FieldDescriptor(\n"
+ "_descriptor.FieldDescriptor(\n"
" name='$name$', full_name='$full_name$', index=$index$,\n"
" number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n"
" has_default_value=$has_default_value$, default_value=$default_value$,\n"
@@ -1000,6 +1032,125 @@ void Generator::PrintSerializedPbInterval(
"serialized_end", SimpleItoa(offset + sp.size()));
}
+namespace {
+void PrintDescriptorOptionsFixingCode(const string& descriptor,
+ const string& options,
+ io::Printer* printer) {
+ // TODO(xiaofeng): I have added a method _SetOptions() to DescriptorBase
+ // in proto2 python runtime but it couldn't be used here because appengine
+ // uses a snapshot version of the library in which the new method is not
+ // yet present. After appengine has synced their runtime library, the code
+ // below should be cleaned up to use _SetOptions().
+ printer->Print(
+ "$descriptor$.has_options = True\n"
+ "$descriptor$._options = $options$\n",
+ "descriptor", descriptor, "options", options);
+}
+} // namespace
+
+// Prints expressions that set the options field of all descriptors.
+void Generator::FixAllDescriptorOptions() const {
+ // Prints an expression that sets the file descriptor's options.
+ string file_options = OptionsValue(
+ "FileOptions", file_->options().SerializeAsString());
+ if (file_options != "None") {
+ PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_);
+ }
+ // Prints expressions that set the options for all top level enums.
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
+ FixOptionsForEnum(enum_descriptor);
+ }
+ // Prints expressions that set the options for all top level extensions.
+ for (int i = 0; i < file_->extension_count(); ++i) {
+ const FieldDescriptor& field = *file_->extension(i);
+ FixOptionsForField(field);
+ }
+ // Prints expressions that set the options for all messages, nested enums,
+ // nested extensions and message fields.
+ for (int i = 0; i < file_->message_type_count(); ++i) {
+ FixOptionsForMessage(*file_->message_type(i));
+ }
+}
+
+// Prints expressions that set the options for an enum descriptor and its
+// value descriptors.
+void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
+ string descriptor_name = ModuleLevelDescriptorName(enum_descriptor);
+ string enum_options = OptionsValue(
+ "EnumOptions", enum_descriptor.options().SerializeAsString());
+ if (enum_options != "None") {
+ PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_);
+ }
+ for (int i = 0; i < enum_descriptor.value_count(); ++i) {
+ const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i);
+ string value_options = OptionsValue(
+ "EnumValueOptions", value_descriptor.options().SerializeAsString());
+ if (value_options != "None") {
+ PrintDescriptorOptionsFixingCode(
+ StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(),
+ value_descriptor.name().c_str()),
+ value_options, printer_);
+ }
+ }
+}
+
+// Prints expressions that set the options for field descriptors (including
+// extensions).
+void Generator::FixOptionsForField(
+ const FieldDescriptor& field) const {
+ string field_options = OptionsValue(
+ "FieldOptions", field.options().SerializeAsString());
+ if (field_options != "None") {
+ string field_name;
+ if (field.is_extension()) {
+ if (field.extension_scope() == NULL) {
+ // Top level extensions.
+ field_name = field.name();
+ } else {
+ field_name = FieldReferencingExpression(
+ field.extension_scope(), field, "extensions_by_name");
+ }
+ } else {
+ field_name = FieldReferencingExpression(
+ field.containing_type(), field, "fields_by_name");
+ }
+ PrintDescriptorOptionsFixingCode(field_name, field_options, printer_);
+ }
+}
+
+// Prints expressions that set the options for a message and all its inner
+// types (nested messages, nested enums, extensions, fields).
+void Generator::FixOptionsForMessage(const Descriptor& descriptor) const {
+ // Nested messages.
+ for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+ FixOptionsForMessage(*descriptor.nested_type(i));
+ }
+ // Enums.
+ for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+ FixOptionsForEnum(*descriptor.enum_type(i));
+ }
+ // Fields.
+ for (int i = 0; i < descriptor.field_count(); ++i) {
+ const FieldDescriptor& field = *descriptor.field(i);
+ FixOptionsForField(field);
+ }
+ // Extensions.
+ for (int i = 0; i < descriptor.extension_count(); ++i) {
+ const FieldDescriptor& field = *descriptor.extension(i);
+ FixOptionsForField(field);
+ }
+ // Message option for this message.
+ string message_options = OptionsValue(
+ "MessageOptions", descriptor.options().SerializeAsString());
+ if (message_options != "None") {
+ string descriptor_name = ModuleLevelDescriptorName(descriptor);
+ PrintDescriptorOptionsFixingCode(descriptor_name,
+ message_options,
+ printer_);
+ }
+}
+
} // namespace python
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index 84eaf8ab..a3f22cee 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -138,6 +138,11 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void PrintSerializedPbInterval(
const DescriptorT& descriptor, DescriptorProtoT& proto) const;
+ void FixAllDescriptorOptions() const;
+ void FixOptionsForField(const FieldDescriptor& field) const;
+ void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
+ void FixOptionsForMessage(const Descriptor& descriptor) const;
+
// Very coarse-grained lock to ensure that Generate() is reentrant.
// Guards file_, printer_ and file_descriptor_serialized_.
mutable Mutex mutex_;
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 5fb5d5cb..860fc875 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -33,6 +33,7 @@
#include <google/protobuf/compiler/subprocess.h>
#include <algorithm>
+#include <iostream>
#ifndef _WIN32
#include <errno.h>
diff --git a/src/google/protobuf/compiler/subprocess.h b/src/google/protobuf/compiler/subprocess.h
index 00564964..de9fce9e 100644
--- a/src/google/protobuf/compiler/subprocess.h
+++ b/src/google/protobuf/compiler/subprocess.h
@@ -53,7 +53,7 @@ class Message;
namespace compiler {
// Utility class for launching sub-processes.
-class LIBPROTOC_EXPORT Subprocess {
+class Subprocess {
public:
Subprocess();
~Subprocess();
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 754b5628..a60abf43 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -54,7 +54,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
#undef PACKAGE // autoheader #defines this. :(
@@ -108,6 +108,21 @@ const char * const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
"sint64", // TYPE_SINT64
};
+const char * const FieldDescriptor::kCppTypeToName[MAX_CPPTYPE + 1] = {
+ "ERROR", // 0 is reserved for errors
+
+ "int32", // CPPTYPE_INT32
+ "int64", // CPPTYPE_INT64
+ "uint32", // CPPTYPE_UINT32
+ "uint64", // CPPTYPE_UINT64
+ "double", // CPPTYPE_DOUBLE
+ "float", // CPPTYPE_FLOAT
+ "bool", // CPPTYPE_BOOL
+ "enum", // CPPTYPE_ENUM
+ "string", // CPPTYPE_STRING
+ "message", // CPPTYPE_MESSAGE
+};
+
const char * const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = {
"ERROR", // 0 is reserved for errors
@@ -221,7 +236,8 @@ struct PointerStringPairHash {
struct Symbol {
enum Type {
- NULL_SYMBOL, MESSAGE, FIELD, ENUM, ENUM_VALUE, SERVICE, METHOD, PACKAGE
+ NULL_SYMBOL, MESSAGE, FIELD, ENUM, ENUM_VALUE, SERVICE, METHOD,
+ PACKAGE
};
Type type;
union {
@@ -311,17 +327,42 @@ class DescriptorPool::Tables {
Tables();
~Tables();
- // Checkpoint the state of the tables. Future calls to Rollback() will
- // return the Tables to this state. This is used when building files, since
- // some kinds of validation errors cannot be detected until the file's
- // descriptors have already been added to the tables. BuildFile() calls
- // Checkpoint() before it starts building and Rollback() if it encounters
- // an error.
- void Checkpoint();
+ // Record the current state of the tables to the stack of checkpoints.
+ // Each call to AddCheckpoint() must be paired with exactly one call to either
+ // ClearLastCheckpoint() or RollbackToLastCheckpoint().
+ //
+ // This is used when building files, since some kinds of validation errors
+ // cannot be detected until the file's descriptors have already been added to
+ // the tables.
+ //
+ // This supports recursive checkpoints, since building a file may trigger
+ // recursive building of other files. Note that recursive checkpoints are not
+ // normally necessary; explicit dependencies are built prior to checkpointing.
+ // So although we recursively build transitive imports, there is at most one
+ // checkpoint in the stack during dependency building.
+ //
+ // Recursive checkpoints only arise during cross-linking of the descriptors.
+ // Symbol references must be resolved, via DescriptorBuilder::FindSymbol and
+ // friends. If the pending file references an unknown symbol
+ // (e.g., it is not defined in the pending file's explicit dependencies), and
+ // the pool is using a fallback database, and that database contains a file
+ // defining that symbol, and that file has not yet been built by the pool,
+ // the pool builds the file during cross-linking, leading to another
+ // checkpoint.
+ void AddCheckpoint();
+
+ // Mark the last checkpoint as having cleared successfully, removing it from
+ // the stack. If the stack is empty, all pending symbols will be committed.
+ //
+ // Note that this does not guarantee that the symbols added since the last
+ // checkpoint won't be rolled back: if a checkpoint gets rolled back,
+ // everything past that point gets rolled back, including symbols added after
+ // checkpoints that were pushed onto the stack after it and marked as cleared.
+ void ClearLastCheckpoint();
- // Roll back the Tables to the state of the last Checkpoint(), removing
- // everything that was added after that point.
- void Rollback();
+ // Roll back the Tables to the state of the checkpoint at the top of the
+ // stack, removing everything that was added after that point.
+ void RollbackToLastCheckpoint();
// The stack of files which are currently being built. Used to detect
// cyclic dependencies when loading files from a DescriptorDatabase. Not
@@ -405,10 +446,28 @@ class DescriptorPool::Tables {
FilesByNameMap files_by_name_;
ExtensionsGroupedByDescriptorMap extensions_;
- int strings_before_checkpoint_;
- int messages_before_checkpoint_;
- int file_tables_before_checkpoint_;
- int allocations_before_checkpoint_;
+ struct CheckPoint {
+ explicit CheckPoint(const Tables* tables)
+ : strings_before_checkpoint(tables->strings_.size()),
+ messages_before_checkpoint(tables->messages_.size()),
+ file_tables_before_checkpoint(tables->file_tables_.size()),
+ allocations_before_checkpoint(tables->allocations_.size()),
+ pending_symbols_before_checkpoint(
+ tables->symbols_after_checkpoint_.size()),
+ pending_files_before_checkpoint(
+ tables->files_after_checkpoint_.size()),
+ pending_extensions_before_checkpoint(
+ tables->extensions_after_checkpoint_.size()) {
+ }
+ int strings_before_checkpoint;
+ int messages_before_checkpoint;
+ int file_tables_before_checkpoint;
+ int allocations_before_checkpoint;
+ int pending_symbols_before_checkpoint;
+ int pending_files_before_checkpoint;
+ int pending_extensions_before_checkpoint;
+ };
+ vector<CheckPoint> checkpoints_;
vector<const char* > symbols_after_checkpoint_;
vector<const char* > files_after_checkpoint_;
vector<DescriptorIntPair> extensions_after_checkpoint_;
@@ -481,11 +540,15 @@ class FileDescriptorTables {
};
DescriptorPool::Tables::Tables()
- : strings_before_checkpoint_(0),
- messages_before_checkpoint_(0),
- allocations_before_checkpoint_(0) {}
+ // Start some hash_map and hash_set objects with a small # of buckets
+ : known_bad_files_(3),
+ extensions_loaded_from_db_(3),
+ symbols_by_name_(3),
+ files_by_name_(3) {}
+
DescriptorPool::Tables::~Tables() {
+ GOOGLE_DCHECK(checkpoints_.empty());
// Note that the deletion order is important, since the destructors of some
// messages may refer to objects in allocations_.
STLDeleteElements(&messages_);
@@ -496,51 +559,80 @@ DescriptorPool::Tables::~Tables() {
STLDeleteElements(&file_tables_);
}
-FileDescriptorTables::FileDescriptorTables() {}
+FileDescriptorTables::FileDescriptorTables()
+ // Initialize all the hash tables to start out with a small # of buckets
+ : symbols_by_parent_(3),
+ fields_by_lowercase_name_(3),
+ fields_by_camelcase_name_(3),
+ fields_by_number_(3),
+ enum_values_by_number_(3) {
+}
+
FileDescriptorTables::~FileDescriptorTables() {}
const FileDescriptorTables FileDescriptorTables::kEmpty;
-void DescriptorPool::Tables::Checkpoint() {
- strings_before_checkpoint_ = strings_.size();
- messages_before_checkpoint_ = messages_.size();
- file_tables_before_checkpoint_ = file_tables_.size();
- allocations_before_checkpoint_ = allocations_.size();
+void DescriptorPool::Tables::AddCheckpoint() {
+ checkpoints_.push_back(CheckPoint(this));
+}
- symbols_after_checkpoint_.clear();
- files_after_checkpoint_.clear();
- extensions_after_checkpoint_.clear();
+void DescriptorPool::Tables::ClearLastCheckpoint() {
+ GOOGLE_DCHECK(!checkpoints_.empty());
+ checkpoints_.pop_back();
+ if (checkpoints_.empty()) {
+ // All checkpoints have been cleared: we can now commit all of the pending
+ // data.
+ symbols_after_checkpoint_.clear();
+ files_after_checkpoint_.clear();
+ extensions_after_checkpoint_.clear();
+ }
}
-void DescriptorPool::Tables::Rollback() {
- for (int i = 0; i < symbols_after_checkpoint_.size(); i++) {
+void DescriptorPool::Tables::RollbackToLastCheckpoint() {
+ GOOGLE_DCHECK(!checkpoints_.empty());
+ const CheckPoint& checkpoint = checkpoints_.back();
+
+ for (int i = checkpoint.pending_symbols_before_checkpoint;
+ i < symbols_after_checkpoint_.size();
+ i++) {
symbols_by_name_.erase(symbols_after_checkpoint_[i]);
}
- for (int i = 0; i < files_after_checkpoint_.size(); i++) {
+ for (int i = checkpoint.pending_files_before_checkpoint;
+ i < files_after_checkpoint_.size();
+ i++) {
files_by_name_.erase(files_after_checkpoint_[i]);
}
- for (int i = 0; i < extensions_after_checkpoint_.size(); i++) {
+ for (int i = checkpoint.pending_extensions_before_checkpoint;
+ i < extensions_after_checkpoint_.size();
+ i++) {
extensions_.erase(extensions_after_checkpoint_[i]);
}
- symbols_after_checkpoint_.clear();
- files_after_checkpoint_.clear();
- extensions_after_checkpoint_.clear();
+ symbols_after_checkpoint_.resize(
+ checkpoint.pending_symbols_before_checkpoint);
+ files_after_checkpoint_.resize(checkpoint.pending_files_before_checkpoint);
+ extensions_after_checkpoint_.resize(
+ checkpoint.pending_extensions_before_checkpoint);
STLDeleteContainerPointers(
- strings_.begin() + strings_before_checkpoint_, strings_.end());
+ strings_.begin() + checkpoint.strings_before_checkpoint, strings_.end());
STLDeleteContainerPointers(
- messages_.begin() + messages_before_checkpoint_, messages_.end());
+ messages_.begin() + checkpoint.messages_before_checkpoint,
+ messages_.end());
STLDeleteContainerPointers(
- file_tables_.begin() + file_tables_before_checkpoint_, file_tables_.end());
- for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) {
+ file_tables_.begin() + checkpoint.file_tables_before_checkpoint,
+ file_tables_.end());
+ for (int i = checkpoint.allocations_before_checkpoint;
+ i < allocations_.size();
+ i++) {
operator delete(allocations_[i]);
}
- strings_.resize(strings_before_checkpoint_);
- messages_.resize(messages_before_checkpoint_);
- file_tables_.resize(file_tables_before_checkpoint_);
- allocations_.resize(allocations_before_checkpoint_);
+ strings_.resize(checkpoint.strings_before_checkpoint);
+ messages_.resize(checkpoint.messages_before_checkpoint);
+ file_tables_.resize(checkpoint.file_tables_before_checkpoint);
+ allocations_.resize(checkpoint.allocations_before_checkpoint);
+ checkpoints_.pop_back();
}
// -------------------------------------------------------------------
@@ -811,7 +903,7 @@ void DeleteGeneratedPool() {
generated_pool_ = NULL;
}
-void InitGeneratedPool() {
+static void InitGeneratedPool() {
generated_database_ = new EncodedDescriptorDatabase;
generated_pool_ = new DescriptorPool(generated_database_);
@@ -874,11 +966,11 @@ const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
const FileDescriptor* result = tables_->FindFile(name);
if (result != NULL) return result;
if (underlay_ != NULL) {
- const FileDescriptor* result = underlay_->FindFileByName(name);
+ result = underlay_->FindFileByName(name);
if (result != NULL) return result;
}
if (TryFindFileInFallbackDatabase(name)) {
- const FileDescriptor* result = tables_->FindFile(name);
+ result = tables_->FindFile(name);
if (result != NULL) return result;
}
return NULL;
@@ -890,12 +982,12 @@ const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
Symbol result = tables_->FindSymbol(symbol_name);
if (!result.IsNull()) return result.GetFile();
if (underlay_ != NULL) {
- const FileDescriptor* result =
+ const FileDescriptor* file_result =
underlay_->FindFileContainingSymbol(symbol_name);
- if (result != NULL) return result;
+ if (file_result != NULL) return file_result;
}
if (TryFindSymbolInFallbackDatabase(symbol_name)) {
- Symbol result = tables_->FindSymbol(symbol_name);
+ result = tables_->FindSymbol(symbol_name);
if (!result.IsNull()) return result.GetFile();
}
return NULL;
@@ -962,12 +1054,11 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
return result;
}
if (underlay_ != NULL) {
- const FieldDescriptor* result =
- underlay_->FindExtensionByNumber(extendee, number);
+ result = underlay_->FindExtensionByNumber(extendee, number);
if (result != NULL) return result;
}
if (TryFindExtensionInFallbackDatabase(extendee, number)) {
- const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+ result = tables_->FindExtension(extendee, number);
if (result != NULL) {
return result;
}
@@ -1241,9 +1332,48 @@ bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
return true;
}
+bool DescriptorPool::IsSubSymbolOfBuiltType(const string& name) const {
+ string prefix = name;
+ for (;;) {
+ string::size_type dot_pos = prefix.find_last_of('.');
+ if (dot_pos == string::npos) {
+ break;
+ }
+ prefix = prefix.substr(0, dot_pos);
+ Symbol symbol = tables_->FindSymbol(prefix);
+ // If the symbol type is anything other than PACKAGE, then its complete
+ // definition is already known.
+ if (!symbol.IsNull() && symbol.type != Symbol::PACKAGE) {
+ return true;
+ }
+ }
+ if (underlay_ != NULL) {
+ // Check to see if any prefix of this symbol exists in the underlay.
+ return underlay_->IsSubSymbolOfBuiltType(name);
+ }
+ return false;
+}
+
bool DescriptorPool::TryFindSymbolInFallbackDatabase(const string& name) const {
if (fallback_database_ == NULL) return false;
+ // We skip looking in the fallback database if the name is a sub-symbol of
+ // any descriptor that already exists in the descriptor pool (except for
+ // package descriptors). This is valid because all symbols except for
+ // packages are defined in a single file, so if the symbol exists then we
+ // should already have its definition.
+ //
+ // The other reason to do this is to support "overriding" type definitions
+ // by merging two databases that define the same type. (Yes, people do
+ // this.) The main difficulty with making this work is that
+ // FindFileContainingSymbol() is allowed to return both false positives
+ // (e.g., SimpleDescriptorDatabase, UpgradedDescriptorDatabase) and false
+ // negatives (e.g. ProtoFileParser, SourceTreeDescriptorDatabase). When two
+ // such databases are merged, looking up a non-existent sub-symbol of a type
+ // that already exists in the descriptor pool can result in an attempt to
+ // load multiple definitions of the same type. The check below avoids this.
+ if (IsSubSymbolOfBuiltType(name)) return false;
+
FileDescriptorProto file_proto;
if (!fallback_database_->FindFileContainingSymbol(name, &file_proto)) {
return false;
@@ -1345,6 +1475,14 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
proto->add_dependency(dependency(i)->name());
}
+ for (int i = 0; i < public_dependency_count(); i++) {
+ proto->add_public_dependency(public_dependencies_[i]);
+ }
+
+ for (int i = 0; i < weak_dependency_count(); i++) {
+ proto->add_weak_dependency(weak_dependencies_[i]);
+ }
+
for (int i = 0; i < message_type_count(); i++) {
message_type(i)->CopyTo(proto->add_message_type());
}
@@ -1363,6 +1501,12 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
}
}
+void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
+ if (source_code_info_ != &SourceCodeInfo::default_instance()) {
+ proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
+ }
+}
+
void Descriptor::CopyTo(DescriptorProto* proto) const {
proto->set_name(name());
@@ -1490,16 +1634,14 @@ void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
namespace {
// Used by each of the option formatters.
-bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
+bool RetrieveOptions(int depth,
+ const Message &options,
+ vector<string> *option_entries) {
option_entries->clear();
const Reflection* reflection = options.GetReflection();
vector<const FieldDescriptor*> fields;
reflection->ListFields(options, &fields);
for (int i = 0; i < fields.size(); i++) {
- // Doesn't make sense to have message type fields here
- if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- continue;
- }
int count = 1;
bool repeated = false;
if (fields[i]->is_repeated()) {
@@ -1508,9 +1650,27 @@ bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
}
for (int j = 0; j < count; j++) {
string fieldval;
- TextFormat::PrintFieldValueToString(options, fields[i],
- repeated ? count : -1, &fieldval);
- option_entries->push_back(fields[i]->name() + " = " + fieldval);
+ if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ string tmp;
+ TextFormat::Printer printer;
+ printer.SetInitialIndentLevel(depth + 1);
+ printer.PrintFieldValueToString(options, fields[i],
+ repeated ? j : -1, &tmp);
+ fieldval.append("{\n");
+ fieldval.append(tmp);
+ fieldval.append(depth * 2, ' ');
+ fieldval.append("}");
+ } else {
+ TextFormat::PrintFieldValueToString(options, fields[i],
+ repeated ? j : -1, &fieldval);
+ }
+ string name;
+ if (fields[i]->is_extension()) {
+ name = "(." + fields[i]->full_name() + ")";
+ } else {
+ name = fields[i]->name();
+ }
+ option_entries->push_back(name + " = " + fieldval);
}
}
return !option_entries->empty();
@@ -1518,9 +1678,9 @@ bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
// Formats options that all appear together in brackets. Does not include
// brackets.
-bool FormatBracketedOptions(const Message &options, string *output) {
+bool FormatBracketedOptions(int depth, const Message &options, string *output) {
vector<string> all_options;
- if (RetrieveOptions(options, &all_options)) {
+ if (RetrieveOptions(depth, options, &all_options)) {
output->append(JoinStrings(all_options, ", "));
}
return !all_options.empty();
@@ -1530,7 +1690,7 @@ bool FormatBracketedOptions(const Message &options, string *output) {
bool FormatLineOptions(int depth, const Message &options, string *output) {
string prefix(depth * 2, ' ');
vector<string> all_options;
- if (RetrieveOptions(options, &all_options)) {
+ if (RetrieveOptions(depth, options, &all_options)) {
for (int i = 0; i < all_options.size(); i++) {
strings::SubstituteAndAppend(output, "$0option $1;\n",
prefix, all_options[i]);
@@ -1544,9 +1704,24 @@ bool FormatLineOptions(int depth, const Message &options, string *output) {
string FileDescriptor::DebugString() const {
string contents = "syntax = \"proto2\";\n\n";
+ set<int> public_dependencies;
+ set<int> weak_dependencies;
+ public_dependencies.insert(public_dependencies_,
+ public_dependencies_ + public_dependency_count_);
+ weak_dependencies.insert(weak_dependencies_,
+ weak_dependencies_ + weak_dependency_count_);
+
for (int i = 0; i < dependency_count(); i++) {
- strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
- dependency(i)->name());
+ if (public_dependencies.count(i) > 0) {
+ strings::SubstituteAndAppend(&contents, "import public \"$0\";\n",
+ dependency(i)->name());
+ } else if (weak_dependencies.count(i) > 0) {
+ strings::SubstituteAndAppend(&contents, "import weak \"$0\";\n",
+ dependency(i)->name());
+ } else {
+ strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
+ dependency(i)->name());
+ }
}
if (!package().empty()) {
@@ -1712,7 +1887,7 @@ void FieldDescriptor::DebugString(int depth, string *contents) const {
}
string formatted_options;
- if (FormatBracketedOptions(options(), &formatted_options)) {
+ if (FormatBracketedOptions(depth, options(), &formatted_options)) {
contents->append(bracketed ? ", " : " [");
bracketed = true;
contents->append(formatted_options);
@@ -1761,7 +1936,7 @@ void EnumValueDescriptor::DebugString(int depth, string *contents) const {
prefix, name(), number());
string formatted_options;
- if (FormatBracketedOptions(options(), &formatted_options)) {
+ if (FormatBracketedOptions(depth, options(), &formatted_options)) {
strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
}
contents->append(";\n");
@@ -1807,6 +1982,126 @@ void MethodDescriptor::DebugString(int depth, string *contents) const {
contents->append(";\n");
}
}
+
+
+// Location methods ===============================================
+
+static bool PathsEqual(const vector<int>& x, const RepeatedField<int32>& y) {
+ if (x.size() != y.size()) return false;
+ for (int i = 0; i < x.size(); ++i) {
+ if (x[i] != y.Get(i)) return false;
+ }
+ return true;
+}
+
+bool FileDescriptor::GetSourceLocation(const vector<int>& path,
+ SourceLocation* out_location) const {
+ GOOGLE_CHECK_NOTNULL(out_location);
+ const SourceCodeInfo* info = source_code_info_;
+ for (int i = 0; info && i < info->location_size(); ++i) {
+ if (PathsEqual(path, info->location(i).path())) {
+ const RepeatedField<int32>& span = info->location(i).span();
+ if (span.size() == 3 || span.size() == 4) {
+ out_location->start_line = span.Get(0);
+ out_location->start_column = span.Get(1);
+ out_location->end_line = span.Get(span.size() == 3 ? 0 : 2);
+ out_location->end_column = span.Get(span.size() - 1);
+
+ out_location->leading_comments = info->location(i).leading_comments();
+ out_location->trailing_comments = info->location(i).trailing_comments();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool FieldDescriptor::is_packed() const {
+ return is_packable() && (options_ != NULL) && options_->packed();
+}
+
+bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool MethodDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return service()->file()->GetSourceLocation(path, out_location);
+}
+
+bool ServiceDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumValueDescriptor::GetSourceLocation(
+ SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return type()->file()->GetSourceLocation(path, out_location);
+}
+
+void Descriptor::GetLocationPath(vector<int>* output) const {
+ if (containing_type()) {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kNestedTypeFieldNumber);
+ output->push_back(index());
+ } else {
+ output->push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ output->push_back(index());
+ }
+}
+
+void FieldDescriptor::GetLocationPath(vector<int>* output) const {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kFieldFieldNumber);
+ output->push_back(index());
+}
+
+void EnumDescriptor::GetLocationPath(vector<int>* output) const {
+ if (containing_type()) {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kEnumTypeFieldNumber);
+ output->push_back(index());
+ } else {
+ output->push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+ output->push_back(index());
+ }
+}
+
+void EnumValueDescriptor::GetLocationPath(vector<int>* output) const {
+ type()->GetLocationPath(output);
+ output->push_back(EnumDescriptorProto::kValueFieldNumber);
+ output->push_back(index());
+}
+
+void ServiceDescriptor::GetLocationPath(vector<int>* output) const {
+ output->push_back(FileDescriptorProto::kServiceFieldNumber);
+ output->push_back(index());
+}
+
+void MethodDescriptor::GetLocationPath(vector<int>* output) const {
+ service()->GetLocationPath(output);
+ output->push_back(ServiceDescriptorProto::kMethodFieldNumber);
+ output->push_back(index());
+}
+
// ===================================================================
namespace {
@@ -1859,6 +2154,7 @@ class DescriptorBuilder {
string filename_;
FileDescriptor* file_;
FileDescriptorTables* file_tables_;
+ set<const FileDescriptor*> dependencies_;
// If LookupSymbol() finds a symbol that is in a file which is not a declared
// dependency of this file, it will fail, but will set
@@ -1888,6 +2184,10 @@ class DescriptorBuilder {
// nested package within package_name.
bool IsInPackage(const FileDescriptor* file, const string& package_name);
+ // Helper function which finds all public dependencies of the given file, and
+ // stores the them in the dependencies_ set in the builder.
+ void RecordPublicDependencies(const FileDescriptor* file);
+
// Like tables_->FindSymbol(), but additionally:
// - Search the pool's underlay if not found in tables_.
// - Insure that the resulting Symbol is from one of the file's declared
@@ -1898,6 +2198,10 @@ class DescriptorBuilder {
// file's declared dependencies.
Symbol FindSymbolNotEnforcingDeps(const string& name);
+ // This implements the body of FindSymbolNotEnforcingDeps().
+ Symbol FindSymbolNotEnforcingDepsHelper(const DescriptorPool* pool,
+ const string& name);
+
// Like FindSymbol(), but looks up the name relative to some other symbol
// name. This first searches siblings of relative_to, then siblings of its
// parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes
@@ -2189,6 +2493,7 @@ class DescriptorBuilder {
void ValidateMapKey(FieldDescriptor* field,
const FieldDescriptorProto& proto);
+
};
const FileDescriptor* DescriptorPool::BuildFile(
@@ -2275,31 +2580,48 @@ bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
file->package()[package_name.size()] == '.');
}
-Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) {
- Symbol result;
+void DescriptorBuilder::RecordPublicDependencies(const FileDescriptor* file) {
+ if (file == NULL || !dependencies_.insert(file).second) return;
+ for (int i = 0; file != NULL && i < file->public_dependency_count(); i++) {
+ RecordPublicDependencies(file->public_dependency(i));
+ }
+}
- // We need to search our pool and all its underlays.
- const DescriptorPool* pool = pool_;
- while (true) {
- // If we are looking at an underlay, we must lock its mutex_, since we are
- // accessing the underlay's tables_ dircetly.
- MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDepsHelper(
+ const DescriptorPool* pool, const string& name) {
+ // If we are looking at an underlay, we must lock its mutex_, since we are
+ // accessing the underlay's tables_ directly.
+ MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
+
+ Symbol result = pool->tables_->FindSymbol(name);
+ if (result.IsNull() && pool->underlay_ != NULL) {
+ // Symbol not found; check the underlay.
+ result = FindSymbolNotEnforcingDepsHelper(pool->underlay_, name);
+ }
- // Note that we don't have to check fallback_database_ here because the
- // symbol has to be in one of its file's direct dependencies, and we have
- // already loaded those by the time we get here.
- result = pool->tables_->FindSymbol(name);
- if (!result.IsNull()) break;
- if (pool->underlay_ == NULL) return kNullSymbol;
- pool = pool->underlay_;
+ if (result.IsNull()) {
+ // In theory, we shouldn't need to check fallback_database_ because the
+ // symbol should be in one of its file's direct dependencies, and we have
+ // already loaded those by the time we get here. But we check anyway so
+ // that we can generate better error message when dependencies are missing
+ // (i.e., "missing dependency" rather than "type is not defined").
+ if (pool->TryFindSymbolInFallbackDatabase(name)) {
+ result = pool->tables_->FindSymbol(name);
+ }
}
return result;
}
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) {
+ return FindSymbolNotEnforcingDepsHelper(pool_, name);
+}
+
Symbol DescriptorBuilder::FindSymbol(const string& name) {
Symbol result = FindSymbolNotEnforcingDeps(name);
+ if (result.IsNull()) return result;
+
if (!pool_->enforce_dependencies_) {
// Hack for CompilerUpgrader.
return result;
@@ -2308,10 +2630,7 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
// Only find symbols which were defined in this file or one of its
// dependencies.
const FileDescriptor* file = result.GetFile();
- if (file == file_) return result;
- for (int i = 0; i < file_->dependency_count(); i++) {
- if (file == file_->dependency(i)) return result;
- }
+ if (file == file_ || dependencies_.count(file) > 0) return result;
if (result.type == Symbol::PACKAGE) {
// Arg, this is overcomplicated. The symbol is a package name. It could
@@ -2322,12 +2641,10 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
// dependency also defines the same package. We can't really rule out this
// symbol unless none of the dependencies define it.
if (IsInPackage(file_, name)) return result;
- for (int i = 0; i < file_->dependency_count(); i++) {
+ for (set<const FileDescriptor*>::const_iterator it = dependencies_.begin();
+ it != dependencies_.end(); ++it) {
// Note: A dependency may be NULL if it was not found or had errors.
- if (file_->dependency(i) != NULL &&
- IsInPackage(file_->dependency(i), name)) {
- return result;
- }
+ if (*it != NULL && IsInPackage(*it, name)) return result;
}
}
@@ -2448,6 +2765,8 @@ Symbol DescriptorBuilder::NewPlaceholder(const string& name,
FileDescriptor* placeholder_file = tables_->Allocate<FileDescriptor>();
memset(placeholder_file, 0, sizeof(*placeholder_file));
+ placeholder_file->source_code_info_ = &SourceCodeInfo::default_instance();
+
placeholder_file->name_ =
tables_->AllocateString(*placeholder_full_name + ".placeholder.proto");
placeholder_file->package_ = placeholder_package;
@@ -2757,11 +3076,19 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
}
// Checkpoint the tables so that we can roll back if something goes wrong.
- tables_->Checkpoint();
+ tables_->AddCheckpoint();
FileDescriptor* result = tables_->Allocate<FileDescriptor>();
file_ = result;
+ if (proto.has_source_code_info()) {
+ SourceCodeInfo *info = tables_->AllocateMessage<SourceCodeInfo>();
+ info->CopyFrom(proto.source_code_info());
+ result->source_code_info_ = info;
+ } else {
+ result->source_code_info_ = &SourceCodeInfo::default_instance();
+ }
+
file_tables_ = tables_->AllocateFileTables();
file_->tables_ = file_tables_;
@@ -2788,7 +3115,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
"A file with this name is already in the pool.");
// Bail out early so that if this is actually the exact same file, we
// don't end up reporting that every single symbol is already defined.
- tables_->Rollback();
+ tables_->RollbackToLastCheckpoint();
return NULL;
}
if (!result->package().empty()) {
@@ -2833,6 +3160,45 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
result->dependencies_[i] = dependency;
}
+ // Check public dependencies.
+ int public_dependency_count = 0;
+ result->public_dependencies_ = tables_->AllocateArray<int>(
+ proto.public_dependency_size());
+ for (int i = 0; i < proto.public_dependency_size(); i++) {
+ // Only put valid public dependency indexes.
+ int index = proto.public_dependency(i);
+ if (index >= 0 && index < proto.dependency_size()) {
+ result->public_dependencies_[public_dependency_count++] = index;
+ } else {
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Invalid public dependency index.");
+ }
+ }
+ result->public_dependency_count_ = public_dependency_count;
+
+ // Build dependency set
+ dependencies_.clear();
+ for (int i = 0; i < result->dependency_count(); i++) {
+ RecordPublicDependencies(result->dependency(i));
+ }
+
+ // Check weak dependencies.
+ int weak_dependency_count = 0;
+ result->weak_dependencies_ = tables_->AllocateArray<int>(
+ proto.weak_dependency_size());
+ for (int i = 0; i < proto.weak_dependency_size(); i++) {
+ int index = proto.weak_dependency(i);
+ if (index >= 0 && index < proto.dependency_size()) {
+ result->weak_dependencies_[weak_dependency_count++] = index;
+ } else {
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Invalid weak dependency index.");
+ }
+ }
+ result->weak_dependency_count_ = weak_dependency_count;
+
// Convert children.
BUILD_ARRAY(proto, result, message_type, BuildMessage , NULL);
BUILD_ARRAY(proto, result, enum_type , BuildEnum , NULL);
@@ -2870,10 +3236,10 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
}
if (had_errors_) {
- tables_->Rollback();
+ tables_->RollbackToLastCheckpoint();
return NULL;
} else {
- tables_->Checkpoint();
+ tables_->ClearLastCheckpoint();
return result;
}
}
@@ -3065,7 +3431,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
UnescapeCEscapeString(proto.default_value()));
} else {
result->default_value_string_ =
- tables_->AllocateString(proto.default_value());
+ tables_->AllocateString(proto.default_value());
}
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -3126,7 +3492,15 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
if (result->number() <= 0) {
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
"Field numbers must be positive integers.");
- } else if (result->number() > FieldDescriptor::kMaxNumber) {
+ } else if (!is_extension && result->number() > FieldDescriptor::kMaxNumber) {
+ // Only validate that the number is within the valid field range if it is
+ // not an extension. Since extension numbers are validated with the
+ // extendee's valid set of extension numbers, and those are in turn
+ // validated against the max allowed number, the check is unnecessary for
+ // extension fields.
+ // This avoids cross-linking issues that arise when attempting to check if
+ // the extendee is a message_set_wire_format message, which has a higher max
+ // on extension numbers.
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
strings::Substitute("Field numbers cannot be greater than $0.",
FieldDescriptor::kMaxNumber));
@@ -3181,12 +3555,10 @@ void DescriptorBuilder::BuildExtensionRange(
"Extension numbers must be positive integers.");
}
- if (result->end > FieldDescriptor::kMaxNumber + 1) {
- AddError(parent->full_name(), proto,
- DescriptorPool::ErrorCollector::NUMBER,
- strings::Substitute("Extension numbers cannot be greater than $0.",
- FieldDescriptor::kMaxNumber));
- }
+ // Checking of the upper bound of the extension range is deferred until after
+ // options interpreting. This allows messages with message_set_wire_format to
+ // have extensions beyond FieldDescriptor::kMaxNumber, since the extension
+ // numbers are actually used as int32s in the message_set_wire_format.
if (result->start >= result->end) {
AddError(parent->full_name(), proto,
@@ -3681,6 +4053,20 @@ void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message);
VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
+
+ const int64 max_extension_range =
+ static_cast<int64>(message->options().message_set_wire_format() ?
+ kint32max :
+ FieldDescriptor::kMaxNumber);
+ for (int i = 0; i < message->extension_range_count(); ++i) {
+ if (message->extension_range(i)->end > max_extension_range + 1) {
+ AddError(
+ message->full_name(), proto.extension_range(i),
+ DescriptorPool::ErrorCollector::NUMBER,
+ strings::Substitute("Extension numbers cannot be greater than $0.",
+ max_extension_range));
+ }
+ }
}
void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
@@ -3689,6 +4075,15 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
ValidateMapKey(field, proto);
}
+ // Only message type fields may be lazy.
+ if (field->options().lazy()) {
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "[lazy = true] can only be specified for submessage fields.");
+ }
+ }
+
// Only repeated primitive fields may be packed.
if (field->options().packed() && !field->is_packable()) {
AddError(
@@ -3727,11 +4122,27 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
"files. Note that you cannot extend a non-lite type to contain "
"a lite type, but the reverse is allowed.");
}
+
}
void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
const EnumDescriptorProto& proto) {
VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
+ if (!enm->options().allow_alias()) {
+ map<int, string> used_values;
+ for (int i = 0; i < enm->value_count(); ++i) {
+ const EnumValueDescriptor* enum_value = enm->value(i);
+ if (used_values.find(enum_value->number()) != used_values.end()) {
+ AddError(enm->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER,
+ "\"" + enum_value->full_name() +
+ "\" uses the same enum value as \"" +
+ used_values[enum_value->number()] + "\"");
+ } else {
+ used_values[enum_value->number()] = enum_value->full_name();
+ }
+ }
+ }
}
void DescriptorBuilder::ValidateEnumValueOptions(
@@ -3811,6 +4222,7 @@ void DescriptorBuilder::ValidateMapKey(FieldDescriptor* field,
field->experimental_map_key_ = key_field;
}
+
#undef VALIDATE_OPTIONS_FROM_ARRAY
// -------------------------------------------------------------------
@@ -3901,9 +4313,11 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// file we're currently building. The descriptor should be there as long as
// the file we're building imported "google/protobuf/descriptors.proto".
- // Note that we use DescriptorBuilder::FindSymbol(), not
+ // Note that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
// DescriptorPool::FindMessageTypeByName() because we're already holding the
- // pool's mutex, and the latter method locks it again.
+ // pool's mutex, and the latter method locks it again. We don't use
+ // FindSymbol() because files that use custom options only need to depend on
+ // the file that defines the option, not descriptor.proto itself.
Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
options->GetDescriptor()->full_name());
if (!symbol.IsNull() && symbol.type == Symbol::MESSAGE) {
@@ -3939,8 +4353,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows
// relative lookups, and 2) because we're already holding the pool's
// mutex, and the latter method locks it again.
- Symbol symbol = builder_->LookupSymbol(name_part,
- options_to_interpret_->name_scope);
+ symbol = builder_->LookupSymbol(name_part,
+ options_to_interpret_->name_scope);
if (!symbol.IsNull() && symbol.type == Symbol::FIELD) {
field = symbol.field_descriptor;
}
@@ -4344,14 +4758,32 @@ class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
virtual const FieldDescriptor* FindExtension(
Message* message, const string& name) const {
assert_mutex_held(builder_->pool_);
+ const Descriptor* descriptor = message->GetDescriptor();
Symbol result = builder_->LookupSymbolNoPlaceholder(
- name, message->GetDescriptor()->full_name());
+ name, descriptor->full_name());
if (result.type == Symbol::FIELD &&
result.field_descriptor->is_extension()) {
return result.field_descriptor;
- } else {
- return NULL;
+ } else if (result.type == Symbol::MESSAGE &&
+ descriptor->options().message_set_wire_format()) {
+ const Descriptor* foreign_type = result.descriptor;
+ // The text format allows MessageSet items to be specified using
+ // the type name, rather than the extension identifier. If the symbol
+ // lookup returned a Message, and the enclosing Message has
+ // message_set_wire_format = true, then return the message set
+ // extension, if one exists.
+ for (int i = 0; i < foreign_type->extension_count(); i++) {
+ const FieldDescriptor* extension = foreign_type->extension(i);
+ if (extension->containing_type() == descriptor &&
+ extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+ extension->is_optional() &&
+ extension->message_type() == foreign_type) {
+ // Found it.
+ return extension;
+ }
+ }
}
+ return NULL;
}
};
@@ -4409,7 +4841,13 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
} else {
string serial;
dynamic->SerializeToString(&serial); // Never fails
- unknown_fields->AddLengthDelimited(option_field->number(), serial);
+ if (option_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ unknown_fields->AddLengthDelimited(option_field->number(), serial);
+ } else {
+ GOOGLE_CHECK_EQ(option_field->type(), FieldDescriptor::TYPE_GROUP);
+ UnknownFieldSet* group = unknown_fields->AddGroup(option_field->number());
+ group->ParseFromString(serial);
+ }
return true;
}
}
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 7f87dd80..410d3ed4 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -89,6 +89,7 @@ class ServiceOptions;
class MethodOptions;
class FileOptions;
class UninterpretedOption;
+class SourceCodeInfo;
// Defined in message.h
class Message;
@@ -100,6 +101,20 @@ class FileDescriptorTables;
// Defined in unknown_field_set.h.
class UnknownField;
+// NB, all indices are zero-based.
+struct SourceLocation {
+ int start_line;
+ int end_line;
+ int start_column;
+ int end_column;
+
+ // Doc comments found at the source location.
+ // TODO(kenton): Maybe this struct should have been named SourceInfo or
+ // something instead. Oh well.
+ string leading_comments;
+ string trailing_comments;
+};
+
// Describes a type of protocol message, or a particular group within a
// message. To obtain the Descriptor for a given message object, call
// Message::GetDescriptor(). Generated message classes also have a
@@ -236,6 +251,13 @@ class LIBPROTOBUF_EXPORT Descriptor {
// this message type's scope.
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this message declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef MessageOptions OptionsType;
@@ -243,6 +265,10 @@ class LIBPROTOBUF_EXPORT Descriptor {
// correct depth
void DebugString(int depth, string *contents) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const FileDescriptor* file_;
@@ -388,15 +414,19 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
// when parsing formats which prefer to use camel-case naming style.
const string& camelcase_name() const;
- Type type() const; // Declared type of this field.
- CppType cpp_type() const; // C++ type of this field.
- Label label() const; // optional/required/repeated
+ Type type() const; // Declared type of this field.
+ const char* type_name() const; // Name of the declared type.
+ CppType cpp_type() const; // C++ type of this field.
+ const char* cpp_type_name() const; // Name of the C++ type.
+ Label label() const; // optional/required/repeated
bool is_required() const; // shorthand for label() == LABEL_REQUIRED
bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL
bool is_repeated() const; // shorthand for label() == LABEL_REPEATED
bool is_packable() const; // shorthand for is_repeated() &&
// IsTypePackable(type())
+ bool is_packed() const; // shorthand for is_packable() &&
+ // options().packed()
// Index of this field within the message's field array, or the file or
// extension scope's extensions array.
@@ -479,6 +509,13 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
// Return true iff [packed = true] is valid for fields of this type.
static inline bool IsTypePackable(Type field_type);
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this field declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef FieldOptions OptionsType;
@@ -490,6 +527,10 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
// types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped.
string DefaultValueAsString(bool quote_string_type) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const string* lowercase_name_;
@@ -527,6 +568,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
static const char * const kTypeToName[MAX_TYPE + 1];
+ static const char * const kCppTypeToName[MAX_CPPTYPE + 1];
+
static const char * const kLabelToName[MAX_LABEL + 1];
// Must be constructed using DescriptorPool.
@@ -583,12 +626,23 @@ class LIBPROTOBUF_EXPORT EnumDescriptor {
// See Descriptor::DebugString().
string DebugString() const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this enum declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef EnumOptions OptionsType;
// See Descriptor::DebugString().
void DebugString(int depth, string *contents) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const FileDescriptor* file_;
@@ -650,12 +704,23 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor {
// See Descriptor::DebugString().
string DebugString() const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this enum value declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef EnumValueOptions OptionsType;
// See Descriptor::DebugString().
void DebugString(int depth, string *contents) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
int number_;
@@ -703,19 +768,29 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor {
// Look up a MethodDescriptor by name.
const MethodDescriptor* FindMethodByName(const string& name) const;
-
// See Descriptor::CopyTo().
void CopyTo(ServiceDescriptorProto* proto) const;
// See Descriptor::DebugString().
string DebugString() const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this service declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef ServiceOptions OptionsType;
// See Descriptor::DebugString().
void DebugString(string *contents) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const FileDescriptor* file_;
@@ -768,12 +843,23 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
// See Descriptor::DebugString().
string DebugString() const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this method declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef MethodOptions OptionsType;
// See Descriptor::DebugString().
void DebugString(int depth, string *contents) const;
+ // Walks up the descriptor tree to generate the source location path
+ // to this descriptor from the file root.
+ void GetLocationPath(vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const ServiceDescriptor* service_;
@@ -791,6 +877,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
};
+
// Describes a whole .proto file. To get the FileDescriptor for a compiled-in
// file, get the descriptor for something defined in that file and call
// descriptor->file(). Use DescriptorPool to construct your own descriptors.
@@ -813,6 +900,22 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
// These are returned in the order they were defined in the .proto file.
const FileDescriptor* dependency(int index) const;
+ // The number of files public imported by this one.
+ // The public dependency list is a subset of the dependency list.
+ int public_dependency_count() const;
+ // Gets a public imported file by index, where 0 <= index <
+ // public_dependency_count().
+ // These are returned in the order they were defined in the .proto file.
+ const FileDescriptor* public_dependency(int index) const;
+
+ // The number of files that are imported for weak fields.
+ // The weak dependency list is a subset of the dependency list.
+ int weak_dependency_count() const;
+ // Gets a weak imported file by index, where 0 <= index <
+ // weak_dependency_count().
+ // These are returned in the order they were defined in the .proto file.
+ const FileDescriptor* weak_dependency(int index) const;
+
// Number of top-level message types defined in this file. (This does not
// include nested types.)
int message_type_count() const;
@@ -866,12 +969,28 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
// See Descriptor::CopyTo().
+ // Notes:
+ // - This method does NOT copy source code information since it is relatively
+ // large and rarely needed. See CopySourceCodeInfoTo() below.
void CopyTo(FileDescriptorProto* proto) const;
+ // Write the source code information of this FileDescriptor into the given
+ // FileDescriptorProto. See CopyTo() above.
+ void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
// See Descriptor::DebugString().
string DebugString() const;
private:
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of the declaration or declaration-part denoted by |path|.
+ // Returns false and leaves |*out_location| unchanged iff location
+ // information was not available. (See SourceCodeInfo for
+ // description of path encoding.)
+ bool GetSourceLocation(const vector<int>& path,
+ SourceLocation* out_location) const;
+
typedef FileOptions OptionsType;
const string* name_;
@@ -879,6 +998,10 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const DescriptorPool* pool_;
int dependency_count_;
const FileDescriptor** dependencies_;
+ int public_dependency_count_;
+ int* public_dependencies_;
+ int weak_dependency_count_;
+ int* weak_dependencies_;
int message_type_count_;
Descriptor* message_types_;
int enum_type_count_;
@@ -890,6 +1013,7 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const FileOptions* options_;
const FileDescriptorTables* tables_;
+ const SourceCodeInfo* source_code_info_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
// descriptor.cc and update them to initialize the field.
@@ -899,6 +1023,8 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
friend class Descriptor;
friend class FieldDescriptor;
friend class EnumDescriptor;
+ friend class EnumValueDescriptor;
+ friend class MethodDescriptor;
friend class ServiceDescriptor;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
};
@@ -1106,7 +1232,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// For internal use only: Gets a non-const pointer to the generated pool.
// This is called at static-initialization time only, so thread-safety is
// not a concern. If both an underlay and a fallback database are present,
- // the fallback database takes precedence.
+ // the underlay takes precedence.
static DescriptorPool* internal_generated_pool();
// For internal use only: Changes the behavior of BuildFile() such that it
@@ -1132,6 +1258,11 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
friend class FileDescriptor;
friend class DescriptorBuilder;
+ // Return true if the given name is a sub-symbol of any non-package
+ // descriptor that already exists in the descriptor pool. (The full
+ // definition of such types is already known.)
+ bool IsSubSymbolOfBuiltType(const string& name) const;
+
// Tries to find something in the fallback database and link in the
// corresponding proto file. Returns true if successful, in which case
// the caller should search for the thing again. These are declared
@@ -1262,11 +1393,12 @@ 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_STRING_ACCESSOR(FileDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
@@ -1342,10 +1474,18 @@ inline int MethodDescriptor::index() const {
return this - service_->methods_;
}
+inline const char* FieldDescriptor::type_name() const {
+ return kTypeToName[type_];
+}
+
inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
return kTypeToCppTypeMap[type_];
}
+inline const char* FieldDescriptor::cpp_type_name() const {
+ return kCppTypeToName[kTypeToCppTypeMap[type_]];
+}
+
inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) {
return kTypeToCppTypeMap[type];
}
@@ -1361,6 +1501,16 @@ inline const FileDescriptor* FileDescriptor::dependency(int index) const {
return dependencies_[index];
}
+inline const FileDescriptor* FileDescriptor::public_dependency(
+ int index) const {
+ return dependencies_[public_dependencies_[index]];
+}
+
+inline const FileDescriptor* FileDescriptor::weak_dependency(
+ int index) const {
+ return dependencies_[weak_dependencies_[index]];
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index b0f0e90e..bb438f25 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1,4 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "google/protobuf/descriptor.pb.h"
@@ -9,6 +10,7 @@
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
@@ -108,10 +110,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
::google::protobuf::MessageFactory::generated_factory(),
sizeof(FileDescriptorSet));
FileDescriptorProto_descriptor_ = file->message_type(1);
- static const int FileDescriptorProto_offsets_[9] = {
+ static const int FileDescriptorProto_offsets_[11] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, dependency_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, public_dependency_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, weak_dependency_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, message_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, enum_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, service_),
@@ -261,12 +265,13 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
::google::protobuf::MessageFactory::generated_factory(),
sizeof(MethodDescriptorProto));
FileOptions_descriptor_ = file->message_type(8);
- static const int FileOptions_offsets_[9] = {
+ static const int FileOptions_offsets_[10] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generate_equals_and_hash_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, go_package_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_),
@@ -302,11 +307,13 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
::google::protobuf::MessageFactory::generated_factory(),
sizeof(MessageOptions));
FieldOptions_descriptor_ = file->message_type(10);
- static const int FieldOptions_offsets_[5] = {
+ static const int FieldOptions_offsets_[7] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, lazy_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, weak_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_),
};
FieldOptions_reflection_ =
@@ -322,7 +329,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(FieldOptions));
FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
EnumOptions_descriptor_ = file->message_type(11);
- static const int EnumOptions_offsets_[1] = {
+ static const int EnumOptions_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, uninterpreted_option_),
};
EnumOptions_reflection_ =
@@ -434,9 +442,11 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
::google::protobuf::MessageFactory::generated_factory(),
sizeof(SourceCodeInfo));
SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0);
- static const int SourceCodeInfo_Location_offsets_[2] = {
+ static const int SourceCodeInfo_Location_offsets_[4] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, span_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, leading_comments_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, trailing_comments_),
};
SourceCodeInfo_Location_reflection_ =
new ::google::protobuf::internal::GeneratedMessageReflection(
@@ -553,106 +563,112 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
if (already_here) return;
already_here = true;
GOOGLE_PROTOBUF_VERIFY_VERSION;
+
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
"\n google/protobuf/descriptor.proto\022\017goog"
"le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
"\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
- "roto\"\227\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
+ "roto\"\313\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
"(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022"
- "6\n\014message_type\030\004 \003(\0132 .google.protobuf."
- "DescriptorProto\0227\n\tenum_type\030\005 \003(\0132$.goo"
- "gle.protobuf.EnumDescriptorProto\0228\n\007serv"
- "ice\030\006 \003(\0132\'.google.protobuf.ServiceDescr"
- "iptorProto\0228\n\textension\030\007 \003(\0132%.google.p"
- "rotobuf.FieldDescriptorProto\022-\n\007options\030"
- "\010 \001(\0132\034.google.protobuf.FileOptions\0229\n\020s"
- "ource_code_info\030\t \001(\0132\037.google.protobuf."
- "SourceCodeInfo\"\251\003\n\017DescriptorProto\022\014\n\004na"
- "me\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.google.protobu"
- "f.FieldDescriptorProto\0228\n\textension\030\006 \003("
+ "\031\n\021public_dependency\030\n \003(\005\022\027\n\017weak_depen"
+ "dency\030\013 \003(\005\0226\n\014message_type\030\004 \003(\0132 .goog"
+ "le.protobuf.DescriptorProto\0227\n\tenum_type"
+ "\030\005 \003(\0132$.google.protobuf.EnumDescriptorP"
+ "roto\0228\n\007service\030\006 \003(\0132\'.google.protobuf."
+ "ServiceDescriptorProto\0228\n\textension\030\007 \003("
"\0132%.google.protobuf.FieldDescriptorProto"
- "\0225\n\013nested_type\030\003 \003(\0132 .google.protobuf."
- "DescriptorProto\0227\n\tenum_type\030\004 \003(\0132$.goo"
- "gle.protobuf.EnumDescriptorProto\022H\n\017exte"
- "nsion_range\030\005 \003(\0132/.google.protobuf.Desc"
- "riptorProto.ExtensionRange\0220\n\007options\030\007 "
- "\001(\0132\037.google.protobuf.MessageOptions\032,\n\016"
- "ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001"
- "(\005\"\224\005\n\024FieldDescriptorProto\022\014\n\004name\030\001 \001("
- "\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.googl"
- "e.protobuf.FieldDescriptorProto.Label\0228\n"
- "\004type\030\005 \001(\0162*.google.protobuf.FieldDescr"
- "iptorProto.Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010ex"
- "tendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001(\t\022.\n\007o"
- "ptions\030\010 \001(\0132\035.google.protobuf.FieldOpti"
- "ons\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FL"
- "OAT\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\n"
- "TYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_EN"
- "UM\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\"C\n\005"
- "Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LABEL_REQUI"
- "RED\020\002\022\022\n\016LABEL_REPEATED\020\003\"\214\001\n\023EnumDescri"
- "ptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132)"
- ".google.protobuf.EnumValueDescriptorProt"
- "o\022-\n\007options\030\003 \001(\0132\034.google.protobuf.Enu"
- "mOptions\"l\n\030EnumValueDescriptorProto\022\014\n\004"
- "name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007options\030\003 "
- "\001(\0132!.google.protobuf.EnumValueOptions\"\220"
- "\001\n\026ServiceDescriptorProto\022\014\n\004name\030\001 \001(\t\022"
- "6\n\006method\030\002 \003(\0132&.google.protobuf.Method"
- "DescriptorProto\0220\n\007options\030\003 \001(\0132\037.googl"
- "e.protobuf.ServiceOptions\"\177\n\025MethodDescr"
- "iptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput_type\030\002"
- " \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007options\030\004 \001"
- "(\0132\036.google.protobuf.MethodOptions\"\325\003\n\013F"
- "ileOptions\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java"
- "_outer_classname\030\010 \001(\t\022\"\n\023java_multiple_"
- "files\030\n \001(\010:\005false\022,\n\035java_generate_equa"
- "ls_and_hash\030\024 \001(\010:\005false\022F\n\014optimize_for"
- "\030\t \001(\0162).google.protobuf.FileOptions.Opt"
- "imizeMode:\005SPEED\022\"\n\023cc_generic_services\030"
- "\020 \001(\010:\005false\022$\n\025java_generic_services\030\021 "
- "\001(\010:\005false\022\"\n\023py_generic_services\030\022 \001(\010:"
- "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
- "google.protobuf.UninterpretedOption\":\n\014O"
- "ptimizeMode\022\t\n\005SPEED\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\"\270\001\n\016MessageOp"
- "tions\022&\n\027message_set_wire_format\030\001 \001(\010:\005"
- "false\022.\n\037no_standard_descriptor_accessor"
- "\030\002 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007"
- " \003(\0132$.google.protobuf.UninterpretedOpti"
- "on*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptions\022:\n\005ctype\030"
- "\001 \001(\0162#.google.protobuf.FieldOptions.CTy"
- "pe:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031\n\ndeprecated"
- "\030\003 \001(\010:\005false\022\034\n\024experimental_map_key\030\t "
- "\001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
- "gle.protobuf.UninterpretedOption\"/\n\005CTyp"
- "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020"
- "\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpr"
- "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni"
- "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValue"
- "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$"
- ".google.protobuf.UninterpretedOption*\t\010\350"
- "\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpret"
- "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint"
- "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptio"
- "ns\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog"
- "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200"
- "\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\013"
- "2-.google.protobuf.UninterpretedOption.N"
- "amePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022pos"
- "itive_int_value\030\004 \001(\004\022\032\n\022negative_int_va"
- "lue\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014strin"
- "g_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_exte"
- "nsion\030\002 \002(\010\"|\n\016SourceCodeInfo\022:\n\010locatio"
- "n\030\001 \003(\0132(.google.protobuf.SourceCodeInfo"
- ".Location\032.\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022"
- "\020\n\004span\030\002 \003(\005B\002\020\001B)\n\023com.google.protobuf"
- "B\020DescriptorProtosH\001", 3940);
+ "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File"
+ "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog"
+ "le.protobuf.SourceCodeInfo\"\251\003\n\017Descripto"
+ "rProto\022\014\n\004name\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.go"
+ "ogle.protobuf.FieldDescriptorProto\0228\n\tex"
+ "tension\030\006 \003(\0132%.google.protobuf.FieldDes"
+ "criptorProto\0225\n\013nested_type\030\003 \003(\0132 .goog"
+ "le.protobuf.DescriptorProto\0227\n\tenum_type"
+ "\030\004 \003(\0132$.google.protobuf.EnumDescriptorP"
+ "roto\022H\n\017extension_range\030\005 \003(\0132/.google.p"
+ "rotobuf.DescriptorProto.ExtensionRange\0220"
+ "\n\007options\030\007 \001(\0132\037.google.protobuf.Messag"
+ "eOptions\032,\n\016ExtensionRange\022\r\n\005start\030\001 \001("
+ "\005\022\013\n\003end\030\002 \001(\005\"\224\005\n\024FieldDescriptorProto\022"
+ "\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004"
+ " \001(\0162+.google.protobuf.FieldDescriptorPr"
+ "oto.Label\0228\n\004type\030\005 \001(\0162*.google.protobu"
+ "f.FieldDescriptorProto.Type\022\021\n\ttype_name"
+ "\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022\025\n\rdefault_valu"
+ "e\030\007 \001(\t\022.\n\007options\030\010 \001(\0132\035.google.protob"
+ "uf.FieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020"
+ "\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYP"
+ "E_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED"
+ "64\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_M"
+ "ESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020"
+ "\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rT"
+ "YPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_"
+ "SINT64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n"
+ "\016LABEL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"\214\001"
+ "\n\023EnumDescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005v"
+ "alue\030\002 \003(\0132).google.protobuf.EnumValueDe"
+ "scriptorProto\022-\n\007options\030\003 \001(\0132\034.google."
+ "protobuf.EnumOptions\"l\n\030EnumValueDescrip"
+ "torProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222"
+ "\n\007options\030\003 \001(\0132!.google.protobuf.EnumVa"
+ "lueOptions\"\220\001\n\026ServiceDescriptorProto\022\014\n"
+ "\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.pro"
+ "tobuf.MethodDescriptorProto\0220\n\007options\030\003"
+ " \001(\0132\037.google.protobuf.ServiceOptions\"\177\n"
+ "\025MethodDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\n"
+ "input_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n"
+ "\007options\030\004 \001(\0132\036.google.protobuf.MethodO"
+ "ptions\"\351\003\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\022F\n\014"
+ "optimize_for\030\t \001(\0162).google.protobuf.Fil"
+ "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa"
+ "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f"
+ "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal"
+ "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022C"
+ "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p"
+ "rotobuf.UninterpretedOption\":\n\014OptimizeM"
+ "ode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RU"
+ "NTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\270\001\n\016MessageOptions\022&\n"
+ "\027message_set_wire_format\030\001 \001(\010:\005false\022.\n"
+ "\037no_standard_descriptor_accessor\030\002 \001(\010:\005"
+ "false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g"
+ "oogle.protobuf.UninterpretedOption*\t\010\350\007\020"
+ "\200\200\200\200\002\"\276\002\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#."
+ "google.protobuf.FieldOptions.CType:\006STRI"
+ "NG\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022"
+ "\031\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experiment"
+ "al_map_key\030\t \001(\t\022\023\n\004weak\030\n \001(\010:\005false\022C\n"
+ "\024uninterpreted_option\030\347\007 \003(\0132$.google.pr"
+ "otobuf.UninterpretedOption\"/\n\005CType\022\n\n\006S"
+ "TRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002*\t\010\350\007"
+ "\020\200\200\200\200\002\"x\n\013EnumOptions\022\031\n\013allow_alias\030\002 \001"
+ "(\010:\004true\022C\n\024uninterpreted_option\030\347\007 \003(\0132"
+ "$.google.protobuf.UninterpretedOption*\t\010"
+ "\350\007\020\200\200\200\200\002\"b\n\020EnumValueOptions\022C\n\024uninterp"
+ "reted_option\030\347\007 \003(\0132$.google.protobuf.Un"
+ "interpretedOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceO"
+ "ptions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
+ "google.protobuf.UninterpretedOption*\t\010\350\007"
+ "\020\200\200\200\200\002\"_\n\rMethodOptions\022C\n\024uninterpreted"
+ "_option\030\347\007 \003(\0132$.google.protobuf.Uninter"
+ "pretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Uninterprete"
+ "dOption\022;\n\004name\030\002 \003(\0132-.google.protobuf."
+ "UninterpretedOption.NamePart\022\030\n\020identifi"
+ "er_value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001"
+ "(\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double"
+ "_value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017ag"
+ "gregate_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\"\261\001\n\016Sou"
+ "rceCodeInfo\022:\n\010location\030\001 \003(\0132(.google.p"
+ "rotobuf.SourceCodeInfo.Location\032c\n\010Locat"
+ "ion\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022"
+ "\030\n\020leading_comments\030\003 \001(\t\022\031\n\021trailing_co"
+ "mments\030\004 \001(\tB)\n\023com.google.protobufB\020Des"
+ "criptorProtosH\001", 4135);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -786,7 +802,7 @@ bool FileDescriptorSet::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -810,7 +826,7 @@ void FileDescriptorSet::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->file(i), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -825,7 +841,7 @@ void FileDescriptorSet::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
1, this->file(i), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -835,7 +851,7 @@ void FileDescriptorSet::SerializeWithCachedSizes(
int FileDescriptorSet::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.FileDescriptorProto file = 1;
total_size += 1 * this->file_size();
for (int i = 0; i < this->file_size(); i++) {
@@ -843,7 +859,7 @@ int FileDescriptorSet::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->file(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -886,7 +902,7 @@ void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
}
bool FileDescriptorSet::IsInitialized() const {
-
+
for (int i = 0; i < file_size(); i++) {
if (!this->file(i).IsInitialized()) return false;
}
@@ -917,6 +933,8 @@ void FileDescriptorSet::Swap(FileDescriptorSet* other) {
const int FileDescriptorProto::kNameFieldNumber;
const int FileDescriptorProto::kPackageFieldNumber;
const int FileDescriptorProto::kDependencyFieldNumber;
+const int FileDescriptorProto::kPublicDependencyFieldNumber;
+const int FileDescriptorProto::kWeakDependencyFieldNumber;
const int FileDescriptorProto::kMessageTypeFieldNumber;
const int FileDescriptorProto::kEnumTypeFieldNumber;
const int FileDescriptorProto::kServiceFieldNumber;
@@ -1000,16 +1018,18 @@ void FileDescriptorProto::Clear() {
package_->clear();
}
}
+ }
+ if (_has_bits_[9 / 32] & (0xffu << (9 % 32))) {
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
}
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (has_source_code_info()) {
if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
}
}
dependency_.Clear();
+ public_dependency_.Clear();
+ weak_dependency_.Clear();
message_type_.Clear();
enum_type_.Clear();
service_.Clear();
@@ -1039,7 +1059,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_package;
break;
}
-
+
// optional string package = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1056,7 +1076,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_dependency;
break;
}
-
+
// repeated string dependency = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1075,7 +1095,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(34)) goto parse_message_type;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
case 4: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1090,7 +1110,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(42)) goto parse_enum_type;
break;
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
case 5: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1105,7 +1125,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(50)) goto parse_service;
break;
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
case 6: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1120,7 +1140,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(58)) goto parse_extension;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
case 7: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1135,7 +1155,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(66)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.FileOptions options = 8;
case 8: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1149,7 +1169,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(74)) goto parse_source_code_info;
break;
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
case 9: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1160,10 +1180,54 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(80)) goto parse_public_dependency;
+ break;
+ }
+
+ // repeated int32 public_dependency = 10;
+ case 10: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_public_dependency:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ 1, 80, input, this->mutable_public_dependency())));
+ } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
+ == ::google::protobuf::internal::WireFormatLite::
+ WIRETYPE_LENGTH_DELIMITED) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, this->mutable_public_dependency())));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(80)) goto parse_public_dependency;
+ if (input->ExpectTag(88)) goto parse_weak_dependency;
+ break;
+ }
+
+ // repeated int32 weak_dependency = 11;
+ case 11: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_weak_dependency:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ 1, 88, input, this->mutable_weak_dependency())));
+ } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
+ == ::google::protobuf::internal::WireFormatLite::
+ WIRETYPE_LENGTH_DELIMITED) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, this->mutable_weak_dependency())));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(88)) goto parse_weak_dependency;
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1190,7 +1254,7 @@ void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// optional string package = 2;
if (has_package()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -1199,7 +1263,7 @@ void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->package(), output);
}
-
+
// repeated string dependency = 3;
for (int i = 0; i < this->dependency_size(); i++) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -1208,43 +1272,55 @@ void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
3, this->dependency(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
for (int i = 0; i < this->message_type_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
4, this->message_type(i), output);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
for (int i = 0; i < this->enum_type_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
5, this->enum_type(i), output);
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
for (int i = 0; i < this->service_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
6, this->service(i), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
for (int i = 0; i < this->extension_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
7, this->extension(i), output);
}
-
+
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
8, this->options(), output);
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
9, this->source_code_info(), output);
}
-
+
+ // repeated int32 public_dependency = 10;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(
+ 10, this->public_dependency(i), output);
+ }
+
+ // repeated int32 weak_dependency = 11;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(
+ 11, this->weak_dependency(i), output);
+ }
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -1262,7 +1338,7 @@ void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string package = 2;
if (has_package()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -1272,7 +1348,7 @@ void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->package(), target);
}
-
+
// repeated string dependency = 3;
for (int i = 0; i < this->dependency_size(); i++) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -1281,49 +1357,61 @@ void FileDescriptorProto::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteStringToArray(3, this->dependency(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
for (int i = 0; i < this->message_type_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
4, this->message_type(i), target);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
for (int i = 0; i < this->enum_type_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
5, this->enum_type(i), target);
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
for (int i = 0; i < this->service_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
6, this->service(i), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
for (int i = 0; i < this->extension_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
7, this->extension(i), target);
}
-
+
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
8, this->options(), target);
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
9, this->source_code_info(), target);
}
-
+
+ // repeated int32 public_dependency = 10;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteInt32ToArray(10, this->public_dependency(i), target);
+ }
+
+ // repeated int32 weak_dependency = 11;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteInt32ToArray(11, this->weak_dependency(i), target);
+ }
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -1333,7 +1421,7 @@ void FileDescriptorProto::SerializeWithCachedSizes(
int FileDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -1341,30 +1429,30 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string package = 2;
if (has_package()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->package());
}
-
+
+ }
+ if (_has_bits_[9 / 32] & (0xffu << (9 % 32))) {
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->source_code_info());
}
-
+
}
// repeated string dependency = 3;
total_size += 1 * this->dependency_size();
@@ -1372,7 +1460,27 @@ int FileDescriptorProto::ByteSize() const {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->dependency(i));
}
-
+
+ // repeated int32 public_dependency = 10;
+ {
+ int data_size = 0;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ data_size += ::google::protobuf::internal::WireFormatLite::
+ Int32Size(this->public_dependency(i));
+ }
+ total_size += 1 * this->public_dependency_size() + data_size;
+ }
+
+ // repeated int32 weak_dependency = 11;
+ {
+ int data_size = 0;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ data_size += ::google::protobuf::internal::WireFormatLite::
+ Int32Size(this->weak_dependency(i));
+ }
+ total_size += 1 * this->weak_dependency_size() + data_size;
+ }
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
total_size += 1 * this->message_type_size();
for (int i = 0; i < this->message_type_size(); i++) {
@@ -1380,7 +1488,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->message_type(i));
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
total_size += 1 * this->enum_type_size();
for (int i = 0; i < this->enum_type_size(); i++) {
@@ -1388,7 +1496,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->enum_type(i));
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
total_size += 1 * this->service_size();
for (int i = 0; i < this->service_size(); i++) {
@@ -1396,7 +1504,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->service(i));
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
total_size += 1 * this->extension_size();
for (int i = 0; i < this->extension_size(); i++) {
@@ -1404,7 +1512,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -1431,6 +1539,8 @@ void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
GOOGLE_CHECK_NE(&from, this);
dependency_.MergeFrom(from.dependency_);
+ public_dependency_.MergeFrom(from.public_dependency_);
+ weak_dependency_.MergeFrom(from.weak_dependency_);
message_type_.MergeFrom(from.message_type_);
enum_type_.MergeFrom(from.enum_type_);
service_.MergeFrom(from.service_);
@@ -1442,11 +1552,11 @@ void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
if (from.has_package()) {
set_package(from.package());
}
+ }
+ if (from._has_bits_[9 / 32] & (0xffu << (9 % 32))) {
if (from.has_options()) {
mutable_options()->::google::protobuf::FileOptions::MergeFrom(from.options());
}
- }
- if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_source_code_info()) {
mutable_source_code_info()->::google::protobuf::SourceCodeInfo::MergeFrom(from.source_code_info());
}
@@ -1467,7 +1577,7 @@ void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
}
bool FileDescriptorProto::IsInitialized() const {
-
+
for (int i = 0; i < message_type_size(); i++) {
if (!this->message_type(i).IsInitialized()) return false;
}
@@ -1491,6 +1601,8 @@ void FileDescriptorProto::Swap(FileDescriptorProto* other) {
std::swap(name_, other->name_);
std::swap(package_, other->package_);
dependency_.Swap(&other->dependency_);
+ public_dependency_.Swap(&other->public_dependency_);
+ weak_dependency_.Swap(&other->weak_dependency_);
message_type_.Swap(&other->message_type_);
enum_type_.Swap(&other->enum_type_);
service_.Swap(&other->service_);
@@ -1599,7 +1711,7 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
if (input->ExpectTag(16)) goto parse_end;
break;
}
-
+
// optional int32 end = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1615,7 +1727,7 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1638,12 +1750,12 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
if (has_start()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output);
}
-
+
// optional int32 end = 2;
if (has_end()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -1656,12 +1768,12 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
if (has_start()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
}
-
+
// optional int32 end = 2;
if (has_end()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -1671,7 +1783,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
int DescriptorProto_ExtensionRange::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional int32 start = 1;
if (has_start()) {
@@ -1679,14 +1791,14 @@ int DescriptorProto_ExtensionRange::ByteSize() const {
::google::protobuf::internal::WireFormatLite::Int32Size(
this->start());
}
-
+
// optional int32 end = 2;
if (has_end()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->end());
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -1737,7 +1849,7 @@ void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRan
}
bool DescriptorProto_ExtensionRange::IsInitialized() const {
-
+
return true;
}
@@ -1869,7 +1981,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_field;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1884,7 +1996,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_nested_type;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1899,7 +2011,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(34)) goto parse_enum_type;
break;
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
case 4: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1914,7 +2026,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(42)) goto parse_extension_range;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
case 5: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1929,7 +2041,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(50)) goto parse_extension;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
case 6: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1944,7 +2056,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(58)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
case 7: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1958,7 +2070,7 @@ bool DescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1985,43 +2097,43 @@ void DescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
for (int i = 0; i < this->field_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->field(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
for (int i = 0; i < this->nested_type_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
3, this->nested_type(i), output);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
for (int i = 0; i < this->enum_type_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
4, this->enum_type(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
for (int i = 0; i < this->extension_range_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
5, this->extension_range(i), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
for (int i = 0; i < this->extension_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
6, this->extension(i), output);
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
7, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -2039,49 +2151,49 @@ void DescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
for (int i = 0; i < this->field_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->field(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
for (int i = 0; i < this->nested_type_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
3, this->nested_type(i), target);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
for (int i = 0; i < this->enum_type_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
4, this->enum_type(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
for (int i = 0; i < this->extension_range_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
5, this->extension_range(i), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
for (int i = 0; i < this->extension_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
6, this->extension(i), target);
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
7, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -2091,7 +2203,7 @@ void DescriptorProto::SerializeWithCachedSizes(
int DescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -2099,14 +2211,14 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
total_size += 1 * this->field_size();
@@ -2115,7 +2227,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->field(i));
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
total_size += 1 * this->extension_size();
for (int i = 0; i < this->extension_size(); i++) {
@@ -2123,7 +2235,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension(i));
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
total_size += 1 * this->nested_type_size();
for (int i = 0; i < this->nested_type_size(); i++) {
@@ -2131,7 +2243,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->nested_type(i));
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
total_size += 1 * this->enum_type_size();
for (int i = 0; i < this->enum_type_size(); i++) {
@@ -2139,7 +2251,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->enum_type(i));
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
total_size += 1 * this->extension_range_size();
for (int i = 0; i < this->extension_range_size(); i++) {
@@ -2147,7 +2259,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension_range(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -2202,7 +2314,7 @@ void DescriptorProto::CopyFrom(const DescriptorProto& from) {
}
bool DescriptorProto::IsInitialized() const {
-
+
for (int i = 0; i < field_size(); i++) {
if (!this->field(i).IsInitialized()) return false;
}
@@ -2459,7 +2571,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_extendee;
break;
}
-
+
// optional string extendee = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2476,7 +2588,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(24)) goto parse_number;
break;
}
-
+
// optional int32 number = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2492,7 +2604,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(32)) goto parse_label;
break;
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
case 4: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2513,7 +2625,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(40)) goto parse_type;
break;
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
case 5: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2534,7 +2646,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(50)) goto parse_type_name;
break;
}
-
+
// optional string type_name = 6;
case 6: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2551,7 +2663,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(58)) goto parse_default_value;
break;
}
-
+
// optional string default_value = 7;
case 7: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2568,7 +2680,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(66)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
case 8: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2582,7 +2694,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -2609,7 +2721,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2618,24 +2730,24 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->extendee(), output);
}
-
+
// optional int32 number = 3;
if (has_number()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->number(), output);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
4, this->label(), output);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
5, this->type(), output);
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2644,7 +2756,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
6, this->type_name(), output);
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2653,13 +2765,13 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
7, this->default_value(), output);
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
8, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -2677,7 +2789,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2687,24 +2799,24 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->extendee(), target);
}
-
+
// optional int32 number = 3;
if (has_number()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
4, this->label(), target);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
5, this->type(), target);
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2714,7 +2826,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
6, this->type_name(), target);
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -2724,14 +2836,14 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
7, this->default_value(), target);
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
8, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -2741,7 +2853,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
int FieldDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -2749,54 +2861,54 @@ int FieldDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional int32 number = 3;
if (has_number()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->number());
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->label());
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->type_name());
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->extendee());
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->default_value());
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -2865,7 +2977,7 @@ void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
}
bool FieldDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
if (!this->options().IsInitialized()) return false;
}
@@ -2998,7 +3110,7 @@ bool EnumDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_value;
break;
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3013,7 +3125,7 @@ bool EnumDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3027,7 +3139,7 @@ bool EnumDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3054,19 +3166,19 @@ void EnumDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
for (int i = 0; i < this->value_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->value(i), output);
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
3, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -3084,21 +3196,21 @@ void EnumDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
for (int i = 0; i < this->value_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->value(i), target);
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
3, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -3108,7 +3220,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes(
int EnumDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -3116,14 +3228,14 @@ int EnumDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
total_size += 1 * this->value_size();
@@ -3132,7 +3244,7 @@ int EnumDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->value(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -3183,7 +3295,7 @@ void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
}
bool EnumDescriptorProto::IsInitialized() const {
-
+
for (int i = 0; i < value_size(); i++) {
if (!this->value(i).IsInitialized()) return false;
}
@@ -3315,7 +3427,7 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(16)) goto parse_number;
break;
}
-
+
// optional int32 number = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3331,7 +3443,7 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3345,7 +3457,7 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3372,18 +3484,18 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// optional int32 number = 2;
if (has_number()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->number(), output);
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
3, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -3401,19 +3513,19 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional int32 number = 2;
if (has_number()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target);
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
3, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -3423,7 +3535,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes(
int EnumValueDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -3431,21 +3543,21 @@ int EnumValueDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional int32 number = 2;
if (has_number()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->number());
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -3499,7 +3611,7 @@ void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
}
bool EnumValueDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
if (!this->options().IsInitialized()) return false;
}
@@ -3627,7 +3739,7 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_method;
break;
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3642,7 +3754,7 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3656,7 +3768,7 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3683,19 +3795,19 @@ void ServiceDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
for (int i = 0; i < this->method_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->method(i), output);
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
3, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -3713,21 +3825,21 @@ void ServiceDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
for (int i = 0; i < this->method_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->method(i), target);
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
3, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -3737,7 +3849,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes(
int ServiceDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -3745,14 +3857,14 @@ int ServiceDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
total_size += 1 * this->method_size();
@@ -3761,7 +3873,7 @@ int ServiceDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->method(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -3812,7 +3924,7 @@ void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
}
bool ServiceDescriptorProto::IsInitialized() const {
-
+
for (int i = 0; i < method_size(); i++) {
if (!this->method(i).IsInitialized()) return false;
}
@@ -3961,7 +4073,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_input_type;
break;
}
-
+
// optional string input_type = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3978,7 +4090,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_output_type;
break;
}
-
+
// optional string output_type = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3995,7 +4107,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectTag(34)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
case 4: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4009,7 +4121,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4036,7 +4148,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name(), output);
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4045,7 +4157,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->input_type(), output);
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4054,13 +4166,13 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
3, this->output_type(), output);
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
4, this->options(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -4078,7 +4190,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4088,7 +4200,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->input_type(), target);
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4098,14 +4210,14 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
3, this->output_type(), target);
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
4, this->options(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -4115,7 +4227,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
int MethodDescriptorProto::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string name = 1;
if (has_name()) {
@@ -4123,28 +4235,28 @@ int MethodDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->input_type());
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->output_type());
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->options());
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -4201,7 +4313,7 @@ void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
}
bool MethodDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
if (!this->options().IsInitialized()) return false;
}
@@ -4260,6 +4372,7 @@ const int FileOptions::kJavaOuterClassnameFieldNumber;
const int FileOptions::kJavaMultipleFilesFieldNumber;
const int FileOptions::kJavaGenerateEqualsAndHashFieldNumber;
const int FileOptions::kOptimizeForFieldNumber;
+const int FileOptions::kGoPackageFieldNumber;
const int FileOptions::kCcGenericServicesFieldNumber;
const int FileOptions::kJavaGenericServicesFieldNumber;
const int FileOptions::kPyGenericServicesFieldNumber;
@@ -4287,6 +4400,7 @@ void FileOptions::SharedCtor() {
java_multiple_files_ = false;
java_generate_equals_and_hash_ = false;
optimize_for_ = 1;
+ go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
cc_generic_services_ = false;
java_generic_services_ = false;
py_generic_services_ = false;
@@ -4304,6 +4418,9 @@ void FileOptions::SharedDtor() {
if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) {
delete java_outer_classname_;
}
+ if (go_package_ != &::google::protobuf::internal::kEmptyString) {
+ delete go_package_;
+ }
if (this != default_instance_) {
}
}
@@ -4345,8 +4462,15 @@ void FileOptions::Clear() {
java_multiple_files_ = false;
java_generate_equals_and_hash_ = false;
optimize_for_ = 1;
+ if (has_go_package()) {
+ if (go_package_ != &::google::protobuf::internal::kEmptyString) {
+ go_package_->clear();
+ }
+ }
cc_generic_services_ = false;
java_generic_services_ = false;
+ }
+ if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
py_generic_services_ = false;
}
uninterpreted_option_.Clear();
@@ -4375,7 +4499,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(66)) goto parse_java_outer_classname;
break;
}
-
+
// optional string java_outer_classname = 8;
case 8: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4392,7 +4516,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(72)) goto parse_optimize_for;
break;
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
case 9: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4413,7 +4537,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(80)) goto parse_java_multiple_files;
break;
}
-
+
// optional bool java_multiple_files = 10 [default = false];
case 10: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4426,10 +4550,27 @@ bool FileOptions::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(90)) goto parse_go_package;
+ break;
+ }
+
+ // optional string go_package = 11;
+ case 11: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_go_package:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_go_package()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectTag(128)) goto parse_cc_generic_services;
break;
}
-
+
// optional bool cc_generic_services = 16 [default = false];
case 16: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4445,7 +4586,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(136)) goto parse_java_generic_services;
break;
}
-
+
// optional bool java_generic_services = 17 [default = false];
case 17: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4461,7 +4602,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(144)) goto parse_py_generic_services;
break;
}
-
+
// optional bool py_generic_services = 18 [default = false];
case 18: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4477,7 +4618,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(160)) goto parse_java_generate_equals_and_hash;
break;
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
case 20: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4493,7 +4634,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
break;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4508,7 +4649,7 @@ bool FileOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4540,7 +4681,7 @@ void FileOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->java_package(), output);
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4549,48 +4690,57 @@ void FileOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
8, this->java_outer_classname(), output);
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
9, this->optimize_for(), output);
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output);
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 11, this->go_package(), output);
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output);
}
-
+
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output);
}
-
+
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output);
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
::google::protobuf::internal::WireFormatLite::WriteBool(20, this->java_generate_equals_and_hash(), output);
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -4608,7 +4758,7 @@ void FileOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->java_package(), target);
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -4618,49 +4768,59 @@ void FileOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
8, this->java_outer_classname(), target);
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
9, this->optimize_for(), target);
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target);
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 11, this->go_package(), target);
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target);
}
-
+
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target);
}
-
+
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target);
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(20, this->java_generate_equals_and_hash(), target);
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -4670,7 +4830,7 @@ void FileOptions::SerializeWithCachedSizes(
int FileOptions::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional string java_package = 1;
if (has_java_package()) {
@@ -4678,45 +4838,54 @@ int FileOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->java_package());
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->java_outer_classname());
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
total_size += 1 + 1;
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
total_size += 2 + 1;
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for());
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->go_package());
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
total_size += 2 + 1;
}
-
+
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
total_size += 2 + 1;
}
-
+
+ }
+ if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
total_size += 2 + 1;
}
-
+
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
@@ -4725,9 +4894,9 @@ int FileOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -4770,12 +4939,17 @@ void FileOptions::MergeFrom(const FileOptions& from) {
if (from.has_optimize_for()) {
set_optimize_for(from.optimize_for());
}
+ if (from.has_go_package()) {
+ set_go_package(from.go_package());
+ }
if (from.has_cc_generic_services()) {
set_cc_generic_services(from.cc_generic_services());
}
if (from.has_java_generic_services()) {
set_java_generic_services(from.java_generic_services());
}
+ }
+ if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_py_generic_services()) {
set_py_generic_services(from.py_generic_services());
}
@@ -4797,11 +4971,11 @@ void FileOptions::CopyFrom(const FileOptions& from) {
}
bool FileOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -4812,6 +4986,7 @@ void FileOptions::Swap(FileOptions* other) {
std::swap(java_multiple_files_, other->java_multiple_files_);
std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_);
std::swap(optimize_for_, other->optimize_for_);
+ std::swap(go_package_, other->go_package_);
std::swap(cc_generic_services_, other->cc_generic_services_);
std::swap(java_generic_services_, other->java_generic_services_);
std::swap(py_generic_services_, other->py_generic_services_);
@@ -4922,7 +5097,7 @@ bool MessageOptions::MergePartialFromCodedStream(
if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor;
break;
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4938,7 +5113,7 @@ bool MessageOptions::MergePartialFromCodedStream(
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
break;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4953,7 +5128,7 @@ bool MessageOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4981,22 +5156,22 @@ void MessageOptions::SerializeWithCachedSizes(
if (has_message_set_wire_format()) {
::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output);
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->no_standard_descriptor_accessor(), output);
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -5009,23 +5184,23 @@ void MessageOptions::SerializeWithCachedSizes(
if (has_message_set_wire_format()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->message_set_wire_format(), target);
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->no_standard_descriptor_accessor(), target);
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -5035,18 +5210,18 @@ void MessageOptions::SerializeWithCachedSizes(
int MessageOptions::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional bool message_set_wire_format = 1 [default = false];
if (has_message_set_wire_format()) {
total_size += 1 + 1;
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
total_size += 1 + 1;
}
-
+
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
@@ -5055,9 +5230,9 @@ int MessageOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5109,11 +5284,11 @@ void MessageOptions::CopyFrom(const MessageOptions& from) {
}
bool MessageOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -5166,8 +5341,10 @@ const int FieldOptions::CType_ARRAYSIZE;
#ifndef _MSC_VER
const int FieldOptions::kCtypeFieldNumber;
const int FieldOptions::kPackedFieldNumber;
+const int FieldOptions::kLazyFieldNumber;
const int FieldOptions::kDeprecatedFieldNumber;
const int FieldOptions::kExperimentalMapKeyFieldNumber;
+const int FieldOptions::kWeakFieldNumber;
const int FieldOptions::kUninterpretedOptionFieldNumber;
#endif // !_MSC_VER
@@ -5189,8 +5366,10 @@ void FieldOptions::SharedCtor() {
_cached_size_ = 0;
ctype_ = 0;
packed_ = false;
+ lazy_ = false;
deprecated_ = false;
experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ weak_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -5232,12 +5411,14 @@ void FieldOptions::Clear() {
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
ctype_ = 0;
packed_ = false;
+ lazy_ = false;
deprecated_ = false;
if (has_experimental_map_key()) {
if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
experimental_map_key_->clear();
}
}
+ weak_ = false;
}
uninterpreted_option_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -5269,7 +5450,7 @@ bool FieldOptions::MergePartialFromCodedStream(
if (input->ExpectTag(16)) goto parse_packed;
break;
}
-
+
// optional bool packed = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5285,7 +5466,7 @@ bool FieldOptions::MergePartialFromCodedStream(
if (input->ExpectTag(24)) goto parse_deprecated;
break;
}
-
+
// optional bool deprecated = 3 [default = false];
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5298,10 +5479,26 @@ bool FieldOptions::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(40)) goto parse_lazy;
+ break;
+ }
+
+ // optional bool lazy = 5 [default = false];
+ case 5: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_lazy:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &lazy_)));
+ set_has_lazy();
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectTag(74)) goto parse_experimental_map_key;
break;
}
-
+
// optional string experimental_map_key = 9;
case 9: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5315,10 +5512,26 @@ bool FieldOptions::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(80)) goto parse_weak;
+ break;
+ }
+
+ // optional bool weak = 10 [default = false];
+ case 10: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_weak:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &weak_)));
+ set_has_weak();
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
break;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5333,7 +5546,7 @@ bool FieldOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5362,17 +5575,22 @@ void FieldOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteEnum(
1, this->ctype(), output);
}
-
+
// optional bool packed = 2;
if (has_packed()) {
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->packed(), output);
}
-
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
}
-
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output);
+ }
+
// optional string experimental_map_key = 9;
if (has_experimental_map_key()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -5381,17 +5599,22 @@ void FieldOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
9, this->experimental_map_key(), output);
}
-
+
+ // optional bool weak = 10 [default = false];
+ if (has_weak()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -5405,17 +5628,22 @@ void FieldOptions::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
1, this->ctype(), target);
}
-
+
// optional bool packed = 2;
if (has_packed()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->packed(), target);
}
-
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
}
-
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target);
+ }
+
// optional string experimental_map_key = 9;
if (has_experimental_map_key()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -5425,18 +5653,23 @@ void FieldOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
9, this->experimental_map_key(), target);
}
-
+
+ // optional bool weak = 10 [default = false];
+ if (has_weak()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -5446,31 +5679,41 @@ void FieldOptions::SerializeWithCachedSizes(
int FieldOptions::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
if (has_ctype()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype());
}
-
+
// optional bool packed = 2;
if (has_packed()) {
total_size += 1 + 1;
}
-
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ total_size += 1 + 1;
+ }
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
total_size += 1 + 1;
}
-
+
// optional string experimental_map_key = 9;
if (has_experimental_map_key()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->experimental_map_key());
}
-
+
+ // optional bool weak = 10 [default = false];
+ if (has_weak()) {
+ total_size += 1 + 1;
+ }
+
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
@@ -5479,9 +5722,9 @@ int FieldOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5515,12 +5758,18 @@ void FieldOptions::MergeFrom(const FieldOptions& from) {
if (from.has_packed()) {
set_packed(from.packed());
}
+ if (from.has_lazy()) {
+ set_lazy(from.lazy());
+ }
if (from.has_deprecated()) {
set_deprecated(from.deprecated());
}
if (from.has_experimental_map_key()) {
set_experimental_map_key(from.experimental_map_key());
}
+ if (from.has_weak()) {
+ set_weak(from.weak());
+ }
}
_extensions_.MergeFrom(from._extensions_);
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
@@ -5539,11 +5788,11 @@ void FieldOptions::CopyFrom(const FieldOptions& from) {
}
bool FieldOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -5551,8 +5800,10 @@ void FieldOptions::Swap(FieldOptions* other) {
if (other != this) {
std::swap(ctype_, other->ctype_);
std::swap(packed_, other->packed_);
+ std::swap(lazy_, other->lazy_);
std::swap(deprecated_, other->deprecated_);
std::swap(experimental_map_key_, other->experimental_map_key_);
+ std::swap(weak_, other->weak_);
uninterpreted_option_.Swap(&other->uninterpreted_option_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.Swap(&other->_unknown_fields_);
@@ -5573,6 +5824,7 @@ void FieldOptions::Swap(FieldOptions* other) {
// ===================================================================
#ifndef _MSC_VER
+const int EnumOptions::kAllowAliasFieldNumber;
const int EnumOptions::kUninterpretedOptionFieldNumber;
#endif // !_MSC_VER
@@ -5592,6 +5844,7 @@ EnumOptions::EnumOptions(const EnumOptions& from)
void EnumOptions::SharedCtor() {
_cached_size_ = 0;
+ allow_alias_ = true;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -5627,6 +5880,9 @@ EnumOptions* EnumOptions::New() const {
void EnumOptions::Clear() {
_extensions_.Clear();
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ allow_alias_ = true;
+ }
uninterpreted_option_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
mutable_unknown_fields()->Clear();
@@ -5638,6 +5894,21 @@ bool EnumOptions::MergePartialFromCodedStream(
::google::protobuf::uint32 tag;
while ((tag = input->ReadTag()) != 0) {
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional bool allow_alias = 2 [default = true];
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &allow_alias_)));
+ set_has_allow_alias();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+ break;
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5652,7 +5923,7 @@ bool EnumOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5676,16 +5947,21 @@ bool EnumOptions::MergePartialFromCodedStream(
void EnumOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // optional bool allow_alias = 2 [default = true];
+ if (has_allow_alias()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->allow_alias(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -5694,17 +5970,22 @@ void EnumOptions::SerializeWithCachedSizes(
::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // optional bool allow_alias = 2 [default = true];
+ if (has_allow_alias()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->allow_alias(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -5714,7 +5995,14 @@ void EnumOptions::SerializeWithCachedSizes(
int EnumOptions::ByteSize() const {
int total_size = 0;
-
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional bool allow_alias = 2 [default = true];
+ if (has_allow_alias()) {
+ total_size += 1 + 1;
+ }
+
+ }
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -5722,9 +6010,9 @@ int EnumOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5751,6 +6039,11 @@ void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
void EnumOptions::MergeFrom(const EnumOptions& from) {
GOOGLE_CHECK_NE(&from, this);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_allow_alias()) {
+ set_allow_alias(from.allow_alias());
+ }
+ }
_extensions_.MergeFrom(from._extensions_);
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
@@ -5768,16 +6061,17 @@ void EnumOptions::CopyFrom(const EnumOptions& from) {
}
bool EnumOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void EnumOptions::Swap(EnumOptions* other) {
if (other != this) {
+ std::swap(allow_alias_, other->allow_alias_);
uninterpreted_option_.Swap(&other->uninterpreted_option_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.Swap(&other->_unknown_fields_);
@@ -5877,7 +6171,7 @@ bool EnumValueOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -5906,11 +6200,11 @@ void EnumValueOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -5925,11 +6219,11 @@ void EnumValueOptions::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -5939,7 +6233,7 @@ void EnumValueOptions::SerializeWithCachedSizes(
int EnumValueOptions::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -5947,9 +6241,9 @@ int EnumValueOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5993,11 +6287,11 @@ void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
}
bool EnumValueOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -6102,7 +6396,7 @@ bool ServiceOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6131,11 +6425,11 @@ void ServiceOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -6150,11 +6444,11 @@ void ServiceOptions::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -6164,7 +6458,7 @@ void ServiceOptions::SerializeWithCachedSizes(
int ServiceOptions::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -6172,9 +6466,9 @@ int ServiceOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -6218,11 +6512,11 @@ void ServiceOptions::CopyFrom(const ServiceOptions& from) {
}
bool ServiceOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -6327,7 +6621,7 @@ bool MethodOptions::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6356,11 +6650,11 @@ void MethodOptions::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -6375,11 +6669,11 @@ void MethodOptions::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
target = _extensions_.SerializeWithCachedSizesToArray(
1000, 536870912, target);
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -6389,7 +6683,7 @@ void MethodOptions::SerializeWithCachedSizes(
int MethodOptions::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -6397,9 +6691,9 @@ int MethodOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -6443,11 +6737,11 @@ void MethodOptions::CopyFrom(const MethodOptions& from) {
}
bool MethodOptions::IsInitialized() const {
-
+
for (int i = 0; i < uninterpreted_option_size(); i++) {
if (!this->uninterpreted_option(i).IsInitialized()) return false;
}
-
+
if (!_extensions_.IsInitialized()) return false; return true;
}
@@ -6565,7 +6859,7 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream(
if (input->ExpectTag(16)) goto parse_is_extension;
break;
}
-
+
// required bool is_extension = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6581,7 +6875,7 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6608,12 +6902,12 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->name_part(), output);
}
-
+
// required bool is_extension = 2;
if (has_is_extension()) {
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->is_extension(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -6631,12 +6925,12 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name_part(), target);
}
-
+
// required bool is_extension = 2;
if (has_is_extension()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->is_extension(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -6646,7 +6940,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes(
int UninterpretedOption_NamePart::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// required string name_part = 1;
if (has_name_part()) {
@@ -6654,12 +6948,12 @@ int UninterpretedOption_NamePart::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->name_part());
}
-
+
// required bool is_extension = 2;
if (has_is_extension()) {
total_size += 1 + 1;
}
-
+
}
if (!unknown_fields().empty()) {
total_size +=
@@ -6711,7 +7005,7 @@ void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart&
bool UninterpretedOption_NamePart::IsInitialized() const {
if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
-
+
return true;
}
@@ -6856,7 +7150,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(26)) goto parse_identifier_value;
break;
}
-
+
// optional string identifier_value = 3;
case 3: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6873,7 +7167,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(32)) goto parse_positive_int_value;
break;
}
-
+
// optional uint64 positive_int_value = 4;
case 4: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6889,7 +7183,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(40)) goto parse_negative_int_value;
break;
}
-
+
// optional int64 negative_int_value = 5;
case 5: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6905,7 +7199,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(49)) goto parse_double_value;
break;
}
-
+
// optional double double_value = 6;
case 6: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6921,7 +7215,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(58)) goto parse_string_value;
break;
}
-
+
// optional bytes string_value = 7;
case 7: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6935,7 +7229,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectTag(66)) goto parse_aggregate_value;
break;
}
-
+
// optional string aggregate_value = 8;
case 8: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6952,7 +7246,7 @@ bool UninterpretedOption::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -6976,7 +7270,7 @@ void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->name(i), output);
}
-
+
// optional string identifier_value = 3;
if (has_identifier_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -6985,28 +7279,28 @@ void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
3, this->identifier_value(), output);
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->positive_int_value(), output);
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
::google::protobuf::internal::WireFormatLite::WriteInt64(5, this->negative_int_value(), output);
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
::google::protobuf::internal::WireFormatLite::WriteDouble(6, this->double_value(), output);
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
::google::protobuf::internal::WireFormatLite::WriteBytes(
7, this->string_value(), output);
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -7015,7 +7309,7 @@ void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteString(
8, this->aggregate_value(), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -7030,7 +7324,7 @@ void UninterpretedOption::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
2, this->name(i), target);
}
-
+
// optional string identifier_value = 3;
if (has_identifier_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -7040,29 +7334,29 @@ void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
3, this->identifier_value(), target);
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->positive_int_value(), target);
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(5, this->negative_int_value(), target);
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(6, this->double_value(), target);
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
target =
::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
7, this->string_value(), target);
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
::google::protobuf::internal::WireFormat::VerifyUTF8String(
@@ -7072,7 +7366,7 @@ void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
8, this->aggregate_value(), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -7082,7 +7376,7 @@ void UninterpretedOption::SerializeWithCachedSizes(
int UninterpretedOption::ByteSize() const {
int total_size = 0;
-
+
if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
// optional string identifier_value = 3;
if (has_identifier_value()) {
@@ -7090,40 +7384,40 @@ int UninterpretedOption::ByteSize() const {
::google::protobuf::internal::WireFormatLite::StringSize(
this->identifier_value());
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::UInt64Size(
this->positive_int_value());
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int64Size(
this->negative_int_value());
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
total_size += 1 + 8;
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::BytesSize(
this->string_value());
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->aggregate_value());
}
-
+
}
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
total_size += 1 * this->name_size();
@@ -7132,7 +7426,7 @@ int UninterpretedOption::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->name(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -7195,7 +7489,7 @@ void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
}
bool UninterpretedOption::IsInitialized() const {
-
+
for (int i = 0; i < name_size(); i++) {
if (!this->name(i).IsInitialized()) return false;
}
@@ -7231,6 +7525,8 @@ void UninterpretedOption::Swap(UninterpretedOption* other) {
#ifndef _MSC_VER
const int SourceCodeInfo_Location::kPathFieldNumber;
const int SourceCodeInfo_Location::kSpanFieldNumber;
+const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber;
+const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber;
#endif // !_MSC_VER
SourceCodeInfo_Location::SourceCodeInfo_Location()
@@ -7249,6 +7545,8 @@ SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location&
void SourceCodeInfo_Location::SharedCtor() {
_cached_size_ = 0;
+ leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -7257,6 +7555,12 @@ SourceCodeInfo_Location::~SourceCodeInfo_Location() {
}
void SourceCodeInfo_Location::SharedDtor() {
+ if (leading_comments_ != &::google::protobuf::internal::kEmptyString) {
+ delete leading_comments_;
+ }
+ if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) {
+ delete trailing_comments_;
+ }
if (this != default_instance_) {
}
}
@@ -7283,6 +7587,18 @@ SourceCodeInfo_Location* SourceCodeInfo_Location::New() const {
}
void SourceCodeInfo_Location::Clear() {
+ if (_has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+ if (has_leading_comments()) {
+ if (leading_comments_ != &::google::protobuf::internal::kEmptyString) {
+ leading_comments_->clear();
+ }
+ }
+ if (has_trailing_comments()) {
+ if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_->clear();
+ }
+ }
+ }
path_.Clear();
span_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -7314,7 +7630,7 @@ bool SourceCodeInfo_Location::MergePartialFromCodedStream(
if (input->ExpectTag(18)) goto parse_span;
break;
}
-
+
// repeated int32 span = 2 [packed = true];
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -7332,10 +7648,44 @@ bool SourceCodeInfo_Location::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(26)) goto parse_leading_comments;
+ break;
+ }
+
+ // optional string leading_comments = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_leading_comments:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_leading_comments()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(34)) goto parse_trailing_comments;
+ break;
+ }
+
+ // optional string trailing_comments = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_trailing_comments:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_trailing_comments()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -7363,7 +7713,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
this->path(i), output);
}
-
+
// repeated int32 span = 2 [packed = true];
if (this->span_size() > 0) {
::google::protobuf::internal::WireFormatLite::WriteTag(2, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
@@ -7373,7 +7723,25 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
this->span(i), output);
}
-
+
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 3, this->leading_comments(), output);
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 4, this->trailing_comments(), output);
+ }
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -7395,7 +7763,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteInt32NoTagToArray(this->path(i), target);
}
-
+
// repeated int32 span = 2 [packed = true];
if (this->span_size() > 0) {
target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
@@ -7409,7 +7777,27 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteInt32NoTagToArray(this->span(i), target);
}
-
+
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 3, this->leading_comments(), target);
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 4, this->trailing_comments(), target);
+ }
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -7419,7 +7807,23 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
int SourceCodeInfo_Location::ByteSize() const {
int total_size = 0;
-
+
+ if (_has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->leading_comments());
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->trailing_comments());
+ }
+
+ }
// repeated int32 path = 1 [packed = true];
{
int data_size = 0;
@@ -7431,10 +7835,12 @@ int SourceCodeInfo_Location::ByteSize() const {
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;
}
-
+
// repeated int32 span = 2 [packed = true];
{
int data_size = 0;
@@ -7446,10 +7852,12 @@ int SourceCodeInfo_Location::ByteSize() const {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
}
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_span_cached_byte_size_ = data_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
total_size += data_size;
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -7477,6 +7885,14 @@ void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) {
GOOGLE_CHECK_NE(&from, this);
path_.MergeFrom(from.path_);
span_.MergeFrom(from.span_);
+ if (from._has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+ if (from.has_leading_comments()) {
+ set_leading_comments(from.leading_comments());
+ }
+ if (from.has_trailing_comments()) {
+ set_trailing_comments(from.trailing_comments());
+ }
+ }
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
@@ -7493,7 +7909,7 @@ void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) {
}
bool SourceCodeInfo_Location::IsInitialized() const {
-
+
return true;
}
@@ -7501,6 +7917,8 @@ void SourceCodeInfo_Location::Swap(SourceCodeInfo_Location* other) {
if (other != this) {
path_.Swap(&other->path_);
span_.Swap(&other->span_);
+ std::swap(leading_comments_, other->leading_comments_);
+ std::swap(trailing_comments_, other->trailing_comments_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.Swap(&other->_unknown_fields_);
std::swap(_cached_size_, other->_cached_size_);
@@ -7597,7 +8015,7 @@ bool SourceCodeInfo::MergePartialFromCodedStream(
if (input->ExpectAtEnd()) return true;
break;
}
-
+
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -7621,7 +8039,7 @@ void SourceCodeInfo::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->location(i), output);
}
-
+
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -7636,7 +8054,7 @@ void SourceCodeInfo::SerializeWithCachedSizes(
WriteMessageNoVirtualToArray(
1, this->location(i), target);
}
-
+
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -7646,7 +8064,7 @@ void SourceCodeInfo::SerializeWithCachedSizes(
int SourceCodeInfo::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
total_size += 1 * this->location_size();
for (int i = 0; i < this->location_size(); i++) {
@@ -7654,7 +8072,7 @@ int SourceCodeInfo::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->location(i));
}
-
+
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -7697,7 +8115,7 @@ void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) {
}
bool SourceCodeInfo::IsInitialized() const {
-
+
return true;
}
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 267d0d35..b7ea1b28 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -20,9 +20,11 @@
#endif
#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
namespace google {
@@ -155,29 +157,29 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
public:
FileDescriptorSet();
virtual ~FileDescriptorSet();
-
+
FileDescriptorSet(const FileDescriptorSet& from);
-
+
inline FileDescriptorSet& operator=(const FileDescriptorSet& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileDescriptorSet& default_instance();
-
+
void Swap(FileDescriptorSet* other);
-
+
// implements Message ----------------------------------------------
-
+
FileDescriptorSet* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -185,7 +187,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
void MergeFrom(const FileDescriptorSet& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -198,13 +200,13 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.FileDescriptorProto file = 1;
inline int file_size() const;
inline void clear_file();
@@ -216,21 +218,21 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
file() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
mutable_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
private:
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+
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 FileDescriptorSet* default_instance_;
};
@@ -240,29 +242,29 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
public:
FileDescriptorProto();
virtual ~FileDescriptorProto();
-
+
FileDescriptorProto(const FileDescriptorProto& from);
-
+
inline FileDescriptorProto& operator=(const FileDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileDescriptorProto& default_instance();
-
+
void Swap(FileDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
FileDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -270,7 +272,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
void MergeFrom(const FileDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -283,13 +285,13 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -300,7 +302,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// optional string package = 2;
inline bool has_package() const;
inline void clear_package();
@@ -311,7 +314,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline void set_package(const char* value, size_t size);
inline ::std::string* mutable_package();
inline ::std::string* release_package();
-
+ inline void set_allocated_package(::std::string* package);
+
// repeated string dependency = 3;
inline int dependency_size() const;
inline void clear_dependency();
@@ -327,7 +331,31 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline void add_dependency(const char* value, size_t size);
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
-
+
+ // repeated int32 public_dependency = 10;
+ inline int public_dependency_size() const;
+ inline void clear_public_dependency();
+ static const int kPublicDependencyFieldNumber = 10;
+ inline ::google::protobuf::int32 public_dependency(int index) const;
+ inline void set_public_dependency(int index, ::google::protobuf::int32 value);
+ inline void add_public_dependency(::google::protobuf::int32 value);
+ inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ public_dependency() const;
+ inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ mutable_public_dependency();
+
+ // repeated int32 weak_dependency = 11;
+ inline int weak_dependency_size() const;
+ inline void clear_weak_dependency();
+ static const int kWeakDependencyFieldNumber = 11;
+ inline ::google::protobuf::int32 weak_dependency(int index) const;
+ inline void set_weak_dependency(int index, ::google::protobuf::int32 value);
+ inline void add_weak_dependency(::google::protobuf::int32 value);
+ inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ weak_dependency() const;
+ inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ mutable_weak_dependency();
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
inline int message_type_size() const;
inline void clear_message_type();
@@ -339,7 +367,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
message_type() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
mutable_message_type();
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
inline int enum_type_size() const;
inline void clear_enum_type();
@@ -351,7 +379,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
enum_type() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
mutable_enum_type();
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
inline int service_size() const;
inline void clear_service();
@@ -363,7 +391,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
service() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
mutable_service();
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
inline int extension_size() const;
inline void clear_extension();
@@ -375,7 +403,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
extension() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_extension();
-
+
// optional .google.protobuf.FileOptions options = 8;
inline bool has_options() const;
inline void clear_options();
@@ -383,7 +411,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline const ::google::protobuf::FileOptions& options() const;
inline ::google::protobuf::FileOptions* mutable_options();
inline ::google::protobuf::FileOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::FileOptions* options);
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
inline bool has_source_code_info() const;
inline void clear_source_code_info();
@@ -391,7 +420,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline const ::google::protobuf::SourceCodeInfo& source_code_info() const;
inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info();
inline ::google::protobuf::SourceCodeInfo* release_source_code_info();
-
+ inline void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info);
+
// @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
private:
inline void set_has_name();
@@ -402,26 +432,28 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline void clear_has_options();
inline void set_has_source_code_info();
inline void clear_has_source_code_info();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::std::string* package_;
::google::protobuf::RepeatedPtrField< ::std::string> dependency_;
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 > public_dependency_;
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 > weak_dependency_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > message_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
::google::protobuf::FileOptions* options_;
::google::protobuf::SourceCodeInfo* source_code_info_;
-
+
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32];
-
+ ::google::protobuf::uint32 _has_bits_[(11 + 31) / 32];
+
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 FileDescriptorProto* default_instance_;
};
@@ -431,29 +463,29 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
public:
DescriptorProto_ExtensionRange();
virtual ~DescriptorProto_ExtensionRange();
-
+
DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from);
-
+
inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const DescriptorProto_ExtensionRange& default_instance();
-
+
void Swap(DescriptorProto_ExtensionRange* other);
-
+
// implements Message ----------------------------------------------
-
+
DescriptorProto_ExtensionRange* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -461,7 +493,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
void MergeFrom(const DescriptorProto_ExtensionRange& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -474,46 +506,46 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional int32 start = 1;
inline bool has_start() const;
inline void clear_start();
static const int kStartFieldNumber = 1;
inline ::google::protobuf::int32 start() const;
inline void set_start(::google::protobuf::int32 value);
-
+
// optional int32 end = 2;
inline bool has_end() const;
inline void clear_end();
static const int kEndFieldNumber = 2;
inline ::google::protobuf::int32 end() const;
inline void set_end(::google::protobuf::int32 value);
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
private:
inline void set_has_start();
inline void clear_has_start();
inline void set_has_end();
inline void clear_has_end();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::int32 start_;
::google::protobuf::int32 end_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+
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 DescriptorProto_ExtensionRange* default_instance_;
};
@@ -523,29 +555,29 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
public:
DescriptorProto();
virtual ~DescriptorProto();
-
+
DescriptorProto(const DescriptorProto& from);
-
+
inline DescriptorProto& operator=(const DescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const DescriptorProto& default_instance();
-
+
void Swap(DescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
DescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -553,7 +585,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
void MergeFrom(const DescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -566,15 +598,15 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef DescriptorProto_ExtensionRange ExtensionRange;
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -585,7 +617,8 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
inline int field_size() const;
inline void clear_field();
@@ -597,7 +630,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
field() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_field();
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
inline int extension_size() const;
inline void clear_extension();
@@ -609,7 +642,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
extension() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_extension();
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
inline int nested_type_size() const;
inline void clear_nested_type();
@@ -621,7 +654,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
nested_type() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
mutable_nested_type();
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
inline int enum_type_size() const;
inline void clear_enum_type();
@@ -633,7 +666,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
enum_type() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
mutable_enum_type();
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
inline int extension_range_size() const;
inline void clear_extension_range();
@@ -645,7 +678,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
extension_range() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
mutable_extension_range();
-
+
// optional .google.protobuf.MessageOptions options = 7;
inline bool has_options() const;
inline void clear_options();
@@ -653,16 +686,17 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
inline const ::google::protobuf::MessageOptions& options() const;
inline ::google::protobuf::MessageOptions* mutable_options();
inline ::google::protobuf::MessageOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::MessageOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
@@ -670,14 +704,14 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_;
::google::protobuf::MessageOptions* options_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
-
+
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 DescriptorProto* default_instance_;
};
@@ -687,29 +721,29 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
public:
FieldDescriptorProto();
virtual ~FieldDescriptorProto();
-
+
FieldDescriptorProto(const FieldDescriptorProto& from);
-
+
inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FieldDescriptorProto& default_instance();
-
+
void Swap(FieldDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
FieldDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -717,7 +751,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
void MergeFrom(const FieldDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -730,11 +764,11 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef FieldDescriptorProto_Type Type;
static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE;
static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT;
@@ -774,7 +808,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Type* value) {
return FieldDescriptorProto_Type_Parse(name, value);
}
-
+
typedef FieldDescriptorProto_Label Label;
static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
@@ -799,9 +833,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Label* value) {
return FieldDescriptorProto_Label_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -812,28 +846,29 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// optional int32 number = 3;
inline bool has_number() const;
inline void clear_number();
static const int kNumberFieldNumber = 3;
inline ::google::protobuf::int32 number() const;
inline void set_number(::google::protobuf::int32 value);
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
inline bool has_label() const;
inline void clear_label();
static const int kLabelFieldNumber = 4;
inline ::google::protobuf::FieldDescriptorProto_Label label() const;
inline void set_label(::google::protobuf::FieldDescriptorProto_Label value);
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
inline bool has_type() const;
inline void clear_type();
static const int kTypeFieldNumber = 5;
inline ::google::protobuf::FieldDescriptorProto_Type type() const;
inline void set_type(::google::protobuf::FieldDescriptorProto_Type value);
-
+
// optional string type_name = 6;
inline bool has_type_name() const;
inline void clear_type_name();
@@ -844,7 +879,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void set_type_name(const char* value, size_t size);
inline ::std::string* mutable_type_name();
inline ::std::string* release_type_name();
-
+ inline void set_allocated_type_name(::std::string* type_name);
+
// optional string extendee = 2;
inline bool has_extendee() const;
inline void clear_extendee();
@@ -855,7 +891,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void set_extendee(const char* value, size_t size);
inline ::std::string* mutable_extendee();
inline ::std::string* release_extendee();
-
+ inline void set_allocated_extendee(::std::string* extendee);
+
// optional string default_value = 7;
inline bool has_default_value() const;
inline void clear_default_value();
@@ -866,7 +903,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void set_default_value(const char* value, size_t size);
inline ::std::string* mutable_default_value();
inline ::std::string* release_default_value();
-
+ inline void set_allocated_default_value(::std::string* default_value);
+
// optional .google.protobuf.FieldOptions options = 8;
inline bool has_options() const;
inline void clear_options();
@@ -874,7 +912,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline const ::google::protobuf::FieldOptions& options() const;
inline ::google::protobuf::FieldOptions* mutable_options();
inline ::google::protobuf::FieldOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::FieldOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
private:
inline void set_has_name();
@@ -893,9 +932,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void clear_has_default_value();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::google::protobuf::int32 number_;
int label_;
@@ -904,14 +943,14 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
::std::string* default_value_;
::google::protobuf::FieldOptions* options_;
int type_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
-
+
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 FieldDescriptorProto* default_instance_;
};
@@ -921,29 +960,29 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
public:
EnumDescriptorProto();
virtual ~EnumDescriptorProto();
-
+
EnumDescriptorProto(const EnumDescriptorProto& from);
-
+
inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumDescriptorProto& default_instance();
-
+
void Swap(EnumDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
EnumDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -951,7 +990,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
void MergeFrom(const EnumDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -964,13 +1003,13 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -981,7 +1020,8 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
inline int value_size() const;
inline void clear_value();
@@ -993,7 +1033,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
value() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
mutable_value();
-
+
// optional .google.protobuf.EnumOptions options = 3;
inline bool has_options() const;
inline void clear_options();
@@ -1001,27 +1041,28 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
inline const ::google::protobuf::EnumOptions& options() const;
inline ::google::protobuf::EnumOptions* mutable_options();
inline ::google::protobuf::EnumOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::EnumOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_;
::google::protobuf::EnumOptions* options_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
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 EnumDescriptorProto* default_instance_;
};
@@ -1031,29 +1072,29 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
public:
EnumValueDescriptorProto();
virtual ~EnumValueDescriptorProto();
-
+
EnumValueDescriptorProto(const EnumValueDescriptorProto& from);
-
+
inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumValueDescriptorProto& default_instance();
-
+
void Swap(EnumValueDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
EnumValueDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1061,7 +1102,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
void MergeFrom(const EnumValueDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1074,13 +1115,13 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -1091,14 +1132,15 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// optional int32 number = 2;
inline bool has_number() const;
inline void clear_number();
static const int kNumberFieldNumber = 2;
inline ::google::protobuf::int32 number() const;
inline void set_number(::google::protobuf::int32 value);
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
inline bool has_options() const;
inline void clear_options();
@@ -1106,7 +1148,8 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
inline const ::google::protobuf::EnumValueOptions& options() const;
inline ::google::protobuf::EnumValueOptions* mutable_options();
inline ::google::protobuf::EnumValueOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::EnumValueOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
private:
inline void set_has_name();
@@ -1115,20 +1158,20 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
inline void clear_has_number();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::google::protobuf::EnumValueOptions* options_;
::google::protobuf::int32 number_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
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 EnumValueDescriptorProto* default_instance_;
};
@@ -1138,29 +1181,29 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
public:
ServiceDescriptorProto();
virtual ~ServiceDescriptorProto();
-
+
ServiceDescriptorProto(const ServiceDescriptorProto& from);
-
+
inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const ServiceDescriptorProto& default_instance();
-
+
void Swap(ServiceDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
ServiceDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1168,7 +1211,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
void MergeFrom(const ServiceDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1181,13 +1224,13 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -1198,7 +1241,8 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
inline int method_size() const;
inline void clear_method();
@@ -1210,7 +1254,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
method() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
mutable_method();
-
+
// optional .google.protobuf.ServiceOptions options = 3;
inline bool has_options() const;
inline void clear_options();
@@ -1218,27 +1262,28 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
inline const ::google::protobuf::ServiceOptions& options() const;
inline ::google::protobuf::ServiceOptions* mutable_options();
inline ::google::protobuf::ServiceOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::ServiceOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_;
::google::protobuf::ServiceOptions* options_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
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 ServiceDescriptorProto* default_instance_;
};
@@ -1248,29 +1293,29 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
public:
MethodDescriptorProto();
virtual ~MethodDescriptorProto();
-
+
MethodDescriptorProto(const MethodDescriptorProto& from);
-
+
inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MethodDescriptorProto& default_instance();
-
+
void Swap(MethodDescriptorProto* other);
-
+
// implements Message ----------------------------------------------
-
+
MethodDescriptorProto* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1278,7 +1323,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
void MergeFrom(const MethodDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1291,13 +1336,13 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
@@ -1308,7 +1353,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
-
+ inline void set_allocated_name(::std::string* name);
+
// optional string input_type = 2;
inline bool has_input_type() const;
inline void clear_input_type();
@@ -1319,7 +1365,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline void set_input_type(const char* value, size_t size);
inline ::std::string* mutable_input_type();
inline ::std::string* release_input_type();
-
+ inline void set_allocated_input_type(::std::string* input_type);
+
// optional string output_type = 3;
inline bool has_output_type() const;
inline void clear_output_type();
@@ -1330,7 +1377,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline void set_output_type(const char* value, size_t size);
inline ::std::string* mutable_output_type();
inline ::std::string* release_output_type();
-
+ inline void set_allocated_output_type(::std::string* output_type);
+
// optional .google.protobuf.MethodOptions options = 4;
inline bool has_options() const;
inline void clear_options();
@@ -1338,7 +1386,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline const ::google::protobuf::MethodOptions& options() const;
inline ::google::protobuf::MethodOptions* mutable_options();
inline ::google::protobuf::MethodOptions* release_options();
-
+ inline void set_allocated_options(::google::protobuf::MethodOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
private:
inline void set_has_name();
@@ -1349,21 +1398,21 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline void clear_has_output_type();
inline void set_has_options();
inline void clear_has_options();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_;
::std::string* input_type_;
::std::string* output_type_;
::google::protobuf::MethodOptions* options_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
-
+
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 MethodDescriptorProto* default_instance_;
};
@@ -1373,29 +1422,29 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
public:
FileOptions();
virtual ~FileOptions();
-
+
FileOptions(const FileOptions& from);
-
+
inline FileOptions& operator=(const FileOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileOptions& default_instance();
-
+
void Swap(FileOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
FileOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1403,7 +1452,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
void MergeFrom(const FileOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1416,11 +1465,11 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef FileOptions_OptimizeMode OptimizeMode;
static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
@@ -1445,9 +1494,9 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
OptimizeMode* value) {
return FileOptions_OptimizeMode_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional string java_package = 1;
inline bool has_java_package() const;
inline void clear_java_package();
@@ -1458,7 +1507,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
inline void set_java_package(const char* value, size_t size);
inline ::std::string* mutable_java_package();
inline ::std::string* release_java_package();
-
+ inline void set_allocated_java_package(::std::string* java_package);
+
// optional string java_outer_classname = 8;
inline bool has_java_outer_classname() const;
inline void clear_java_outer_classname();
@@ -1469,49 +1519,62 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
inline void set_java_outer_classname(const char* value, size_t size);
inline ::std::string* mutable_java_outer_classname();
inline ::std::string* release_java_outer_classname();
-
+ inline void set_allocated_java_outer_classname(::std::string* java_outer_classname);
+
// optional bool java_multiple_files = 10 [default = false];
inline bool has_java_multiple_files() const;
inline void clear_java_multiple_files();
static const int kJavaMultipleFilesFieldNumber = 10;
inline bool java_multiple_files() const;
inline void set_java_multiple_files(bool value);
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
inline bool has_java_generate_equals_and_hash() const;
inline void clear_java_generate_equals_and_hash();
static const int kJavaGenerateEqualsAndHashFieldNumber = 20;
inline bool java_generate_equals_and_hash() const;
inline void set_java_generate_equals_and_hash(bool value);
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
inline bool has_optimize_for() const;
inline void clear_optimize_for();
static const int kOptimizeForFieldNumber = 9;
inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
-
+
+ // optional string go_package = 11;
+ inline bool has_go_package() const;
+ inline void clear_go_package();
+ static const int kGoPackageFieldNumber = 11;
+ inline const ::std::string& go_package() const;
+ inline void set_go_package(const ::std::string& value);
+ inline void set_go_package(const char* value);
+ inline void set_go_package(const char* value, size_t size);
+ inline ::std::string* mutable_go_package();
+ inline ::std::string* release_go_package();
+ inline void set_allocated_go_package(::std::string* go_package);
+
// optional bool cc_generic_services = 16 [default = false];
inline bool has_cc_generic_services() const;
inline void clear_cc_generic_services();
static const int kCcGenericServicesFieldNumber = 16;
inline bool cc_generic_services() const;
inline void set_cc_generic_services(bool value);
-
+
// optional bool java_generic_services = 17 [default = false];
inline bool has_java_generic_services() const;
inline void clear_java_generic_services();
static const int kJavaGenericServicesFieldNumber = 17;
inline bool java_generic_services() const;
inline void set_java_generic_services(bool value);
-
+
// optional bool py_generic_services = 18 [default = false];
inline bool has_py_generic_services() const;
inline void clear_py_generic_services();
static const int kPyGenericServicesFieldNumber = 18;
inline bool py_generic_services() const;
inline void set_py_generic_services(bool value);
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -1523,7 +1586,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
private:
@@ -1537,17 +1600,19 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
inline void clear_has_java_generate_equals_and_hash();
inline void set_has_optimize_for();
inline void clear_has_optimize_for();
+ inline void set_has_go_package();
+ inline void clear_has_go_package();
inline void set_has_cc_generic_services();
inline void clear_has_cc_generic_services();
inline void set_has_java_generic_services();
inline void clear_has_java_generic_services();
inline void set_has_py_generic_services();
inline void clear_has_py_generic_services();
-
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* java_package_;
::std::string* java_outer_classname_;
int optimize_for_;
@@ -1555,16 +1620,17 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
bool java_generate_equals_and_hash_;
bool cc_generic_services_;
bool java_generic_services_;
+ ::std::string* go_package_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
bool py_generic_services_;
-
+
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32];
-
+ ::google::protobuf::uint32 _has_bits_[(10 + 31) / 32];
+
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 FileOptions* default_instance_;
};
@@ -1574,29 +1640,29 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
public:
MessageOptions();
virtual ~MessageOptions();
-
+
MessageOptions(const MessageOptions& from);
-
+
inline MessageOptions& operator=(const MessageOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MessageOptions& default_instance();
-
+
void Swap(MessageOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
MessageOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1604,7 +1670,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
void MergeFrom(const MessageOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1617,27 +1683,27 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional bool message_set_wire_format = 1 [default = false];
inline bool has_message_set_wire_format() const;
inline void clear_message_set_wire_format();
static const int kMessageSetWireFormatFieldNumber = 1;
inline bool message_set_wire_format() const;
inline void set_message_set_wire_format(bool value);
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
inline bool has_no_standard_descriptor_accessor() const;
inline void clear_no_standard_descriptor_accessor();
static const int kNoStandardDescriptorAccessorFieldNumber = 2;
inline bool no_standard_descriptor_accessor() const;
inline void set_no_standard_descriptor_accessor(bool value);
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -1649,7 +1715,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
private:
@@ -1657,22 +1723,22 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
inline void clear_has_message_set_wire_format();
inline void set_has_no_standard_descriptor_accessor();
inline void clear_has_no_standard_descriptor_accessor();
-
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
bool message_set_wire_format_;
bool no_standard_descriptor_accessor_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+
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 MessageOptions* default_instance_;
};
@@ -1682,29 +1748,29 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
public:
FieldOptions();
virtual ~FieldOptions();
-
+
FieldOptions(const FieldOptions& from);
-
+
inline FieldOptions& operator=(const FieldOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FieldOptions& default_instance();
-
+
void Swap(FieldOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
FieldOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1712,7 +1778,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
void MergeFrom(const FieldOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1725,11 +1791,11 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef FieldOptions_CType CType;
static const CType STRING = FieldOptions_CType_STRING;
static const CType CORD = FieldOptions_CType_CORD;
@@ -1754,30 +1820,37 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
CType* value) {
return FieldOptions_CType_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
inline bool has_ctype() const;
inline void clear_ctype();
static const int kCtypeFieldNumber = 1;
inline ::google::protobuf::FieldOptions_CType ctype() const;
inline void set_ctype(::google::protobuf::FieldOptions_CType value);
-
+
// optional bool packed = 2;
inline bool has_packed() const;
inline void clear_packed();
static const int kPackedFieldNumber = 2;
inline bool packed() const;
inline void set_packed(bool value);
-
+
+ // optional bool lazy = 5 [default = false];
+ inline bool has_lazy() const;
+ inline void clear_lazy();
+ static const int kLazyFieldNumber = 5;
+ inline bool lazy() const;
+ inline void set_lazy(bool value);
+
// optional bool deprecated = 3 [default = false];
inline bool has_deprecated() const;
inline void clear_deprecated();
static const int kDeprecatedFieldNumber = 3;
inline bool deprecated() const;
inline void set_deprecated(bool value);
-
+
// optional string experimental_map_key = 9;
inline bool has_experimental_map_key() const;
inline void clear_experimental_map_key();
@@ -1788,7 +1861,15 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
inline void set_experimental_map_key(const char* value, size_t size);
inline ::std::string* mutable_experimental_map_key();
inline ::std::string* release_experimental_map_key();
-
+ inline void set_allocated_experimental_map_key(::std::string* experimental_map_key);
+
+ // optional bool weak = 10 [default = false];
+ inline bool has_weak() const;
+ inline void clear_weak();
+ static const int kWeakFieldNumber = 10;
+ inline bool weak() const;
+ inline void set_weak(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -1800,7 +1881,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
private:
@@ -1808,28 +1889,34 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
inline void clear_has_ctype();
inline void set_has_packed();
inline void clear_has_packed();
+ inline void set_has_lazy();
+ inline void clear_has_lazy();
inline void set_has_deprecated();
inline void clear_has_deprecated();
inline void set_has_experimental_map_key();
inline void clear_has_experimental_map_key();
-
+ inline void set_has_weak();
+ inline void clear_has_weak();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
int ctype_;
bool packed_;
+ bool lazy_;
bool deprecated_;
+ bool weak_;
::std::string* experimental_map_key_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
-
+ ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
+
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 FieldOptions* default_instance_;
};
@@ -1839,29 +1926,29 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
public:
EnumOptions();
virtual ~EnumOptions();
-
+
EnumOptions(const EnumOptions& from);
-
+
inline EnumOptions& operator=(const EnumOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumOptions& default_instance();
-
+
void Swap(EnumOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
EnumOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1869,7 +1956,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
void MergeFrom(const EnumOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1882,13 +1969,20 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
+ // optional bool allow_alias = 2 [default = true];
+ inline bool has_allow_alias() const;
+ inline void clear_allow_alias();
+ static const int kAllowAliasFieldNumber = 2;
+ inline bool allow_alias() const;
+ inline void set_allow_alias(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -1900,24 +1994,27 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
private:
-
+ inline void set_has_allow_alias();
+ inline void clear_has_allow_alias();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+ bool allow_alias_;
+
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
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 EnumOptions* default_instance_;
};
@@ -1927,29 +2024,29 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
public:
EnumValueOptions();
virtual ~EnumValueOptions();
-
+
EnumValueOptions(const EnumValueOptions& from);
-
+
inline EnumValueOptions& operator=(const EnumValueOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumValueOptions& default_instance();
-
+
void Swap(EnumValueOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
EnumValueOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -1957,7 +2054,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
void MergeFrom(const EnumValueOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1970,13 +2067,13 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -1988,24 +2085,24 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
private:
-
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+
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 EnumValueOptions* default_instance_;
};
@@ -2015,29 +2112,29 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
public:
ServiceOptions();
virtual ~ServiceOptions();
-
+
ServiceOptions(const ServiceOptions& from);
-
+
inline ServiceOptions& operator=(const ServiceOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const ServiceOptions& default_instance();
-
+
void Swap(ServiceOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
ServiceOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2045,7 +2142,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
void MergeFrom(const ServiceOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2058,13 +2155,13 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -2076,24 +2173,24 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
private:
-
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+
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 ServiceOptions* default_instance_;
};
@@ -2103,29 +2200,29 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
public:
MethodOptions();
virtual ~MethodOptions();
-
+
MethodOptions(const MethodOptions& from);
-
+
inline MethodOptions& operator=(const MethodOptions& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MethodOptions& default_instance();
-
+
void Swap(MethodOptions* other);
-
+
// implements Message ----------------------------------------------
-
+
MethodOptions* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2133,7 +2230,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
void MergeFrom(const MethodOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2146,13 +2243,13 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@@ -2164,24 +2261,24 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
uninterpreted_option() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
private:
-
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+
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 MethodOptions* default_instance_;
};
@@ -2191,29 +2288,29 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
public:
UninterpretedOption_NamePart();
virtual ~UninterpretedOption_NamePart();
-
+
UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from);
-
+
inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const UninterpretedOption_NamePart& default_instance();
-
+
void Swap(UninterpretedOption_NamePart* other);
-
+
// implements Message ----------------------------------------------
-
+
UninterpretedOption_NamePart* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2221,7 +2318,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
void MergeFrom(const UninterpretedOption_NamePart& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2234,13 +2331,13 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// required string name_part = 1;
inline bool has_name_part() const;
inline void clear_name_part();
@@ -2251,33 +2348,34 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
inline void set_name_part(const char* value, size_t size);
inline ::std::string* mutable_name_part();
inline ::std::string* release_name_part();
-
+ inline void set_allocated_name_part(::std::string* name_part);
+
// required bool is_extension = 2;
inline bool has_is_extension() const;
inline void clear_is_extension();
static const int kIsExtensionFieldNumber = 2;
inline bool is_extension() const;
inline void set_is_extension(bool value);
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
private:
inline void set_has_name_part();
inline void clear_has_name_part();
inline void set_has_is_extension();
inline void clear_has_is_extension();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::std::string* name_part_;
bool is_extension_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+
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 UninterpretedOption_NamePart* default_instance_;
};
@@ -2287,29 +2385,29 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
public:
UninterpretedOption();
virtual ~UninterpretedOption();
-
+
UninterpretedOption(const UninterpretedOption& from);
-
+
inline UninterpretedOption& operator=(const UninterpretedOption& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const UninterpretedOption& default_instance();
-
+
void Swap(UninterpretedOption* other);
-
+
// implements Message ----------------------------------------------
-
+
UninterpretedOption* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2317,7 +2415,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
void MergeFrom(const UninterpretedOption& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2330,15 +2428,15 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef UninterpretedOption_NamePart NamePart;
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
inline int name_size() const;
inline void clear_name();
@@ -2350,7 +2448,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
name() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
mutable_name();
-
+
// optional string identifier_value = 3;
inline bool has_identifier_value() const;
inline void clear_identifier_value();
@@ -2361,28 +2459,29 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
inline void set_identifier_value(const char* value, size_t size);
inline ::std::string* mutable_identifier_value();
inline ::std::string* release_identifier_value();
-
+ inline void set_allocated_identifier_value(::std::string* identifier_value);
+
// optional uint64 positive_int_value = 4;
inline bool has_positive_int_value() const;
inline void clear_positive_int_value();
static const int kPositiveIntValueFieldNumber = 4;
inline ::google::protobuf::uint64 positive_int_value() const;
inline void set_positive_int_value(::google::protobuf::uint64 value);
-
+
// optional int64 negative_int_value = 5;
inline bool has_negative_int_value() const;
inline void clear_negative_int_value();
static const int kNegativeIntValueFieldNumber = 5;
inline ::google::protobuf::int64 negative_int_value() const;
inline void set_negative_int_value(::google::protobuf::int64 value);
-
+
// optional double double_value = 6;
inline bool has_double_value() const;
inline void clear_double_value();
static const int kDoubleValueFieldNumber = 6;
inline double double_value() const;
inline void set_double_value(double value);
-
+
// optional bytes string_value = 7;
inline bool has_string_value() const;
inline void clear_string_value();
@@ -2393,7 +2492,8 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
inline void set_string_value(const void* value, size_t size);
inline ::std::string* mutable_string_value();
inline ::std::string* release_string_value();
-
+ inline void set_allocated_string_value(::std::string* string_value);
+
// optional string aggregate_value = 8;
inline bool has_aggregate_value() const;
inline void clear_aggregate_value();
@@ -2404,7 +2504,8 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
inline void set_aggregate_value(const char* value, size_t size);
inline ::std::string* mutable_aggregate_value();
inline ::std::string* release_aggregate_value();
-
+ inline void set_allocated_aggregate_value(::std::string* aggregate_value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
private:
inline void set_has_identifier_value();
@@ -2419,9 +2520,9 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
inline void clear_has_string_value();
inline void set_has_aggregate_value();
inline void clear_has_aggregate_value();
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart > name_;
::std::string* identifier_value_;
::google::protobuf::uint64 positive_int_value_;
@@ -2429,14 +2530,14 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
double double_value_;
::std::string* string_value_;
::std::string* aggregate_value_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
-
+
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 UninterpretedOption* default_instance_;
};
@@ -2446,29 +2547,29 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
public:
SourceCodeInfo_Location();
virtual ~SourceCodeInfo_Location();
-
+
SourceCodeInfo_Location(const SourceCodeInfo_Location& from);
-
+
inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const SourceCodeInfo_Location& default_instance();
-
+
void Swap(SourceCodeInfo_Location* other);
-
+
// implements Message ----------------------------------------------
-
+
SourceCodeInfo_Location* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2476,7 +2577,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
void MergeFrom(const SourceCodeInfo_Location& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2489,13 +2590,13 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated int32 path = 1 [packed = true];
inline int path_size() const;
inline void clear_path();
@@ -2507,7 +2608,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
path() const;
inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
mutable_path();
-
+
// repeated int32 span = 2 [packed = true];
inline int span_size() const;
inline void clear_span();
@@ -2519,24 +2620,54 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
span() const;
inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
mutable_span();
-
+
+ // optional string leading_comments = 3;
+ inline bool has_leading_comments() const;
+ inline void clear_leading_comments();
+ static const int kLeadingCommentsFieldNumber = 3;
+ inline const ::std::string& leading_comments() const;
+ inline void set_leading_comments(const ::std::string& value);
+ inline void set_leading_comments(const char* value);
+ inline void set_leading_comments(const char* value, size_t size);
+ inline ::std::string* mutable_leading_comments();
+ inline ::std::string* release_leading_comments();
+ inline void set_allocated_leading_comments(::std::string* leading_comments);
+
+ // optional string trailing_comments = 4;
+ inline bool has_trailing_comments() const;
+ inline void clear_trailing_comments();
+ static const int kTrailingCommentsFieldNumber = 4;
+ inline const ::std::string& trailing_comments() const;
+ inline void set_trailing_comments(const ::std::string& value);
+ inline void set_trailing_comments(const char* value);
+ inline void set_trailing_comments(const char* value, size_t size);
+ inline ::std::string* mutable_trailing_comments();
+ inline ::std::string* release_trailing_comments();
+ inline void set_allocated_trailing_comments(::std::string* trailing_comments);
+
// @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
private:
-
+ inline void set_has_leading_comments();
+ inline void clear_has_leading_comments();
+ inline void set_has_trailing_comments();
+ inline void clear_has_trailing_comments();
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_;
mutable int _path_cached_byte_size_;
::google::protobuf::RepeatedField< ::google::protobuf::int32 > span_;
mutable int _span_cached_byte_size_;
-
+ ::std::string* leading_comments_;
+ ::std::string* trailing_comments_;
+
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+
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 SourceCodeInfo_Location* default_instance_;
};
@@ -2546,29 +2677,29 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
public:
SourceCodeInfo();
virtual ~SourceCodeInfo();
-
+
SourceCodeInfo(const SourceCodeInfo& from);
-
+
inline SourceCodeInfo& operator=(const SourceCodeInfo& from) {
CopyFrom(from);
return *this;
}
-
+
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
-
+
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const SourceCodeInfo& default_instance();
-
+
void Swap(SourceCodeInfo* other);
-
+
// implements Message ----------------------------------------------
-
+
SourceCodeInfo* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
@@ -2576,7 +2707,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
void MergeFrom(const SourceCodeInfo& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2589,15 +2720,15 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
public:
-
+
::google::protobuf::Metadata GetMetadata() const;
-
+
// nested types ----------------------------------------------------
-
+
typedef SourceCodeInfo_Location Location;
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
inline int location_size() const;
inline void clear_location();
@@ -2609,21 +2740,21 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
location() const;
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
mutable_location();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
private:
-
+
::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_;
-
+
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+
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 SourceCodeInfo* default_instance_;
};
@@ -2720,6 +2851,18 @@ inline ::std::string* FileDescriptorProto::release_name() {
return temp;
}
}
+inline void FileDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string package = 2;
inline bool FileDescriptorProto::has_package() const {
@@ -2778,6 +2921,18 @@ inline ::std::string* FileDescriptorProto::release_package() {
return temp;
}
}
+inline void FileDescriptorProto::set_allocated_package(::std::string* package) {
+ if (package_ != &::google::protobuf::internal::kEmptyString) {
+ delete package_;
+ }
+ if (package) {
+ set_has_package();
+ package_ = package;
+ } else {
+ clear_has_package();
+ package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated string dependency = 3;
inline int FileDescriptorProto::dependency_size() const {
@@ -2823,6 +2978,56 @@ FileDescriptorProto::mutable_dependency() {
return &dependency_;
}
+// repeated int32 public_dependency = 10;
+inline int FileDescriptorProto::public_dependency_size() const {
+ return public_dependency_.size();
+}
+inline void FileDescriptorProto::clear_public_dependency() {
+ public_dependency_.Clear();
+}
+inline ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
+ return public_dependency_.Get(index);
+}
+inline void FileDescriptorProto::set_public_dependency(int index, ::google::protobuf::int32 value) {
+ public_dependency_.Set(index, value);
+}
+inline void FileDescriptorProto::add_public_dependency(::google::protobuf::int32 value) {
+ public_dependency_.Add(value);
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::public_dependency() const {
+ return public_dependency_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_public_dependency() {
+ return &public_dependency_;
+}
+
+// repeated int32 weak_dependency = 11;
+inline int FileDescriptorProto::weak_dependency_size() const {
+ return weak_dependency_.size();
+}
+inline void FileDescriptorProto::clear_weak_dependency() {
+ weak_dependency_.Clear();
+}
+inline ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
+ return weak_dependency_.Get(index);
+}
+inline void FileDescriptorProto::set_weak_dependency(int index, ::google::protobuf::int32 value) {
+ weak_dependency_.Set(index, value);
+}
+inline void FileDescriptorProto::add_weak_dependency(::google::protobuf::int32 value) {
+ weak_dependency_.Add(value);
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::weak_dependency() const {
+ return weak_dependency_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_weak_dependency() {
+ return &weak_dependency_;
+}
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
inline int FileDescriptorProto::message_type_size() const {
return message_type_.size();
@@ -2925,13 +3130,13 @@ FileDescriptorProto::mutable_extension() {
// optional .google.protobuf.FileOptions options = 8;
inline bool FileDescriptorProto::has_options() const {
- return (_has_bits_[0] & 0x00000080u) != 0;
+ return (_has_bits_[0] & 0x00000200u) != 0;
}
inline void FileDescriptorProto::set_has_options() {
- _has_bits_[0] |= 0x00000080u;
+ _has_bits_[0] |= 0x00000200u;
}
inline void FileDescriptorProto::clear_has_options() {
- _has_bits_[0] &= ~0x00000080u;
+ _has_bits_[0] &= ~0x00000200u;
}
inline void FileDescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
@@ -2951,16 +3156,25 @@ inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
inline bool FileDescriptorProto::has_source_code_info() const {
- return (_has_bits_[0] & 0x00000100u) != 0;
+ return (_has_bits_[0] & 0x00000400u) != 0;
}
inline void FileDescriptorProto::set_has_source_code_info() {
- _has_bits_[0] |= 0x00000100u;
+ _has_bits_[0] |= 0x00000400u;
}
inline void FileDescriptorProto::clear_has_source_code_info() {
- _has_bits_[0] &= ~0x00000100u;
+ _has_bits_[0] &= ~0x00000400u;
}
inline void FileDescriptorProto::clear_source_code_info() {
if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
@@ -2980,6 +3194,15 @@ inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_c
source_code_info_ = NULL;
return temp;
}
+inline void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) {
+ delete source_code_info_;
+ source_code_info_ = source_code_info;
+ if (source_code_info) {
+ set_has_source_code_info();
+ } else {
+ clear_has_source_code_info();
+ }
+}
// -------------------------------------------------------------------
@@ -3090,6 +3313,18 @@ inline ::std::string* DescriptorProto::release_name() {
return temp;
}
}
+inline void DescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
inline int DescriptorProto::field_size() const {
@@ -3244,6 +3479,15 @@ inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -3306,6 +3550,18 @@ inline ::std::string* FieldDescriptorProto::release_name() {
return temp;
}
}
+inline void FieldDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional int32 number = 3;
inline bool FieldDescriptorProto::has_number() const {
@@ -3347,7 +3603,7 @@ inline ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::labe
return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_);
}
inline void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) {
- GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
+ assert(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
set_has_label();
label_ = value;
}
@@ -3370,7 +3626,7 @@ inline ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type(
return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_);
}
inline void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) {
- GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
+ assert(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
set_has_type();
type_ = value;
}
@@ -3432,6 +3688,18 @@ inline ::std::string* FieldDescriptorProto::release_type_name() {
return temp;
}
}
+inline void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) {
+ if (type_name_ != &::google::protobuf::internal::kEmptyString) {
+ delete type_name_;
+ }
+ if (type_name) {
+ set_has_type_name();
+ type_name_ = type_name;
+ } else {
+ clear_has_type_name();
+ type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string extendee = 2;
inline bool FieldDescriptorProto::has_extendee() const {
@@ -3490,6 +3758,18 @@ inline ::std::string* FieldDescriptorProto::release_extendee() {
return temp;
}
}
+inline void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) {
+ if (extendee_ != &::google::protobuf::internal::kEmptyString) {
+ delete extendee_;
+ }
+ if (extendee) {
+ set_has_extendee();
+ extendee_ = extendee;
+ } else {
+ clear_has_extendee();
+ extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string default_value = 7;
inline bool FieldDescriptorProto::has_default_value() const {
@@ -3548,6 +3828,18 @@ inline ::std::string* FieldDescriptorProto::release_default_value() {
return temp;
}
}
+inline void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) {
+ if (default_value_ != &::google::protobuf::internal::kEmptyString) {
+ delete default_value_;
+ }
+ if (default_value) {
+ set_has_default_value();
+ default_value_ = default_value;
+ } else {
+ clear_has_default_value();
+ default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional .google.protobuf.FieldOptions options = 8;
inline bool FieldDescriptorProto::has_options() const {
@@ -3577,6 +3869,15 @@ inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options()
options_ = NULL;
return temp;
}
+inline void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -3639,6 +3940,18 @@ inline ::std::string* EnumDescriptorProto::release_name() {
return temp;
}
}
+inline void EnumDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
inline int EnumDescriptorProto::value_size() const {
@@ -3693,6 +4006,15 @@ inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -3755,6 +4077,18 @@ inline ::std::string* EnumValueDescriptorProto::release_name() {
return temp;
}
}
+inline void EnumValueDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional int32 number = 2;
inline bool EnumValueDescriptorProto::has_number() const {
@@ -3806,6 +4140,15 @@ inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_o
options_ = NULL;
return temp;
}
+inline void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -3868,6 +4211,18 @@ inline ::std::string* ServiceDescriptorProto::release_name() {
return temp;
}
}
+inline void ServiceDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
inline int ServiceDescriptorProto::method_size() const {
@@ -3922,6 +4277,15 @@ inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_optio
options_ = NULL;
return temp;
}
+inline void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -3984,6 +4348,18 @@ inline ::std::string* MethodDescriptorProto::release_name() {
return temp;
}
}
+inline void MethodDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_;
+ }
+ if (name) {
+ set_has_name();
+ name_ = name;
+ } else {
+ clear_has_name();
+ name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string input_type = 2;
inline bool MethodDescriptorProto::has_input_type() const {
@@ -4042,6 +4418,18 @@ inline ::std::string* MethodDescriptorProto::release_input_type() {
return temp;
}
}
+inline void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) {
+ if (input_type_ != &::google::protobuf::internal::kEmptyString) {
+ delete input_type_;
+ }
+ if (input_type) {
+ set_has_input_type();
+ input_type_ = input_type;
+ } else {
+ clear_has_input_type();
+ input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string output_type = 3;
inline bool MethodDescriptorProto::has_output_type() const {
@@ -4100,6 +4488,18 @@ inline ::std::string* MethodDescriptorProto::release_output_type() {
return temp;
}
}
+inline void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) {
+ if (output_type_ != &::google::protobuf::internal::kEmptyString) {
+ delete output_type_;
+ }
+ if (output_type) {
+ set_has_output_type();
+ output_type_ = output_type;
+ } else {
+ clear_has_output_type();
+ output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional .google.protobuf.MethodOptions options = 4;
inline bool MethodDescriptorProto::has_options() const {
@@ -4129,6 +4529,15 @@ inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options
options_ = NULL;
return temp;
}
+inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+}
// -------------------------------------------------------------------
@@ -4191,6 +4600,18 @@ inline ::std::string* FileOptions::release_java_package() {
return temp;
}
}
+inline void FileOptions::set_allocated_java_package(::std::string* java_package) {
+ if (java_package_ != &::google::protobuf::internal::kEmptyString) {
+ delete java_package_;
+ }
+ if (java_package) {
+ set_has_java_package();
+ java_package_ = java_package;
+ } else {
+ clear_has_java_package();
+ java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string java_outer_classname = 8;
inline bool FileOptions::has_java_outer_classname() const {
@@ -4249,6 +4670,18 @@ inline ::std::string* FileOptions::release_java_outer_classname() {
return temp;
}
}
+inline void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) {
+ if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) {
+ delete java_outer_classname_;
+ }
+ if (java_outer_classname) {
+ set_has_java_outer_classname();
+ java_outer_classname_ = java_outer_classname;
+ } else {
+ clear_has_java_outer_classname();
+ java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional bool java_multiple_files = 10 [default = false];
inline bool FileOptions::has_java_multiple_files() const {
@@ -4312,20 +4745,90 @@ inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for()
return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_);
}
inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) {
- GOOGLE_DCHECK(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
+ assert(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
set_has_optimize_for();
optimize_for_ = value;
}
+// optional string go_package = 11;
+inline bool FileOptions::has_go_package() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void FileOptions::set_has_go_package() {
+ _has_bits_[0] |= 0x00000020u;
+}
+inline void FileOptions::clear_has_go_package() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+inline void FileOptions::clear_go_package() {
+ if (go_package_ != &::google::protobuf::internal::kEmptyString) {
+ go_package_->clear();
+ }
+ clear_has_go_package();
+}
+inline const ::std::string& FileOptions::go_package() const {
+ return *go_package_;
+}
+inline void FileOptions::set_go_package(const ::std::string& value) {
+ set_has_go_package();
+ if (go_package_ == &::google::protobuf::internal::kEmptyString) {
+ go_package_ = new ::std::string;
+ }
+ go_package_->assign(value);
+}
+inline void FileOptions::set_go_package(const char* value) {
+ set_has_go_package();
+ if (go_package_ == &::google::protobuf::internal::kEmptyString) {
+ go_package_ = new ::std::string;
+ }
+ go_package_->assign(value);
+}
+inline void FileOptions::set_go_package(const char* value, size_t size) {
+ set_has_go_package();
+ if (go_package_ == &::google::protobuf::internal::kEmptyString) {
+ go_package_ = new ::std::string;
+ }
+ go_package_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* FileOptions::mutable_go_package() {
+ set_has_go_package();
+ if (go_package_ == &::google::protobuf::internal::kEmptyString) {
+ go_package_ = new ::std::string;
+ }
+ return go_package_;
+}
+inline ::std::string* FileOptions::release_go_package() {
+ clear_has_go_package();
+ if (go_package_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = go_package_;
+ go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+inline void FileOptions::set_allocated_go_package(::std::string* go_package) {
+ if (go_package_ != &::google::protobuf::internal::kEmptyString) {
+ delete go_package_;
+ }
+ if (go_package) {
+ set_has_go_package();
+ go_package_ = go_package;
+ } else {
+ clear_has_go_package();
+ go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
// optional bool cc_generic_services = 16 [default = false];
inline bool FileOptions::has_cc_generic_services() const {
- return (_has_bits_[0] & 0x00000020u) != 0;
+ return (_has_bits_[0] & 0x00000040u) != 0;
}
inline void FileOptions::set_has_cc_generic_services() {
- _has_bits_[0] |= 0x00000020u;
+ _has_bits_[0] |= 0x00000040u;
}
inline void FileOptions::clear_has_cc_generic_services() {
- _has_bits_[0] &= ~0x00000020u;
+ _has_bits_[0] &= ~0x00000040u;
}
inline void FileOptions::clear_cc_generic_services() {
cc_generic_services_ = false;
@@ -4341,13 +4844,13 @@ inline void FileOptions::set_cc_generic_services(bool value) {
// optional bool java_generic_services = 17 [default = false];
inline bool FileOptions::has_java_generic_services() const {
- return (_has_bits_[0] & 0x00000040u) != 0;
+ return (_has_bits_[0] & 0x00000080u) != 0;
}
inline void FileOptions::set_has_java_generic_services() {
- _has_bits_[0] |= 0x00000040u;
+ _has_bits_[0] |= 0x00000080u;
}
inline void FileOptions::clear_has_java_generic_services() {
- _has_bits_[0] &= ~0x00000040u;
+ _has_bits_[0] &= ~0x00000080u;
}
inline void FileOptions::clear_java_generic_services() {
java_generic_services_ = false;
@@ -4363,13 +4866,13 @@ inline void FileOptions::set_java_generic_services(bool value) {
// optional bool py_generic_services = 18 [default = false];
inline bool FileOptions::has_py_generic_services() const {
- return (_has_bits_[0] & 0x00000080u) != 0;
+ return (_has_bits_[0] & 0x00000100u) != 0;
}
inline void FileOptions::set_has_py_generic_services() {
- _has_bits_[0] |= 0x00000080u;
+ _has_bits_[0] |= 0x00000100u;
}
inline void FileOptions::clear_has_py_generic_services() {
- _has_bits_[0] &= ~0x00000080u;
+ _has_bits_[0] &= ~0x00000100u;
}
inline void FileOptions::clear_py_generic_services() {
py_generic_services_ = false;
@@ -4503,7 +5006,7 @@ inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const {
return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_);
}
inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) {
- GOOGLE_DCHECK(::google::protobuf::FieldOptions_CType_IsValid(value));
+ assert(::google::protobuf::FieldOptions_CType_IsValid(value));
set_has_ctype();
ctype_ = value;
}
@@ -4530,15 +5033,37 @@ inline void FieldOptions::set_packed(bool value) {
packed_ = value;
}
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::has_lazy() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void FieldOptions::set_has_lazy() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void FieldOptions::clear_has_lazy() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void FieldOptions::clear_lazy() {
+ lazy_ = false;
+ clear_has_lazy();
+}
+inline bool FieldOptions::lazy() const {
+ return lazy_;
+}
+inline void FieldOptions::set_lazy(bool value) {
+ set_has_lazy();
+ lazy_ = value;
+}
+
// optional bool deprecated = 3 [default = false];
inline bool FieldOptions::has_deprecated() const {
- return (_has_bits_[0] & 0x00000004u) != 0;
+ return (_has_bits_[0] & 0x00000008u) != 0;
}
inline void FieldOptions::set_has_deprecated() {
- _has_bits_[0] |= 0x00000004u;
+ _has_bits_[0] |= 0x00000008u;
}
inline void FieldOptions::clear_has_deprecated() {
- _has_bits_[0] &= ~0x00000004u;
+ _has_bits_[0] &= ~0x00000008u;
}
inline void FieldOptions::clear_deprecated() {
deprecated_ = false;
@@ -4554,13 +5079,13 @@ inline void FieldOptions::set_deprecated(bool value) {
// optional string experimental_map_key = 9;
inline bool FieldOptions::has_experimental_map_key() const {
- return (_has_bits_[0] & 0x00000008u) != 0;
+ return (_has_bits_[0] & 0x00000010u) != 0;
}
inline void FieldOptions::set_has_experimental_map_key() {
- _has_bits_[0] |= 0x00000008u;
+ _has_bits_[0] |= 0x00000010u;
}
inline void FieldOptions::clear_has_experimental_map_key() {
- _has_bits_[0] &= ~0x00000008u;
+ _has_bits_[0] &= ~0x00000010u;
}
inline void FieldOptions::clear_experimental_map_key() {
if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
@@ -4609,6 +5134,40 @@ inline ::std::string* FieldOptions::release_experimental_map_key() {
return temp;
}
}
+inline void FieldOptions::set_allocated_experimental_map_key(::std::string* experimental_map_key) {
+ if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
+ delete experimental_map_key_;
+ }
+ if (experimental_map_key) {
+ set_has_experimental_map_key();
+ experimental_map_key_ = experimental_map_key;
+ } else {
+ clear_has_experimental_map_key();
+ experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
+// optional bool weak = 10 [default = false];
+inline bool FieldOptions::has_weak() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void FieldOptions::set_has_weak() {
+ _has_bits_[0] |= 0x00000020u;
+}
+inline void FieldOptions::clear_has_weak() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+inline void FieldOptions::clear_weak() {
+ weak_ = false;
+ clear_has_weak();
+}
+inline bool FieldOptions::weak() const {
+ return weak_;
+}
+inline void FieldOptions::set_weak(bool value) {
+ set_has_weak();
+ weak_ = value;
+}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int FieldOptions::uninterpreted_option_size() const {
@@ -4639,6 +5198,28 @@ FieldOptions::mutable_uninterpreted_option() {
// EnumOptions
+// optional bool allow_alias = 2 [default = true];
+inline bool EnumOptions::has_allow_alias() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void EnumOptions::set_has_allow_alias() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void EnumOptions::clear_has_allow_alias() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void EnumOptions::clear_allow_alias() {
+ allow_alias_ = true;
+ clear_has_allow_alias();
+}
+inline bool EnumOptions::allow_alias() const {
+ return allow_alias_;
+}
+inline void EnumOptions::set_allow_alias(bool value) {
+ set_has_allow_alias();
+ allow_alias_ = value;
+}
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int EnumOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@@ -4812,6 +5393,18 @@ inline ::std::string* UninterpretedOption_NamePart::release_name_part() {
return temp;
}
}
+inline void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) {
+ if (name_part_ != &::google::protobuf::internal::kEmptyString) {
+ delete name_part_;
+ }
+ if (name_part) {
+ set_has_name_part();
+ name_part_ = name_part;
+ } else {
+ clear_has_name_part();
+ name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// required bool is_extension = 2;
inline bool UninterpretedOption_NamePart::has_is_extension() const {
@@ -4921,6 +5514,18 @@ inline ::std::string* UninterpretedOption::release_identifier_value() {
return temp;
}
}
+inline void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) {
+ if (identifier_value_ != &::google::protobuf::internal::kEmptyString) {
+ delete identifier_value_;
+ }
+ if (identifier_value) {
+ set_has_identifier_value();
+ identifier_value_ = identifier_value;
+ } else {
+ clear_has_identifier_value();
+ identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional uint64 positive_int_value = 4;
inline bool UninterpretedOption::has_positive_int_value() const {
@@ -5045,6 +5650,18 @@ inline ::std::string* UninterpretedOption::release_string_value() {
return temp;
}
}
+inline void UninterpretedOption::set_allocated_string_value(::std::string* string_value) {
+ if (string_value_ != &::google::protobuf::internal::kEmptyString) {
+ delete string_value_;
+ }
+ if (string_value) {
+ set_has_string_value();
+ string_value_ = string_value;
+ } else {
+ clear_has_string_value();
+ string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// optional string aggregate_value = 8;
inline bool UninterpretedOption::has_aggregate_value() const {
@@ -5103,6 +5720,18 @@ inline ::std::string* UninterpretedOption::release_aggregate_value() {
return temp;
}
}
+inline void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) {
+ if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) {
+ delete aggregate_value_;
+ }
+ if (aggregate_value) {
+ set_has_aggregate_value();
+ aggregate_value_ = aggregate_value;
+ } else {
+ clear_has_aggregate_value();
+ aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
// -------------------------------------------------------------------
@@ -5158,6 +5787,146 @@ SourceCodeInfo_Location::mutable_span() {
return &span_;
}
+// optional string leading_comments = 3;
+inline bool SourceCodeInfo_Location::has_leading_comments() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void SourceCodeInfo_Location::set_has_leading_comments() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void SourceCodeInfo_Location::clear_has_leading_comments() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void SourceCodeInfo_Location::clear_leading_comments() {
+ if (leading_comments_ != &::google::protobuf::internal::kEmptyString) {
+ leading_comments_->clear();
+ }
+ clear_has_leading_comments();
+}
+inline const ::std::string& SourceCodeInfo_Location::leading_comments() const {
+ return *leading_comments_;
+}
+inline void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) {
+ set_has_leading_comments();
+ if (leading_comments_ == &::google::protobuf::internal::kEmptyString) {
+ leading_comments_ = new ::std::string;
+ }
+ leading_comments_->assign(value);
+}
+inline void SourceCodeInfo_Location::set_leading_comments(const char* value) {
+ set_has_leading_comments();
+ if (leading_comments_ == &::google::protobuf::internal::kEmptyString) {
+ leading_comments_ = new ::std::string;
+ }
+ leading_comments_->assign(value);
+}
+inline void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) {
+ set_has_leading_comments();
+ if (leading_comments_ == &::google::protobuf::internal::kEmptyString) {
+ leading_comments_ = new ::std::string;
+ }
+ leading_comments_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+ set_has_leading_comments();
+ if (leading_comments_ == &::google::protobuf::internal::kEmptyString) {
+ leading_comments_ = new ::std::string;
+ }
+ return leading_comments_;
+}
+inline ::std::string* SourceCodeInfo_Location::release_leading_comments() {
+ clear_has_leading_comments();
+ if (leading_comments_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = leading_comments_;
+ leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+inline void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) {
+ if (leading_comments_ != &::google::protobuf::internal::kEmptyString) {
+ delete leading_comments_;
+ }
+ if (leading_comments) {
+ set_has_leading_comments();
+ leading_comments_ = leading_comments;
+ } else {
+ clear_has_leading_comments();
+ leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
+// optional string trailing_comments = 4;
+inline bool SourceCodeInfo_Location::has_trailing_comments() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void SourceCodeInfo_Location::set_has_trailing_comments() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void SourceCodeInfo_Location::clear_has_trailing_comments() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void SourceCodeInfo_Location::clear_trailing_comments() {
+ if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_->clear();
+ }
+ clear_has_trailing_comments();
+}
+inline const ::std::string& SourceCodeInfo_Location::trailing_comments() const {
+ return *trailing_comments_;
+}
+inline void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) {
+ set_has_trailing_comments();
+ if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_ = new ::std::string;
+ }
+ trailing_comments_->assign(value);
+}
+inline void SourceCodeInfo_Location::set_trailing_comments(const char* value) {
+ set_has_trailing_comments();
+ if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_ = new ::std::string;
+ }
+ trailing_comments_->assign(value);
+}
+inline void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) {
+ set_has_trailing_comments();
+ if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_ = new ::std::string;
+ }
+ trailing_comments_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+ set_has_trailing_comments();
+ if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) {
+ trailing_comments_ = new ::std::string;
+ }
+ return trailing_comments_;
+}
+inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() {
+ clear_has_trailing_comments();
+ if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = trailing_comments_;
+ trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+inline void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) {
+ if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) {
+ delete trailing_comments_;
+ }
+ if (trailing_comments) {
+ set_has_trailing_comments();
+ trailing_comments_ = trailing_comments;
+ } else {
+ clear_has_trailing_comments();
+ trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
// -------------------------------------------------------------------
// SourceCodeInfo
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 4eeb43b5..a785f79f 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -59,6 +59,11 @@ message FileDescriptorProto {
// Names of files imported by this file.
repeated string dependency = 3;
+ // Indexes of the public imported files in the dependency list above.
+ repeated int32 public_dependency = 10;
+ // Indexes of the weak imported files in the dependency list.
+ // For Google-internal migration only. Do not use.
+ repeated int32 weak_dependency = 11;
// All top-level definitions in this file.
repeated DescriptorProto message_type = 4;
@@ -101,13 +106,13 @@ message FieldDescriptorProto {
// Order is weird for historical reasons.
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
- TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
- // take 10 bytes. Use TYPE_SINT64 if negative
- // values are likely.
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
+ // negative values are likely.
+ TYPE_INT64 = 3;
TYPE_UINT64 = 4;
- TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
- // take 10 bytes. Use TYPE_SINT32 if negative
- // values are likely.
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
+ // negative values are likely.
+ TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
@@ -199,6 +204,7 @@ message MethodDescriptorProto {
optional MethodOptions options = 4;
}
+
// ===================================================================
// Options
@@ -271,6 +277,9 @@ message FileOptions {
}
optional OptimizeMode optimize_for = 9 [default=SPEED];
+ // Sets the Go package where structs generated from this .proto will be
+ // placed. There is no default.
+ optional string go_package = 11;
@@ -349,6 +358,37 @@ message FieldOptions {
optional bool packed = 2;
+
+ // Should this field be parsed lazily? Lazy applies only to message-type
+ // fields. It means that when the outer message is initially parsed, the
+ // inner message's contents will not be parsed but instead stored in encoded
+ // form. The inner message will actually be parsed when it is first accessed.
+ //
+ // This is only a hint. Implementations are free to choose whether to use
+ // eager or lazy parsing regardless of the value of this option. However,
+ // setting this option true suggests that the protocol author believes that
+ // using lazy parsing on this field is worth the additional bookkeeping
+ // overhead typically needed to implement it.
+ //
+ // This option does not affect the public interface of any generated code;
+ // all method signatures remain the same. Furthermore, thread-safety of the
+ // interface is not affected by this option; const methods remain safe to
+ // call from multiple threads concurrently, while non-const methods continue
+ // to require exclusive access.
+ //
+ //
+ // Note that implementations may choose not to check required fields within
+ // a lazy sub-message. That is, calling IsInitialized() on the outher message
+ // may return true even if the inner message has missing required fields.
+ // This is necessary because otherwise the inner message would have to be
+ // parsed in order to perform the check, defeating the purpose of lazy
+ // parsing. An implementation which chooses not to check required fields
+ // must be consistent about it. That is, for any particular sub-message, the
+ // implementation must either *always* check its required fields, or *never*
+ // check its required fields, regardless of whether or not the message has
+ // been parsed.
+ optional bool lazy = 5 [default=false];
+
// Is this field deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for accessors, or it will be completely ignored; in the very least, this
@@ -369,6 +409,9 @@ message FieldOptions {
// TODO: Fully-implement this, then remove the "experimental_" prefix.
optional string experimental_map_key = 9;
+ // For Google-internal migration only. Do not use.
+ optional bool weak = 10 [default=false];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -378,6 +421,10 @@ message FieldOptions {
message EnumOptions {
+ // Set this option to false to disallow mapping different tag names to a same
+ // value.
+ optional bool allow_alias = 2 [default=true];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -421,6 +468,7 @@ message MethodOptions {
extensions 1000 to max;
}
+
// A message representing a option the parser does not recognize. This only
// appears in options protos created by the compiler::Parser class.
// DescriptorPool resolves these when building Descriptor objects. Therefore,
@@ -532,7 +580,41 @@ message SourceCodeInfo {
// 1 to each before displaying to a user.
repeated int32 span = 2 [packed=true];
- // TODO(kenton): Record comments appearing before and after the
- // declaration.
+ // If this SourceCodeInfo represents a complete declaration, these are any
+ // comments appearing before and after the declaration which appear to be
+ // attached to the declaration.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // Only the comment content is provided; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk
+ // will be stripped from the beginning of each line other than the first.
+ // Newlines are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to qux.
+ // //
+ // // Another line attached to qux.
+ // optional double qux = 4;
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ optional string leading_comments = 3;
+ optional string trailing_comments = 4;
}
}
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
index 23e48a67..35e459d5 100644
--- a/src/google/protobuf/descriptor_database.cc
+++ b/src/google/protobuf/descriptor_database.cc
@@ -39,7 +39,7 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/map-util.h>
namespace google {
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index f32b1db9..2ccb1458 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -41,6 +41,7 @@
#include <string>
#include <utility>
#include <vector>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
namespace google {
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 55aebfd1..3503f13e 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -36,13 +36,15 @@
#include <vector>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/text_format.h>
-#include <google/protobuf/unittest.pb.h>
-#include <google/protobuf/unittest_custom_options.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -1518,9 +1520,8 @@ TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
class MiscTest : public testing::Test {
protected:
- // Function which makes a field of the given type just to find out what its
- // cpp_type is.
- FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
+ // Function which makes a field descriptor of the given type.
+ const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
FileDescriptorProto file_proto;
file_proto.set_name("foo.proto");
AddEmptyEnum(&file_proto, "DummyEnum");
@@ -1538,19 +1539,62 @@ class MiscTest : public testing::Test {
}
// Build the descriptors and get the pointers.
- DescriptorPool pool;
- const FileDescriptor* file = pool.BuildFile(file_proto);
+ pool_.reset(new DescriptorPool());
+ const FileDescriptor* file = pool_->BuildFile(file_proto);
if (file != NULL &&
file->message_type_count() == 1 &&
file->message_type(0)->field_count() == 1) {
- return file->message_type(0)->field(0)->cpp_type();
+ return file->message_type(0)->field(0);
} else {
- return static_cast<FieldDescriptor::CppType>(0);
+ return NULL;
}
}
+
+ const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->type_name() : "";
+ }
+
+ FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->cpp_type() :
+ static_cast<FieldDescriptor::CppType>(0);
+ }
+
+ const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->cpp_type_name() : "";
+ }
+
+ scoped_ptr<DescriptorPool> pool_;
};
+TEST_F(MiscTest, TypeNames) {
+ // Test that correct type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("double" , GetTypeNameForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_STREQ("float" , GetTypeNameForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_STREQ("int64" , GetTypeNameForFieldType(FD::TYPE_INT64 ));
+ EXPECT_STREQ("uint64" , GetTypeNameForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_STREQ("int32" , GetTypeNameForFieldType(FD::TYPE_INT32 ));
+ EXPECT_STREQ("fixed64" , GetTypeNameForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_STREQ("fixed32" , GetTypeNameForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_STREQ("bool" , GetTypeNameForFieldType(FD::TYPE_BOOL ));
+ EXPECT_STREQ("string" , GetTypeNameForFieldType(FD::TYPE_STRING ));
+ EXPECT_STREQ("group" , GetTypeNameForFieldType(FD::TYPE_GROUP ));
+ EXPECT_STREQ("message" , GetTypeNameForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_STREQ("bytes" , GetTypeNameForFieldType(FD::TYPE_BYTES ));
+ EXPECT_STREQ("uint32" , GetTypeNameForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_STREQ("enum" , GetTypeNameForFieldType(FD::TYPE_ENUM ));
+ EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_STREQ("sint32" , GetTypeNameForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_STREQ("sint64" , GetTypeNameForFieldType(FD::TYPE_SINT64 ));
+}
+
TEST_F(MiscTest, CppTypes) {
// Test that CPP types are assigned correctly.
@@ -1576,6 +1620,31 @@ TEST_F(MiscTest, CppTypes) {
EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SINT64 ));
}
+TEST_F(MiscTest, CppTypeNames) {
+ // Test that correct CPP type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("double" , GetCppTypeNameForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_STREQ("float" , GetCppTypeNameForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_INT64 ));
+ EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_INT32 ));
+ EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_STREQ("bool" , GetCppTypeNameForFieldType(FD::TYPE_BOOL ));
+ EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_STRING ));
+ EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP ));
+ EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_BYTES ));
+ EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_STREQ("enum" , GetCppTypeNameForFieldType(FD::TYPE_ENUM ));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SINT64 ));
+}
+
TEST_F(MiscTest, DefaultValues) {
// Test that setting default values works.
FileDescriptorProto file_proto;
@@ -1739,13 +1808,31 @@ TEST_F(MiscTest, FieldOptions) {
}
// ===================================================================
+enum DescriptorPoolMode {
+ NO_DATABASE,
+ FALLBACK_DATABASE
+};
-class AllowUnknownDependenciesTest : public testing::Test {
+class AllowUnknownDependenciesTest
+ : public testing::TestWithParam<DescriptorPoolMode> {
protected:
+ DescriptorPoolMode mode() {
+ return GetParam();
+ }
+
virtual void SetUp() {
FileDescriptorProto foo_proto, bar_proto;
- pool_.AllowUnknownDependencies();
+ switch (mode()) {
+ case NO_DATABASE:
+ pool_.reset(new DescriptorPool);
+ break;
+ case FALLBACK_DATABASE:
+ pool_.reset(new DescriptorPool(&db_));
+ break;
+ }
+
+ pool_->AllowUnknownDependencies();
ASSERT_TRUE(TextFormat::ParseFromString(
"name: 'foo.proto'"
@@ -1776,13 +1863,13 @@ class AllowUnknownDependenciesTest : public testing::Test {
&bar_proto));
// Collect pointers to stuff.
- bar_file_ = pool_.BuildFile(bar_proto);
+ bar_file_ = BuildFile(bar_proto);
ASSERT_TRUE(bar_file_ != NULL);
ASSERT_EQ(1, bar_file_->message_type_count());
bar_type_ = bar_file_->message_type(0);
- foo_file_ = pool_.BuildFile(foo_proto);
+ foo_file_ = BuildFile(foo_proto);
ASSERT_TRUE(foo_file_ != NULL);
ASSERT_EQ(1, foo_file_->message_type_count());
@@ -1794,6 +1881,20 @@ class AllowUnknownDependenciesTest : public testing::Test {
qux_field_ = foo_type_->field(2);
}
+ const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
+ switch (mode()) {
+ case NO_DATABASE:
+ return pool_->BuildFile(proto);
+ break;
+ case FALLBACK_DATABASE: {
+ EXPECT_TRUE(db_.Add(proto));
+ return pool_->FindFileByName(proto.name());
+ }
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+ }
+
const FileDescriptor* bar_file_;
const Descriptor* bar_type_;
const FileDescriptor* foo_file_;
@@ -1802,10 +1903,11 @@ class AllowUnknownDependenciesTest : public testing::Test {
const FieldDescriptor* baz_field_;
const FieldDescriptor* qux_field_;
- DescriptorPool pool_;
+ SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
+ scoped_ptr<DescriptorPool> pool_;
};
-TEST_F(AllowUnknownDependenciesTest, PlaceholderFile) {
+TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
ASSERT_EQ(2, foo_file_->dependency_count());
EXPECT_EQ(bar_file_, foo_file_->dependency(0));
@@ -1814,11 +1916,11 @@ TEST_F(AllowUnknownDependenciesTest, PlaceholderFile) {
EXPECT_EQ(0, baz_file->message_type_count());
// Placeholder files should not be findable.
- EXPECT_EQ(bar_file_, pool_.FindFileByName(bar_file_->name()));
- EXPECT_TRUE(pool_.FindFileByName(baz_file->name()) == NULL);
+ EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
+ EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == NULL);
}
-TEST_F(AllowUnknownDependenciesTest, PlaceholderTypes) {
+TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
EXPECT_EQ(bar_type_, bar_field_->message_type());
@@ -1836,12 +1938,12 @@ TEST_F(AllowUnknownDependenciesTest, PlaceholderTypes) {
EXPECT_EQ("corge.Qux.placeholder.proto", qux_type->file()->name());
// Placeholder types should not be findable.
- EXPECT_EQ(bar_type_, pool_.FindMessageTypeByName(bar_type_->full_name()));
- EXPECT_TRUE(pool_.FindMessageTypeByName(baz_type->full_name()) == NULL);
- EXPECT_TRUE(pool_.FindEnumTypeByName(qux_type->full_name()) == NULL);
+ EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
+ EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == NULL);
+ EXPECT_TRUE(pool_->FindEnumTypeByName(qux_type->full_name()) == NULL);
}
-TEST_F(AllowUnknownDependenciesTest, CopyTo) {
+TEST_P(AllowUnknownDependenciesTest, CopyTo) {
// FieldDescriptor::CopyTo() should write non-fully-qualified type names
// for placeholder types which were not originally fully-qualified.
FieldDescriptorProto proto;
@@ -1864,7 +1966,7 @@ TEST_F(AllowUnknownDependenciesTest, CopyTo) {
EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
}
-TEST_F(AllowUnknownDependenciesTest, CustomOptions) {
+TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
// Qux should still have the uninterpreted option attached.
ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size());
const UninterpretedOption& option =
@@ -1873,7 +1975,7 @@ TEST_F(AllowUnknownDependenciesTest, CustomOptions) {
EXPECT_EQ("grault", option.name(0).name_part());
}
-TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
+TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
// Test that we can extend an unknown type. This is slightly tricky because
// it means that the placeholder type must have an extension range.
@@ -1884,7 +1986,7 @@ TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
"extension { extendee: 'UnknownType' name:'some_extension' number:123"
" label:LABEL_OPTIONAL type:TYPE_INT32 }",
&extension_proto));
- const FileDescriptor* file = pool_.BuildFile(extension_proto);
+ const FileDescriptor* file = BuildFile(extension_proto);
ASSERT_TRUE(file != NULL);
@@ -1896,7 +1998,7 @@ TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
}
-TEST_F(AllowUnknownDependenciesTest, CustomOption) {
+TEST_P(AllowUnknownDependenciesTest, CustomOption) {
// Test that we can use a custom option without having parsed
// descriptor.proto.
@@ -1937,7 +2039,7 @@ TEST_F(AllowUnknownDependenciesTest, CustomOption) {
"}",
&option_proto));
- const FileDescriptor* file = pool_.BuildFile(option_proto);
+ const FileDescriptor* file = BuildFile(option_proto);
ASSERT_TRUE(file != NULL);
// Verify that no extension options were set, but they were left as
@@ -1949,6 +2051,81 @@ TEST_F(AllowUnknownDependenciesTest, CustomOption) {
EXPECT_EQ(2, file->options().uninterpreted_option_size());
}
+TEST_P(AllowUnknownDependenciesTest,
+ UndeclaredDependencyTriggersBuildOfDependency) {
+ // Crazy case: suppose foo.proto refers to a symbol without declaring the
+ // dependency that finds it. In the event that the pool is backed by a
+ // DescriptorDatabase, the pool will attempt to find the symbol in the
+ // database. If successful, it will build the undeclared dependency to verify
+ // that the file does indeed contain the symbol. If that file fails to build,
+ // then its descriptors must be rolled back. However, we still want foo.proto
+ // to build successfully, since we are allowing unknown dependencies.
+
+ FileDescriptorProto undeclared_dep_proto;
+ // We make this file fail to build by giving it two fields with tag 1.
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"invalid_file_as_undeclared_dep.proto\" "
+ "package: \"undeclared\" "
+ "message_type: { "
+ " name: \"Quux\" "
+ " field { "
+ " name:'qux' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
+ " }"
+ " field { "
+ " name:'quux' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
+ " }"
+ "}",
+ &undeclared_dep_proto));
+ // We can't use the BuildFile() helper because we don't actually want to build
+ // it into the descriptor pool in the fallback database case: it just needs to
+ // be sitting in the database so that it gets built during the building of
+ // test.proto below.
+ switch (mode()) {
+ case NO_DATABASE: {
+ ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == NULL);
+ break;
+ }
+ case FALLBACK_DATABASE: {
+ ASSERT_TRUE(db_.Add(undeclared_dep_proto));
+ }
+ }
+
+ FileDescriptorProto test_proto;
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"test.proto\" "
+ "message_type: { "
+ " name: \"Corge\" "
+ " field { "
+ " name:'quux' number:1 label: LABEL_OPTIONAL "
+ " type_name:'undeclared.Quux' type: TYPE_MESSAGE "
+ " }"
+ "}",
+ &test_proto));
+
+ const FileDescriptor* file = BuildFile(test_proto);
+ ASSERT_TRUE(file != NULL);
+ GOOGLE_LOG(INFO) << file->DebugString();
+
+ EXPECT_EQ(0, file->dependency_count());
+ ASSERT_EQ(1, file->message_type_count());
+ const Descriptor* corge_desc = file->message_type(0);
+ ASSERT_EQ("Corge", corge_desc->name());
+ ASSERT_EQ(1, corge_desc->field_count());
+
+ const FieldDescriptor* quux_field = corge_desc->field(0);
+ ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, quux_field->type());
+ ASSERT_EQ("Quux", quux_field->message_type()->name());
+ ASSERT_EQ("undeclared.Quux", quux_field->message_type()->full_name());
+ EXPECT_EQ("undeclared.Quux.placeholder.proto",
+ quux_field->message_type()->file()->name());
+ // The place holder type should not be findable.
+ ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == NULL);
+}
+
+INSTANTIATE_TEST_CASE_P(DatabaseSource,
+ AllowUnknownDependenciesTest,
+ testing::Values(NO_DATABASE, FALLBACK_DATABASE));
+
// ===================================================================
TEST(CustomOptions, OptionLocations) {
@@ -2451,6 +2628,15 @@ TEST_F(ValidationErrorTest, UnknownDependency) {
"bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
}
+TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
+ BuildFile("name: \"foo.proto\"");
+ BuildFileWithErrors(
+ "name: \"bar.proto\" "
+ "dependency: \"foo.proto\" "
+ "public_dependency: 1",
+ "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
+}
+
TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
// Used to crash: If we depend on a non-existent file and then refer to a
// package defined in a file that we didn't import, and that package is
@@ -2829,6 +3015,164 @@ TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
"necessary import.\n");
}
+TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
+ // Test for hidden dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import "bar.proto"
+ //
+ // // foo.proto
+ // import "forward.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Error, needs to import bar.proto explicitly.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\"");
+
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "dependency: \"forward.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}",
+ "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+ "which is not imported by \"foo.proto\". To use it here, please add the "
+ "necessary import.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import public "bar.proto"
+ //
+ // // foo.proto
+ // import "forward.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Correct. "bar.proto" is public imported into
+ // // forward.proto, so when "foo.proto" imports
+ // // "forward.proto", it imports "bar.proto" too.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "dependency: \"forward.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import public "bar.proto"
+ //
+ // // forward2.proto
+ // import public "forward.proto"
+ //
+ // // foo.proto
+ // import "forward2.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Correct, public imports are transitive.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"forward2.proto\""
+ "dependency: \"forward.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "dependency: \"forward2.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}");
+}
+
+TEST_F(ValidationErrorTest,
+ FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import "bar.proto"
+ //
+ // // forward2.proto
+ // import public "forward.proto"
+ //
+ // // foo.proto
+ // import "forward2.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Error, the "bar.proto" is not public imported
+ // // into "forward.proto", so will not be imported
+ // // into either "forward2.proto" or "foo.proto".
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\"");
+
+ BuildFile(
+ "name: \"forward2.proto\""
+ "dependency: \"forward.proto\" "
+ "public_dependency: 0");
+
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "dependency: \"forward2.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}",
+ "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+ "which is not imported by \"foo.proto\". To use it here, please add the "
+ "necessary import.\n");
+}
+
+
TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
// The following should produce an error that Bar.Baz is not defined:
// message Bar { message Baz {} }
@@ -3031,7 +3375,8 @@ TEST_F(ValidationErrorTest, InputTypeNotDefined) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
- "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n");
+ "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
+ );
}
TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
@@ -3044,7 +3389,8 @@ TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
- "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n");
+ "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
+ );
}
TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
@@ -3056,7 +3402,8 @@ TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
- "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n");
+ "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
+ );
}
TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
@@ -3069,9 +3416,11 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
- "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n");
+ "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
+ );
}
+
TEST_F(ValidationErrorTest, IllegalPackedField) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -3592,7 +3941,8 @@ TEST_F(ValidationErrorTest, RollbackAfterError) {
" }"
"}",
- "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n");
+ "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
+ );
// Make sure that if we build the same file again with the error fixed,
// it works. If the above rollback was incomplete, then some symbols will
@@ -3641,6 +3991,19 @@ TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]);
}
+TEST_F(ValidationErrorTest, DisallowEnumAlias) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "enum_type {"
+ " name: \"Bar\""
+ " value { name:\"ENUM_A\" number:0 }"
+ " value { name:\"ENUM_B\" number:0 }"
+ " options { allow_alias: false }"
+ "}",
+ "foo.proto: Bar: NUMBER: "
+ "\"ENUM_B\" uses the same enum value as \"ENUM_A\"\n");
+}
+
// ===================================================================
// DescriptorDatabase
@@ -3659,16 +4022,23 @@ class DatabaseBackedPoolTest : public testing::Test {
virtual void SetUp() {
AddToDatabase(&database_,
- "name: \"foo.proto\" "
- "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
- "enum_type { name:\"TestEnum\" value { name:\"DUMMY\" number:0 } } "
- "service { name:\"TestService\" } ");
+ "name: 'foo.proto' "
+ "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
+ "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
+ "service { name:'TestService' } ");
AddToDatabase(&database_,
- "name: \"bar.proto\" "
- "dependency: \"foo.proto\" "
- "message_type { name:\"Bar\" } "
- "extension { name:\"foo_ext\" extendee: \".Foo\" number:5 "
+ "name: 'bar.proto' "
+ "dependency: 'foo.proto' "
+ "message_type { name:'Bar' } "
+ "extension { name:'foo_ext' extendee: '.Foo' number:5 "
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+ // Baz has an undeclared dependency on Foo.
+ AddToDatabase(&database_,
+ "name: 'baz.proto' "
+ "message_type { "
+ " name:'Baz' "
+ " field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
+ "}");
}
// We can't inject a file containing errors into a DescriptorPool, so we
@@ -3907,6 +4277,33 @@ TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
error_collector.text_);
}
+TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
+ // Check that we find and report undeclared dependencies on types that exist
+ // in the descriptor database but that have not not been built yet.
+ MockErrorCollector error_collector;
+ DescriptorPool pool(&database_, &error_collector);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+ EXPECT_EQ(
+ "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
+ "which is not imported by \"baz.proto\". To use it here, please add "
+ "the necessary import.\n",
+ error_collector.text_);
+}
+
+TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
+ // Make sure that all traces of bad types are removed from the pool. This used
+ // to be b/4529436, due to the fact that a symbol resolution failure could
+ // potentially cause another file to be recursively built, which would trigger
+ // a checkpoint _past_ possibly invalid symbols.
+ // Baz is defined in the database, but the file is invalid because it is
+ // missing a necessary import.
+ DescriptorPool pool(&database_);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+ // Make sure that searching again for the file or the type fails.
+ EXPECT_TRUE(pool.FindFileByName("baz.proto") == NULL);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+}
+
TEST_F(DatabaseBackedPoolTest, UnittestProto) {
// Try to load all of unittest.proto from a DescriptorDatabase. This should
// thoroughly test all paths through DescriptorBuilder to insure that there
@@ -3963,6 +4360,16 @@ TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL);
EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL);
+
+ EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == NULL);
+ EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == NULL);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == NULL);
+ EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == NULL);
+ EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == NULL);
+ EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == NULL);
+ EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == NULL);
+
EXPECT_EQ(0, call_counter.call_count_);
}
@@ -4028,6 +4435,219 @@ TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
// ===================================================================
+class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ AbortingErrorCollector() {}
+
+ virtual void AddError(
+ const string &filename,
+ const string &element_name,
+ const Message *message,
+ ErrorLocation location,
+ const string &error_message) {
+ GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << ": "
+ << error_message;
+ }
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
+};
+
+// A source tree containing only one file.
+class SingletonSourceTree : public compiler::SourceTree {
+ public:
+ SingletonSourceTree(const string& filename, const string& contents)
+ : filename_(filename), contents_(contents) {}
+
+ virtual io::ZeroCopyInputStream* Open(const string& filename) {
+ return filename == filename_ ?
+ new io::ArrayInputStream(contents_.data(), contents_.size()) : NULL;
+ }
+
+ private:
+ const string filename_;
+ const string contents_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree);
+};
+
+const char *const kSourceLocationTestInput =
+ "syntax = \"proto2\";\n"
+ "message A {\n"
+ " optional int32 a = 1;\n"
+ " message B {\n"
+ " required double b = 1;\n"
+ " }\n"
+ "}\n"
+ "enum Indecision {\n"
+ " YES = 1;\n"
+ " NO = 2;\n"
+ " MAYBE = 3;\n"
+ "}\n"
+ "service S {\n"
+ " rpc Method(A) returns (A.B);\n"
+ // Put an empty line here to make the source location range match.
+ "\n"
+ "}\n";
+
+class SourceLocationTest : public testing::Test {
+ public:
+ SourceLocationTest()
+ : source_tree_("/test/test.proto", kSourceLocationTestInput),
+ db_(&source_tree_),
+ pool_(&db_, &collector_) {}
+
+ static string PrintSourceLocation(const SourceLocation &loc) {
+ return strings::Substitute("$0:$1-$2:$3",
+ 1 + loc.start_line,
+ 1 + loc.start_column,
+ 1 + loc.end_line,
+ 1 + loc.end_column);
+ }
+
+ private:
+ AbortingErrorCollector collector_;
+ SingletonSourceTree source_tree_;
+ compiler::SourceTreeDescriptorDatabase db_;
+
+ protected:
+ DescriptorPool pool_;
+};
+
+// TODO(adonovan): implement support for option fields and for
+// subparts of declarations.
+
+TEST_F(SourceLocationTest, GetSourceLocation) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ const Descriptor *a_desc = file_desc->FindMessageTypeByName("A");
+ EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("2:1-7:2", PrintSourceLocation(loc));
+
+ const Descriptor *a_b_desc = a_desc->FindNestedTypeByName("B");
+ EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("4:3-6:4", PrintSourceLocation(loc));
+
+ const EnumDescriptor *e_desc = file_desc->FindEnumTypeByName("Indecision");
+ EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("8:1-12:2", PrintSourceLocation(loc));
+
+ const EnumValueDescriptor *yes_desc = e_desc->FindValueByName("YES");
+ EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("9:3-9:13", PrintSourceLocation(loc));
+
+ const ServiceDescriptor *s_desc = file_desc->FindServiceByName("S");
+ EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("13:1-16:2", PrintSourceLocation(loc));
+
+ const MethodDescriptor *m_desc = s_desc->FindMethodByName("Method");
+ EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("14:3-14:31", PrintSourceLocation(loc));
+
+}
+
+// Missing SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ FileDescriptorProto proto;
+ file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
+ EXPECT_FALSE(proto.has_source_code_info());
+
+ DescriptorPool bad1_pool(&pool_);
+ const FileDescriptor* bad1_file_desc =
+ GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto));
+ const Descriptor *bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
+ EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
+}
+
+// Corrupt SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ FileDescriptorProto proto;
+ file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
+ EXPECT_FALSE(proto.has_source_code_info());
+ SourceCodeInfo_Location *loc_msg =
+ proto.mutable_source_code_info()->add_location();
+ loc_msg->add_path(1);
+ loc_msg->add_path(2);
+ loc_msg->add_path(3);
+ loc_msg->add_span(4);
+ loc_msg->add_span(5);
+ loc_msg->add_span(6);
+
+ DescriptorPool bad2_pool(&pool_);
+ const FileDescriptor* bad2_file_desc =
+ GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto));
+ const Descriptor *bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
+ EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
+}
+
+// ===================================================================
+
+const char* const kCopySourceCodeInfoToTestInput =
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n";
+
+// Required since source code information is not preserved by
+// FileDescriptorTest.
+class CopySourceCodeInfoToTest : public testing::Test {
+ public:
+ CopySourceCodeInfoToTest()
+ : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
+ db_(&source_tree_),
+ pool_(&db_, &collector_) {}
+
+ private:
+ AbortingErrorCollector collector_;
+ SingletonSourceTree source_tree_;
+ compiler::SourceTreeDescriptorDatabase db_;
+
+ protected:
+ DescriptorPool pool_;
+};
+
+TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
+ const FileDescriptor* file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+ FileDescriptorProto file_desc_proto;
+ ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+ file_desc->CopyTo(&file_desc_proto);
+ EXPECT_FALSE(file_desc_proto.has_source_code_info());
+}
+
+TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
+ const FileDescriptor* file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+ FileDescriptorProto file_desc_proto;
+ ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+ file_desc->CopySourceCodeInfoTo(&file_desc_proto);
+ const SourceCodeInfo& info = file_desc_proto.source_code_info();
+ ASSERT_EQ(3, info.location_size());
+ // Get the Foo message location
+ const SourceCodeInfo_Location& foo_location = info.location(1);
+ ASSERT_EQ(2, foo_location.path_size());
+ EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
+ EXPECT_EQ(0, foo_location.path(1)); // Foo is the first message defined
+ ASSERT_EQ(3, foo_location.span_size()); // Foo spans one line
+ EXPECT_EQ(1, foo_location.span(0)); // Foo is declared on line 1
+ EXPECT_EQ(0, foo_location.span(1)); // Foo starts at column 0
+ EXPECT_EQ(14, foo_location.span(2)); // Foo ends on column 14
+}
+
+// ===================================================================
+
} // namespace descriptor_unittest
} // namespace protobuf
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index c711a2da..e4bebb25 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -123,7 +123,9 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
case FD::CPPTYPE_FLOAT : return sizeof(float );
case FD::CPPTYPE_BOOL : return sizeof(bool );
case FD::CPPTYPE_ENUM : return sizeof(int );
- case FD::CPPTYPE_MESSAGE: return sizeof(Message*);
+
+ case FD::CPPTYPE_MESSAGE:
+ return sizeof(Message*);
case FD::CPPTYPE_STRING:
switch (field->options().ctype()) {
@@ -178,7 +180,17 @@ class DynamicMessage : public Message {
// important (the prototype must be deleted *before* the offsets).
scoped_array<int> offsets;
scoped_ptr<const GeneratedMessageReflection> reflection;
- scoped_ptr<const DynamicMessage> prototype;
+ // Don't use a scoped_ptr to hold the prototype: the destructor for
+ // DynamicMessage needs to know whether it is the prototype, and does so by
+ // looking back at this field. This would assume details about the
+ // implementation of scoped_ptr.
+ const DynamicMessage* prototype;
+
+ TypeInfo() : prototype(NULL) {}
+
+ ~TypeInfo() {
+ delete prototype;
+ }
};
DynamicMessage(const TypeInfo* type_info);
@@ -196,6 +208,14 @@ class DynamicMessage : public Message {
Metadata GetMetadata() const;
+ // We actually allocate more memory than sizeof(*this) when this
+ // class's memory is allocated via the global operator new. Thus, we need to
+ // manually call the global operator delete. Calling the destructor is taken
+ // care of for us.
+ static void operator delete(void* ptr) {
+ ::operator delete(ptr);
+ }
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
@@ -368,11 +388,12 @@ DynamicMessage::~DynamicMessage() {
break;
}
}
- } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
- !is_prototype()) {
- Message* message = *reinterpret_cast<Message**>(field_ptr);
- if (message != NULL) {
- delete message;
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (!is_prototype()) {
+ Message* message = *reinterpret_cast<Message**>(field_ptr);
+ if (message != NULL) {
+ delete message;
+ }
}
}
}
@@ -403,7 +424,7 @@ void DynamicMessage::CrossLinkPrototypes() {
}
Message* DynamicMessage::New() const {
- void* new_base = reinterpret_cast<uint8*>(operator new(type_info_->size));
+ void* new_base = operator new(type_info_->size);
memset(new_base, 0, type_info_->size);
return new(new_base) DynamicMessage(type_info_);
}
@@ -465,7 +486,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
if (*target != NULL) {
// Already exists.
- return (*target)->prototype.get();
+ return (*target)->prototype;
}
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
@@ -533,13 +554,13 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
void* base = operator new(size);
memset(base, 0, size);
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
- type_info->prototype.reset(prototype);
+ type_info->prototype = prototype;
// Construct the reflection object.
type_info->reflection.reset(
new GeneratedMessageReflection(
type_info->type,
- type_info->prototype.get(),
+ type_info->prototype,
type_info->offsets.get(),
type_info->has_bits_offset,
type_info->unknown_fields_offset,
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index 81dd2c63..b3d1e5d2 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -68,7 +68,7 @@ class DescriptorPool; // descriptor.h
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
public:
// Construct a DynamicMessageFactory that will search for extensions in
- // the DescriptorPool in which the exendee is defined.
+ // the DescriptorPool in which the extendee is defined.
DynamicMessageFactory();
// Construct a DynamicMessageFactory that will search for extensions in
@@ -102,7 +102,7 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
// object. The returned object remains property of the factory and will
// be destroyed when the factory is destroyed. Also, any objects created
// by calling the prototype's New() method share some data with the
- // prototype, so these must be destoyed before the DynamicMessageFactory
+ // prototype, so these must be destroyed before the DynamicMessageFactory
// is destroyed.
//
// The given descriptor must outlive the returned message, and hence must
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 41b89ab5..e4615970 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -73,11 +73,15 @@ class DynamicMessageTest : public testing::Test {
// unittest_import.proto.
FileDescriptorProto unittest_file;
FileDescriptorProto unittest_import_file;
+ FileDescriptorProto unittest_import_public_file;
unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
unittest_import::ImportMessage::descriptor()->file()->CopyTo(
&unittest_import_file);
+ unittest_import::PublicImportMessage::descriptor()->file()->CopyTo(
+ &unittest_import_public_file);
+ ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL);
ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 1a6f5dfc..2cbba8f5 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -71,7 +71,7 @@ void DeleteRegistry() {
void InitRegistry() {
registry_ = new ExtensionRegistry;
- internal::OnShutdown(&DeleteRegistry);
+ OnShutdown(&DeleteRegistry);
}
// This function is only called at startup, so there is no need for thread-
@@ -180,6 +180,17 @@ bool ExtensionSet::Has(int number) const {
return !iter->second.is_cleared;
}
+int ExtensionSet::NumExtensions() const {
+ int result = 0;
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ if (!iter->second.is_cleared) {
+ ++result;
+ }
+ }
+ return result;
+}
+
int ExtensionSet::ExtensionSize(int number) const {
map<int, Extension>::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) return false;
@@ -293,6 +304,14 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
#undef PRIMITIVE_ACCESSORS
+void* ExtensionSet::MutableRawRepeatedField(int number) {
+ // We assume that all the RepeatedField<>* pointers have the same
+ // size and alignment within the anonymous union in Extension.
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "no extension numbered " << number;
+ return iter->second.repeated_int32_value;
+}
+
// -------------------------------------------------------------------
// Enums
@@ -422,7 +441,11 @@ const MessageLite& ExtensionSet::GetMessage(
return default_value;
} else {
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
- return *iter->second.message_value;
+ if (iter->second.is_lazy) {
+ return iter->second.lazymessage_value->GetMessage(default_value);
+ } else {
+ return *iter->second.message_value;
+ }
}
}
@@ -439,12 +462,19 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
extension->type = type;
GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false;
+ extension->is_lazy = false;
extension->message_value = prototype.New();
+ extension->is_cleared = false;
+ return extension->message_value;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ if (extension->is_lazy) {
+ return extension->lazymessage_value->MutableMessage(prototype);
+ } else {
+ return extension->message_value;
+ }
}
- extension->is_cleared = false;
- return extension->message_value;
}
// Defined in extension_set_heavy.cc.
@@ -452,6 +482,56 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
// const Descriptor* message_type,
// MessageFactory* factory)
+void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
+ const FieldDescriptor* descriptor,
+ MessageLite* message) {
+ if (message == NULL) {
+ ClearExtension(number);
+ return;
+ }
+ Extension* extension;
+ if (MaybeNewExtension(number, descriptor, &extension)) {
+ extension->type = type;
+ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+ extension->is_repeated = false;
+ extension->is_lazy = false;
+ extension->message_value = message;
+ } else {
+ GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+ if (extension->is_lazy) {
+ extension->lazymessage_value->SetAllocatedMessage(message);
+ } else {
+ delete extension->message_value;
+ extension->message_value = message;
+ }
+ }
+ extension->is_cleared = false;
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(int number,
+ const MessageLite& prototype) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return NULL.
+ return NULL;
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+ MessageLite* ret = NULL;
+ if (iter->second.is_lazy) {
+ ret = iter->second.lazymessage_value->ReleaseMessage(prototype);
+ delete iter->second.lazymessage_value;
+ } else {
+ ret = iter->second.message_value;
+ }
+ extensions_.erase(number);
+ return ret;
+ }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+// MessageFactory* factory);
+
const MessageLite& ExtensionSet::GetRepeatedMessage(
int number, int index) const {
map<int, Extension>::const_iterator iter = extensions_.find(number);
@@ -484,7 +564,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
// RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result = extension->repeated_message_value
- ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
+ ->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == NULL) {
result = prototype.New();
extension->repeated_message_value->AddAllocated(result);
@@ -540,6 +620,16 @@ void ExtensionSet::RemoveLast(int number) {
}
}
+MessageLite* ExtensionSet::ReleaseLast(int number) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+
+ Extension* extension = &iter->second;
+ GOOGLE_DCHECK(extension->is_repeated);
+ GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+ return extension->repeated_message_value->ReleaseLast();
+}
+
void ExtensionSet::SwapElements(int number, int index1, int index2) {
map<int, Extension>::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
@@ -602,9 +692,11 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) {
if (is_new) {
// Extension did not already exist in set.
extension->type = other_extension.type;
+ extension->is_packed = other_extension.is_packed;
extension->is_repeated = true;
} else {
GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+ GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
GOOGLE_DCHECK(extension->is_repeated);
}
@@ -675,12 +767,55 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) {
*other_extension.string_value,
other_extension.descriptor);
break;
- case WireFormatLite::CPPTYPE_MESSAGE:
- MutableMessage(iter->first, other_extension.type,
- *other_extension.message_value,
- other_extension.descriptor)
- ->CheckTypeAndMergeFrom(*other_extension.message_value);
+ case WireFormatLite::CPPTYPE_MESSAGE: {
+ Extension* extension;
+ bool is_new = MaybeNewExtension(iter->first,
+ other_extension.descriptor,
+ &extension);
+ if (is_new) {
+ extension->type = other_extension.type;
+ extension->is_packed = other_extension.is_packed;
+ extension->is_repeated = false;
+ if (other_extension.is_lazy) {
+ extension->is_lazy = true;
+ extension->lazymessage_value =
+ other_extension.lazymessage_value->New();
+ extension->lazymessage_value->MergeFrom(
+ *other_extension.lazymessage_value);
+ } else {
+ extension->is_lazy = false;
+ extension->message_value =
+ other_extension.message_value->New();
+ extension->message_value->CheckTypeAndMergeFrom(
+ *other_extension.message_value);
+ }
+ } else {
+ GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+ GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed);
+ GOOGLE_DCHECK(!extension->is_repeated);
+ if (other_extension.is_lazy) {
+ if (extension->is_lazy) {
+ extension->lazymessage_value->MergeFrom(
+ *other_extension.lazymessage_value);
+ } else {
+ extension->message_value->CheckTypeAndMergeFrom(
+ other_extension.lazymessage_value->GetMessage(
+ *extension->message_value));
+ }
+ } else {
+ if (extension->is_lazy) {
+ extension->lazymessage_value->MutableMessage(
+ *other_extension.message_value)->CheckTypeAndMergeFrom(
+ *other_extension.message_value);
+ } else {
+ extension->message_value->CheckTypeAndMergeFrom(
+ *other_extension.message_value);
+ }
+ }
+ }
+ extension->is_cleared = false;
break;
+ }
}
}
}
@@ -706,7 +841,11 @@ bool ExtensionSet::IsInitialized() const {
}
} else {
if (!extension.is_cleared) {
- if (!extension.message_value->IsInitialized()) return false;
+ if (extension.is_lazy) {
+ if (!extension.lazymessage_value->IsInitialized()) return false;
+ } else {
+ if (!extension.message_value->IsInitialized()) return false;
+ }
}
}
}
@@ -715,27 +854,42 @@ bool ExtensionSet::IsInitialized() const {
return true;
}
-bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
- ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper) {
- int number = WireFormatLite::GetTagFieldNumber(tag);
+bool ExtensionSet::FindExtensionInfoFromTag(
+ uint32 tag, ExtensionFinder* extension_finder,
+ int* field_number, ExtensionInfo* extension) {
+ *field_number = WireFormatLite::GetTagFieldNumber(tag);
WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
- ExtensionInfo extension;
bool is_unknown;
- if (!extension_finder->Find(number, &extension)) {
+ if (!extension_finder->Find(*field_number, extension)) {
is_unknown = true;
- } else if (extension.is_packed) {
+ } else if (extension->is_packed) {
is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
} else {
WireFormatLite::WireType expected_wire_type =
- WireFormatLite::WireTypeForFieldType(real_type(extension.type));
+ WireFormatLite::WireTypeForFieldType(real_type(extension->type));
is_unknown = (wire_type != expected_wire_type);
}
+ return !is_unknown;
+}
+
+bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ FieldSkipper* field_skipper) {
+ int number;
+ ExtensionInfo extension;
+ if (!FindExtensionInfoFromTag(tag, extension_finder, &number, &extension)) {
+ return field_skipper->SkipField(input, tag);
+ } else {
+ return ParseFieldWithExtensionInfo(number, extension, input, field_skipper);
+ }
+}
- if (is_unknown) {
- field_skipper->SkipField(input, tag);
- } else if (extension.is_packed) {
+bool ExtensionSet::ParseFieldWithExtensionInfo(
+ int number, const ExtensionInfo& extension,
+ io::CodedInputStream* input,
+ FieldSkipper* field_skipper) {
+ if (extension.is_packed) {
uint32 size;
if (!input->ReadVarint32(&size)) return false;
io::CodedInputStream::Limit limit = input->PushLimit(size);
@@ -852,8 +1006,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
case WireFormatLite::TYPE_BYTES: {
string* value = extension.is_repeated ?
- AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) :
- MutableString(number, WireFormatLite::TYPE_STRING,
+ AddString(number, WireFormatLite::TYPE_BYTES, extension.descriptor) :
+ MutableString(number, WireFormatLite::TYPE_BYTES,
extension.descriptor);
if (!WireFormatLite::ReadBytes(input, value)) return false;
break;
@@ -896,120 +1050,11 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
// const MessageLite* containing_type,
// UnknownFieldSet* unknown_fields)
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
- ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper) {
- while (true) {
- uint32 tag = input->ReadTag();
- switch (tag) {
- case 0:
- return true;
- case WireFormatLite::kMessageSetItemStartTag:
- if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
- return false;
- }
- break;
- default:
- if (!ParseField(tag, input, extension_finder, field_skipper)) {
- return false;
- }
- break;
- }
- }
-}
-
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
- const MessageLite* containing_type) {
- FieldSkipper skipper;
- GeneratedExtensionFinder finder(containing_type);
- return ParseMessageSet(input, &finder, &skipper);
-}
-
// Defined in extension_set_heavy.cc.
// bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
// const MessageLite* containing_type,
// UnknownFieldSet* unknown_fields);
-bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
- ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper) {
- // TODO(kenton): It would be nice to share code between this and
- // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
- // differences would be hard to factor out.
-
- // This method parses a group which should contain two fields:
- // required int32 type_id = 2;
- // required data message = 3;
-
- // Once we see a type_id, we'll construct a fake tag for this extension
- // which is the tag it would have had under the proto2 extensions wire
- // format.
- uint32 fake_tag = 0;
-
- // If we see message data before the type_id, we'll append it to this so
- // we can parse it later. This will probably never happen in practice,
- // as no MessageSet encoder I know of writes the message before the type ID.
- // But, it's technically valid so we should allow it.
- // TODO(kenton): Use a Cord instead? Do I care?
- string message_data;
-
- while (true) {
- uint32 tag = input->ReadTag();
- if (tag == 0) return false;
-
- switch (tag) {
- case WireFormatLite::kMessageSetTypeIdTag: {
- uint32 type_id;
- if (!input->ReadVarint32(&type_id)) return false;
- fake_tag = WireFormatLite::MakeTag(type_id,
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
-
- if (!message_data.empty()) {
- // We saw some message data before the type_id. Have to parse it
- // now.
- io::CodedInputStream sub_input(
- reinterpret_cast<const uint8*>(message_data.data()),
- message_data.size());
- if (!ParseField(fake_tag, &sub_input,
- extension_finder, field_skipper)) {
- return false;
- }
- message_data.clear();
- }
-
- break;
- }
-
- case WireFormatLite::kMessageSetMessageTag: {
- if (fake_tag == 0) {
- // We haven't seen a type_id yet. Append this data to message_data.
- string temp;
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
- if (!input->ReadString(&temp, length)) return false;
- message_data.append(temp);
- } else {
- // Already saw type_id, so we can parse this directly.
- if (!ParseField(fake_tag, input,
- extension_finder, field_skipper)) {
- return false;
- }
- }
-
- break;
- }
-
- case WireFormatLite::kMessageSetItemEndTag: {
- return true;
- }
-
- default: {
- if (!field_skipper->SkipField(input, tag)) return false;
- }
- }
- }
-}
-
void ExtensionSet::SerializeWithCachedSizes(
int start_field_number, int end_field_number,
io::CodedOutputStream* output) const {
@@ -1021,14 +1066,6 @@ void ExtensionSet::SerializeWithCachedSizes(
}
}
-void ExtensionSet::SerializeMessageSetWithCachedSizes(
- io::CodedOutputStream* output) const {
- map<int, Extension>::const_iterator iter;
- for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
- iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
- }
-}
-
int ExtensionSet::ByteSize() const {
int total_size = 0;
@@ -1040,17 +1077,6 @@ int ExtensionSet::ByteSize() const {
return total_size;
}
-int ExtensionSet::MessageSetByteSize() const {
- int total_size = 0;
-
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- total_size += iter->second.MessageSetItemByteSize(iter->first);
- }
-
- return total_size;
-}
-
// Defined in extension_set_heavy.cc.
// int ExtensionSet::SpaceUsedExcludingSelf() const
@@ -1094,7 +1120,11 @@ void ExtensionSet::Extension::Clear() {
string_value->clear();
break;
case WireFormatLite::CPPTYPE_MESSAGE:
- message_value->Clear();
+ if (is_lazy) {
+ lazymessage_value->Clear();
+ } else {
+ message_value->Clear();
+ }
break;
default:
// No need to do anything. Get*() will return the default value
@@ -1206,40 +1236,18 @@ void ExtensionSet::Extension::SerializeFieldWithCachedSizes(
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case WireFormatLite::TYPE_MESSAGE:
+ if (is_lazy) {
+ lazymessage_value->WriteMessage(number, output);
+ } else {
+ WireFormatLite::WriteMessage(number, *message_value, output);
+ }
+ break;
}
}
}
-void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
- int number,
- io::CodedOutputStream* output) const {
- if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
- // Not a valid MessageSet extension, but serialize it the normal way.
- SerializeFieldWithCachedSizes(number, output);
- return;
- }
-
- if (is_cleared) return;
-
- // Start group.
- output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
-
- // Write type ID.
- WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
- number,
- output);
- // Write message.
- WireFormatLite::WriteMessageMaybeToArray(
- WireFormatLite::kMessageSetMessageNumber,
- *message_value,
- output);
-
- // End group.
- output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
-}
-
int ExtensionSet::Extension::ByteSize(int number) const {
int result = 0;
@@ -1353,8 +1361,16 @@ int ExtensionSet::Extension::ByteSize(int number) const {
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case WireFormatLite::TYPE_MESSAGE: {
+ if (is_lazy) {
+ int size = lazymessage_value->ByteSize();
+ result += io::CodedOutputStream::VarintSize32(size) + size;
+ } else {
+ result += WireFormatLite::MessageSize(*message_value);
+ }
+ break;
+ }
// Stuff with fixed size.
#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \
@@ -1375,29 +1391,6 @@ int ExtensionSet::Extension::ByteSize(int number) const {
return result;
}
-int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
- if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
- // Not a valid MessageSet extension, but compute the byte size for it the
- // normal way.
- return ByteSize(number);
- }
-
- if (is_cleared) return 0;
-
- int our_size = WireFormatLite::kMessageSetItemTagsSize;
-
- // type_id
- our_size += io::CodedOutputStream::VarintSize32(number);
-
- // message
- int message_size = message_value->ByteSize();
-
- our_size += io::CodedOutputStream::VarintSize32(message_size);
- our_size += message_size;
-
- return our_size;
-}
-
int ExtensionSet::Extension::GetSize() const {
GOOGLE_DCHECK(is_repeated);
switch (cpp_type(type)) {
@@ -1448,7 +1441,11 @@ void ExtensionSet::Extension::Free() {
delete string_value;
break;
case WireFormatLite::CPPTYPE_MESSAGE:
- delete message_value;
+ if (is_lazy) {
+ delete lazymessage_value;
+ } else {
+ delete message_value;
+ }
break;
default:
break;
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index ac1ada02..03af7eaf 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -89,8 +89,8 @@ typedef bool EnumValidityFuncWithArg(const void* arg, int number);
// Information about a registered extension.
struct ExtensionInfo {
inline ExtensionInfo() {}
- inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed)
- : type(type), is_repeated(is_repeated), is_packed(is_packed),
+ inline ExtensionInfo(FieldType type_param, bool isrepeated, bool ispacked)
+ : type(type_param), is_repeated(isrepeated), is_packed(ispacked),
descriptor(NULL) {}
FieldType type;
@@ -214,6 +214,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
bool Has(int number) const;
int ExtensionSize(int number) const; // Size of a repeated extension.
+ int NumExtensions() const; // The number of extensions
FieldType ExtensionType(int number) const;
void ClearExtension(int number);
@@ -251,10 +252,21 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
const MessageLite& prototype, desc);
MessageLite* MutableMessage(const FieldDescriptor* decsriptor,
MessageFactory* factory);
+ // Adds the given message to the ExtensionSet, taking ownership of the
+ // message object. Existing message with the same number will be deleted.
+ // If "message" is NULL, this is equivalent to "ClearExtension(number)".
+ void SetAllocatedMessage(int number, FieldType type,
+ const FieldDescriptor* descriptor,
+ MessageLite* message);
+ MessageLite* ReleaseMessage(int number, const MessageLite& prototype);
+ MessageLite* ReleaseMessage(const FieldDescriptor* descriptor,
+ MessageFactory* factory);
#undef desc
// repeated fields -------------------------------------------------
+ void* MutableRawRepeatedField(int number);
+
int32 GetRepeatedInt32 (int number, int index) const;
int64 GetRepeatedInt64 (int number, int index) const;
uint32 GetRepeatedUInt32(int number, int index) const;
@@ -296,6 +308,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
#undef desc
void RemoveLast(int number);
+ MessageLite* ReleaseLast(int number);
void SwapElements(int number, int index1, int index2);
// -----------------------------------------------------------------
@@ -312,18 +325,18 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void Swap(ExtensionSet* other);
bool IsInitialized() const;
- // Parses a single extension from the input. The input should start out
- // positioned immediately after the tag. |containing_type| is the default
- // instance for the containing message; it is used only to look up the
- // extension by number. See RegisterExtension(), above. Unlike the other
- // methods of ExtensionSet, this only works for generated message types --
- // it looks up extensions registered using RegisterExtension().
+ // Parses a single extension from the input. The input should start out
+ // positioned immediately after the tag.
bool ParseField(uint32 tag, io::CodedInputStream* input,
ExtensionFinder* extension_finder,
FieldSkipper* field_skipper);
// Specific versions for lite or full messages (constructs the appropriate
- // FieldSkipper automatically).
+ // FieldSkipper automatically). |containing_type| is the default
+ // instance for the containing message; it is used only to look up the
+ // extension by number. See RegisterExtension(), above. Unlike the other
+ // methods of ExtensionSet, this only works for generated message types --
+ // it looks up extensions registered using RegisterExtension().
bool ParseField(uint32 tag, io::CodedInputStream* input,
const MessageLite* containing_type);
bool ParseField(uint32 tag, io::CodedInputStream* input,
@@ -382,18 +395,49 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
private:
+ // Interface of a lazily parsed singular message extension.
+ class LIBPROTOBUF_EXPORT LazyMessageExtension {
+ public:
+ LazyMessageExtension() {}
+ virtual ~LazyMessageExtension() {}
+
+ virtual LazyMessageExtension* New() const = 0;
+ virtual const MessageLite& GetMessage(
+ const MessageLite& prototype) const = 0;
+ virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0;
+ virtual void SetAllocatedMessage(MessageLite *message) = 0;
+ virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0;
+
+ virtual bool IsInitialized() const = 0;
+ virtual int ByteSize() const = 0;
+ virtual int SpaceUsed() const = 0;
+
+ virtual void MergeFrom(const LazyMessageExtension& other) = 0;
+ virtual void Clear() = 0;
+
+ virtual bool ReadMessage(const MessageLite& prototype,
+ io::CodedInputStream* input) = 0;
+ virtual void WriteMessage(int number,
+ io::CodedOutputStream* output) const = 0;
+ virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
+ };
struct Extension {
+ // The order of these fields packs Extension into 24 bytes when using 8
+ // byte alignment. Consider this when adding or removing fields here.
union {
- int32 int32_value;
- int64 int64_value;
- uint32 uint32_value;
- uint64 uint64_value;
- float float_value;
- double double_value;
- bool bool_value;
- int enum_value;
- string* string_value;
- MessageLite* message_value;
+ int32 int32_value;
+ int64 int64_value;
+ uint32 uint32_value;
+ uint64 uint64_value;
+ float float_value;
+ double double_value;
+ bool bool_value;
+ int enum_value;
+ string* string_value;
+ MessageLite* message_value;
+ LazyMessageExtension* lazymessage_value;
RepeatedField <int32 >* repeated_int32_value;
RepeatedField <int64 >* repeated_int64_value;
@@ -416,21 +460,28 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// removing it from the map, we just set is_cleared = true. This has no
// meaning for repeated types; for those, the size of the RepeatedField
// simply becomes zero when cleared.
- bool is_cleared;
+ bool is_cleared : 4;
+
+ // For singular message types, indicates whether lazy parsing is enabled
+ // for this extension. This field is only valid when type == TYPE_MESSAGE
+ // and !is_repeated because we only support lazy parsing for singular
+ // message types currently. If is_lazy = true, the extension is stored in
+ // lazymessage_value. Otherwise, the extension will be message_value.
+ bool is_lazy : 4;
// For repeated types, this indicates if the [packed=true] option is set.
bool is_packed;
- // The descriptor for this extension, if one exists and is known. May be
- // NULL. Must not be NULL if the descriptor for the extension does not
- // live in the same pool as the descriptor for the containing type.
- const FieldDescriptor* descriptor;
-
// For packed fields, the size of the packed data is recorded here when
// ByteSize() is called then used during serialization.
// TODO(kenton): Use atomic<int> when C++ supports it.
mutable int cached_size;
+ // The descriptor for this extension, if one exists and is known. May be
+ // NULL. Must not be NULL if the descriptor for the extension does not
+ // live in the same pool as the descriptor for the containing type.
+ const FieldDescriptor* descriptor;
+
// Some helper methods for operations on a single Extension.
void SerializeFieldWithCachedSizes(
int number,
@@ -453,6 +504,25 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
};
+ // Returns true and fills field_number and extension if extension is found.
+ bool FindExtensionInfoFromTag(uint32 tag, ExtensionFinder* extension_finder,
+ int* field_number, ExtensionInfo* extension);
+
+ // Parses a single extension from the input. The input should start out
+ // positioned immediately after the wire tag. This method is called in
+ // ParseField() after field number is extracted from the wire tag and
+ // ExtensionInfo is found by the field number.
+ bool ParseFieldWithExtensionInfo(int field_number,
+ const ExtensionInfo& extension,
+ io::CodedInputStream* input,
+ FieldSkipper* field_skipper);
+
+ // Like ParseField(), but this method may parse singular message extensions
+ // lazily depending on the value of FLAGS_eagerly_parse_message_sets.
+ bool ParseFieldMaybeLazily(uint32 tag, io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ FieldSkipper* field_skipper);
+
// Gets the extension with the given number, creating it if it does not
// already exist. Returns true if the extension did not already exist.
bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
@@ -720,6 +790,15 @@ class MessageTypeTraits {
return static_cast<Type*>(
set->MutableMessage(number, field_type, Type::default_instance(), NULL));
}
+ static inline void SetAllocated(int number, FieldType field_type,
+ MutableType message, ExtensionSet* set) {
+ set->SetAllocatedMessage(number, field_type, NULL, message);
+ }
+ static inline MutableType Release(int number, FieldType field_type,
+ ExtensionSet* set) {
+ return static_cast<Type*>(set->ReleaseMessage(
+ number, Type::default_instance()));
+ }
};
template <typename Type>
@@ -787,113 +866,137 @@ class ExtensionIdentifier {
// causes problems if the class has a nested message or enum type with that
// name and "_TypeTraits" is technically reserved for the C++ library since
// it starts with an underscore followed by a capital letter.
+//
+// For similar reason, we use "_field_type" and "_is_packed" as parameter names
+// below, so that "field_type" and "is_packed" can be used as field names.
#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \
/* Has, Size, Clear */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline bool HasExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _extensions_.Has(id.number()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void ClearExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
_extensions_.ClearExtension(id.number()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline int ExtensionSize( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _extensions_.ExtensionSize(id.number()); \
} \
\
/* Singular accessors */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::ConstType GetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _proto_TypeTraits::Get(id.number(), _extensions_, \
id.default_value()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::MutableType MutableExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
- return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Mutable(id.number(), _field_type, \
+ &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void SetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
typename _proto_TypeTraits::ConstType value) { \
- _proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \
+ _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); \
+ } \
+ \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline void SetAllocatedExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ typename _proto_TypeTraits::MutableType value) { \
+ _proto_TypeTraits::SetAllocated(id.number(), _field_type, \
+ value, &_extensions_); \
+ } \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::MutableType ReleaseExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Release(id.number(), _field_type, \
+ &_extensions_); \
} \
\
/* Repeated accessors */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::ConstType GetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
int index) const { \
return _proto_TypeTraits::Get(id.number(), _extensions_, index); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::MutableType MutableExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
int index) { \
return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void SetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
int index, typename _proto_TypeTraits::ConstType value) { \
_proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::MutableType AddExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
- return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void AddExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
typename _proto_TypeTraits::ConstType value) { \
- _proto_TypeTraits::Add(id.number(), field_type, is_packed, \
+ _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, \
value, &_extensions_); \
}
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 2721f15d..483d7055 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -35,17 +35,20 @@
// Contains methods defined in extension_set.h which cannot be part of the
// lite library because they use descriptors or reflection.
-#include <google/protobuf/extension_set.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
+
namespace protobuf {
namespace internal {
+
// Implementation of ExtensionFinder which finds extensions in a given
// DescriptorPool, using the given MessageFactory to construct sub-objects.
// This class is implemented in extension_set_heavy.cc.
@@ -103,6 +106,11 @@ inline FieldDescriptor::CppType cpp_type(FieldType type) {
static_cast<FieldDescriptor::Type>(type));
}
+inline WireFormatLite::FieldType field_type(FieldType type) {
+ GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+ return static_cast<WireFormatLite::FieldType>(type);
+}
+
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
: FieldDescriptor::LABEL_OPTIONAL, \
@@ -118,7 +126,12 @@ const MessageLite& ExtensionSet::GetMessage(int number,
return *factory->GetPrototype(message_type);
} else {
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
- return *iter->second.message_value;
+ if (iter->second.is_lazy) {
+ return iter->second.lazymessage_value->GetMessage(
+ *factory->GetPrototype(message_type));
+ } else {
+ return *iter->second.message_value;
+ }
}
}
@@ -132,13 +145,41 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
extension->is_packed = false;
const MessageLite* prototype =
factory->GetPrototype(descriptor->message_type());
- GOOGLE_CHECK(prototype != NULL);
+ extension->is_lazy = false;
extension->message_value = prototype->New();
+ extension->is_cleared = false;
+ return extension->message_value;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ if (extension->is_lazy) {
+ return extension->lazymessage_value->MutableMessage(
+ *factory->GetPrototype(descriptor->message_type()));
+ } else {
+ return extension->message_value;
+ }
+ }
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+ MessageFactory* factory) {
+ map<int, Extension>::iterator iter = extensions_.find(descriptor->number());
+ if (iter == extensions_.end()) {
+ // Not present. Return NULL.
+ return NULL;
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+ MessageLite* ret = NULL;
+ if (iter->second.is_lazy) {
+ ret = iter->second.lazymessage_value->ReleaseMessage(
+ *factory->GetPrototype(descriptor->message_type()));
+ delete iter->second.lazymessage_value;
+ } else {
+ ret = iter->second.message_value;
+ }
+ extensions_.erase(descriptor->number());
+ return ret;
}
- extension->is_cleared = false;
- return extension->message_value;
}
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
@@ -157,7 +198,7 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
// RepeatedPtrField<Message> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result = extension->repeated_message_value
- ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
+ ->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == NULL) {
const MessageLite* prototype;
if (extension->repeated_message_value->size() == 0) {
@@ -286,7 +327,11 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
StringSpaceUsedExcludingSelf(*string_value);
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
- total_size += down_cast<Message*>(message_value)->SpaceUsed();
+ if (is_lazy) {
+ total_size += lazymessage_value->SpaceUsed();
+ } else {
+ total_size += down_cast<Message*>(message_value)->SpaceUsed();
+ }
break;
default:
// No extra storage costs for primitive types.
@@ -419,8 +464,15 @@ uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case FieldDescriptor::TYPE_MESSAGE:
+ if (is_lazy) {
+ target = lazymessage_value->WriteMessageToArray(number, target);
+ } else {
+ target = WireFormatLite::WriteMessageToArray(
+ number, *message_value, target);
+ }
+ break;
}
}
return target;
@@ -444,14 +496,216 @@ uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
target = WireFormatLite::WriteUInt32ToArray(
WireFormatLite::kMessageSetTypeIdNumber, number, target);
// Write message.
- target = WireFormatLite::WriteMessageToArray(
- WireFormatLite::kMessageSetMessageNumber, *message_value, target);
+ if (is_lazy) {
+ target = lazymessage_value->WriteMessageToArray(
+ WireFormatLite::kMessageSetMessageNumber, target);
+ } else {
+ target = WireFormatLite::WriteMessageToArray(
+ WireFormatLite::kMessageSetMessageNumber, *message_value, target);
+ }
// End group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemEndTag, target);
return target;
}
+
+bool ExtensionSet::ParseFieldMaybeLazily(
+ uint32 tag, io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ FieldSkipper* field_skipper) {
+ return ParseField(tag, input, extension_finder, field_skipper);
+}
+
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ FieldSkipper* field_skipper) {
+ while (true) {
+ uint32 tag = input->ReadTag();
+ switch (tag) {
+ case 0:
+ return true;
+ case WireFormatLite::kMessageSetItemStartTag:
+ if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
+ return false;
+ }
+ break;
+ default:
+ if (!ParseField(tag, input, extension_finder, field_skipper)) {
+ return false;
+ }
+ break;
+ }
+ }
+}
+
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
+ const MessageLite* containing_type) {
+ FieldSkipper skipper;
+ GeneratedExtensionFinder finder(containing_type);
+ return ParseMessageSet(input, &finder, &skipper);
+}
+
+bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ FieldSkipper* field_skipper) {
+ // TODO(kenton): It would be nice to share code between this and
+ // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
+ // differences would be hard to factor out.
+
+ // This method parses a group which should contain two fields:
+ // required int32 type_id = 2;
+ // required data message = 3;
+
+ // Once we see a type_id, we'll construct a fake tag for this extension
+ // which is the tag it would have had under the proto2 extensions wire
+ // format.
+ uint32 fake_tag = 0;
+
+ // If we see message data before the type_id, we'll append it to this so
+ // we can parse it later.
+ string message_data;
+
+ while (true) {
+ uint32 tag = input->ReadTag();
+ if (tag == 0) return false;
+
+ switch (tag) {
+ case WireFormatLite::kMessageSetTypeIdTag: {
+ uint32 type_id;
+ if (!input->ReadVarint32(&type_id)) return false;
+ fake_tag = WireFormatLite::MakeTag(type_id,
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+
+ if (!message_data.empty()) {
+ // We saw some message data before the type_id. Have to parse it
+ // now.
+ io::CodedInputStream sub_input(
+ reinterpret_cast<const uint8*>(message_data.data()),
+ message_data.size());
+ if (!ParseFieldMaybeLazily(fake_tag, &sub_input,
+ extension_finder, field_skipper)) {
+ return false;
+ }
+ message_data.clear();
+ }
+
+ break;
+ }
+
+ case WireFormatLite::kMessageSetMessageTag: {
+ if (fake_tag == 0) {
+ // We haven't seen a type_id yet. Append this data to message_data.
+ string temp;
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (!input->ReadString(&temp, length)) return false;
+ io::StringOutputStream output_stream(&message_data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteVarint32(length);
+ coded_output.WriteString(temp);
+ } else {
+ // Already saw type_id, so we can parse this directly.
+ if (!ParseFieldMaybeLazily(fake_tag, input,
+ extension_finder, field_skipper)) {
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case WireFormatLite::kMessageSetItemEndTag: {
+ return true;
+ }
+
+ default: {
+ if (!field_skipper->SkipField(input, tag)) return false;
+ }
+ }
+ }
+}
+
+void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
+ int number,
+ io::CodedOutputStream* output) const {
+ if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+ // Not a valid MessageSet extension, but serialize it the normal way.
+ SerializeFieldWithCachedSizes(number, output);
+ return;
+ }
+
+ if (is_cleared) return;
+
+ // Start group.
+ output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
+
+ // Write type ID.
+ WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+ number,
+ output);
+ // Write message.
+ if (is_lazy) {
+ lazymessage_value->WriteMessage(
+ WireFormatLite::kMessageSetMessageNumber, output);
+ } else {
+ WireFormatLite::WriteMessageMaybeToArray(
+ WireFormatLite::kMessageSetMessageNumber,
+ *message_value,
+ output);
+ }
+
+ // End group.
+ output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+}
+
+int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
+ if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+ // Not a valid MessageSet extension, but compute the byte size for it the
+ // normal way.
+ return ByteSize(number);
+ }
+
+ if (is_cleared) return 0;
+
+ int our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+ // type_id
+ our_size += io::CodedOutputStream::VarintSize32(number);
+
+ // message
+ int message_size = 0;
+ if (is_lazy) {
+ message_size = lazymessage_value->ByteSize();
+ } else {
+ message_size = message_value->ByteSize();
+ }
+
+ our_size += io::CodedOutputStream::VarintSize32(message_size);
+ our_size += message_size;
+
+ return our_size;
+}
+
+void ExtensionSet::SerializeMessageSetWithCachedSizes(
+ io::CodedOutputStream* output) const {
+ map<int, Extension>::const_iterator iter;
+ for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
+ iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
+ }
+}
+
+int ExtensionSet::MessageSetByteSize() const {
+ int total_size = 0;
+
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ total_size += iter->second.MessageSetItemByteSize(iter->first);
+ }
+
+ return total_size;
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index 000f846c..1e7c5a5e 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -34,6 +34,7 @@
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
@@ -46,9 +47,10 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
+
namespace protobuf {
namespace internal {
namespace {
@@ -140,23 +142,98 @@ TEST(ExtensionSetTest, ClearOneField) {
TestUtil::ExpectAllExtensionsSet(message);
}
+TEST(ExtensionSetTest, SetAllocatedExtensin) {
+ unittest::TestAllExtensions message;
+ EXPECT_FALSE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+ // Add a extension using SetAllocatedExtension
+ unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
+ message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+ foreign_message);
+ EXPECT_TRUE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+ EXPECT_EQ(foreign_message,
+ message.MutableExtension(
+ unittest::optional_foreign_message_extension));
+ EXPECT_EQ(foreign_message,
+ &message.GetExtension(
+ unittest::optional_foreign_message_extension));
+
+ // SetAllocatedExtension should delete the previously existing extension.
+ // (We reply on unittest to check memory leaks for this case)
+ message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+ new unittest::ForeignMessage());
+
+ // SetAllocatedExtension with a NULL parameter is equivalent to ClearExtenion.
+ message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+ NULL);
+ EXPECT_FALSE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+}
+
+TEST(ExtensionSetTest, ReleaseExtension) {
+ unittest::TestMessageSet message;
+ EXPECT_FALSE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // Add a extension using SetAllocatedExtension
+ unittest::TestMessageSetExtension1* extension =
+ new unittest::TestMessageSetExtension1();
+ message.SetAllocatedExtension(
+ unittest::TestMessageSetExtension1::message_set_extension,
+ extension);
+ EXPECT_TRUE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // Release the extension using ReleaseExtension
+ unittest::TestMessageSetExtension1* released_extension =
+ message.ReleaseExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ EXPECT_EQ(extension, released_extension);
+ EXPECT_FALSE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // ReleaseExtension will return the underlying object even after
+ // ClearExtension is called.
+ message.SetAllocatedExtension(
+ unittest::TestMessageSetExtension1::message_set_extension,
+ extension);
+ message.ClearExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ released_extension = message.ReleaseExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ EXPECT_TRUE(released_extension != NULL);
+ delete released_extension;
+}
+
+
TEST(ExtensionSetTest, CopyFrom) {
unittest::TestAllExtensions message1, message2;
- string data;
TestUtil::SetAllExtensions(&message1);
message2.CopyFrom(message1);
TestUtil::ExpectAllExtensionsSet(message2);
+ message2.CopyFrom(message1); // exercise copy when fields already exist
+ TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensioSetTest, CopyFromPacked) {
+ unittest::TestPackedExtensions message1, message2;
+
+ TestUtil::SetPackedExtensions(&message1);
+ message2.CopyFrom(message1);
+ TestUtil::ExpectPackedExtensionsSet(message2);
+ message2.CopyFrom(message1); // exercise copy when fields already exist
+ TestUtil::ExpectPackedExtensionsSet(message2);
}
TEST(ExtensionSetTest, CopyFromUpcasted) {
unittest::TestAllExtensions message1, message2;
- string data;
const Message& upcasted_message = message1;
TestUtil::SetAllExtensions(&message1);
message2.CopyFrom(upcasted_message);
TestUtil::ExpectAllExtensionsSet(message2);
+ // exercise copy when fields already exist
+ message2.CopyFrom(upcasted_message);
+ TestUtil::ExpectAllExtensionsSet(message2);
}
TEST(ExtensionSetTest, SwapWithEmpty) {
@@ -418,7 +495,8 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
for (int i = 0; i < 16; ++i) { \
message.AddExtension(unittest::repeated_##type##_extension, value); \
} \
- int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \
+ int expected_size = sizeof(cpptype) * (16 - \
+ kMinRepeatedFieldAllocationSize) + empty_repeated_field_size; \
EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \
} while (0)
@@ -450,7 +528,8 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
for (int i = 0; i < 16; ++i) {
message.AddExtension(unittest::repeated_string_extension, value);
}
- min_expected_size += (sizeof(value) + value.size()) * 16;
+ min_expected_size += (sizeof(value) + value.size()) *
+ (16 - kMinRepeatedFieldAllocationSize);
EXPECT_LE(min_expected_size, message.SpaceUsed());
}
// Repeated messages
@@ -465,7 +544,8 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
message.AddExtension(unittest::repeated_foreign_message_extension)->
CopyFrom(prototype);
}
- min_expected_size += 16 * prototype.SpaceUsed();
+ min_expected_size +=
+ (16 - kMinRepeatedFieldAllocationSize) * prototype.SpaceUsed();
EXPECT_LE(min_expected_size, message.SpaceUsed());
}
}
diff --git a/src/google/protobuf/generated_enum_reflection.h b/src/google/protobuf/generated_enum_reflection.h
new file mode 100644
index 00000000..a09a540b
--- /dev/null
+++ b/src/google/protobuf/generated_enum_reflection.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jasonh@google.com (Jason Hsueh)
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+// It provides reflection support for generated enums, and is included in
+// generated .pb.h files and should have minimal dependencies. The methods are
+// implemented in generated_message_reflection.cc.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+ class EnumDescriptor;
+} // namespace protobuf
+
+namespace protobuf {
+
+// Returns the EnumDescriptor for enum type E, which must be a
+// proto-declared enum type. Code generated by the protocol compiler
+// will include specializations of this template for each enum type declared.
+template <typename E>
+const EnumDescriptor* GetEnumDescriptor();
+
+namespace internal {
+
+// Helper for EnumType_Parse functions: try to parse the string 'name' as an
+// enum name of the given type, returning true and filling in value on success,
+// or returning false and leaving value unchanged on failure.
+LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
+ const string& name,
+ int* value);
+
+template<typename EnumType>
+bool ParseNamedEnum(const EnumDescriptor* descriptor,
+ const string& name,
+ EnumType* value) {
+ int tmp;
+ if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
+ *value = static_cast<EnumType>(tmp);
+ return true;
+}
+
+// Just a wrapper around printing the name of a value. The main point of this
+// function is not to be inlined, so that you can do this without including
+// descriptor.h.
+LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index a0dd75c6..f4d0851d 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -33,9 +33,9 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <algorithm>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_util.h>
@@ -321,7 +321,7 @@ void GeneratedMessageReflection::Swap(
"descriptor.";
GOOGLE_CHECK_EQ(message2->GetReflection(), this)
<< "Second argument to Swap() (of type \""
- << message1->GetDescriptor()->full_name()
+ << message2->GetDescriptor()->full_name()
<< "\") is not compatible with this reflection object (which is for type \""
<< descriptor_->full_name()
<< "\"). Note that the exact same class is required; not just the same "
@@ -380,8 +380,11 @@ void GeneratedMessageReflection::Swap(
SWAP_VALUES(DOUBLE, double);
SWAP_VALUES(BOOL , bool );
SWAP_VALUES(ENUM , int );
- SWAP_VALUES(MESSAGE, Message*);
#undef SWAP_VALUES
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ std::swap(*MutableRaw<Message*>(message1, field),
+ *MutableRaw<Message*>(message2, field));
+ break;
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
@@ -588,6 +591,20 @@ void GeneratedMessageReflection::RemoveLast(
}
}
+Message* GeneratedMessageReflection::ReleaseLast(
+ Message* message,
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(ReleaseLast, REPEATED, MESSAGE);
+
+ if (field->is_extension()) {
+ return static_cast<Message*>(
+ MutableExtensionSet(message)->ReleaseLast(field->number()));
+ } else {
+ return MutableRaw<RepeatedPtrFieldBase>(message, field)
+ ->ReleaseLast<GenericTypeHandler<Message> >();
+ }
+}
+
void GeneratedMessageReflection::SwapElements(
Message* message,
const FieldDescriptor* field,
@@ -889,7 +906,9 @@ const EnumValueDescriptor* GeneratedMessageReflection::GetEnum(
}
const EnumValueDescriptor* result =
field->enum_type()->FindValueByNumber(value);
- GOOGLE_CHECK(result != NULL);
+ GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field "
+ << field->full_name() << " of type "
+ << field->enum_type()->full_name() << ".";
return result;
}
@@ -919,7 +938,9 @@ const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum(
}
const EnumValueDescriptor* result =
field->enum_type()->FindValueByNumber(value);
- GOOGLE_CHECK(result != NULL);
+ GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field "
+ << field->full_name() << " of type "
+ << field->enum_type()->full_name() << ".";
return result;
}
@@ -960,13 +981,15 @@ const Message& GeneratedMessageReflection::GetMessage(
MessageFactory* factory) const {
USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
+ if (factory == NULL) factory = message_factory_;
+
if (field->is_extension()) {
return static_cast<const Message&>(
GetExtensionSet(message).GetMessage(
- field->number(), field->message_type(),
- factory == NULL ? message_factory_ : factory));
+ field->number(), field->message_type(), factory));
} else {
- const Message* result = GetRaw<const Message*>(message, field);
+ const Message* result;
+ result = GetRaw<const Message*>(message, field);
if (result == NULL) {
result = DefaultRaw<const Message*>(field);
}
@@ -979,17 +1002,40 @@ Message* GeneratedMessageReflection::MutableMessage(
MessageFactory* factory) const {
USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+ if (factory == NULL) factory = message_factory_;
+
if (field->is_extension()) {
return static_cast<Message*>(
- MutableExtensionSet(message)->MutableMessage(field,
- factory == NULL ? message_factory_ : factory));
+ MutableExtensionSet(message)->MutableMessage(field, factory));
} else {
- Message** result = MutableField<Message*>(message, field);
- if (*result == NULL) {
+ Message* result;
+ Message** result_holder = MutableField<Message*>(message, field);
+ if (*result_holder == NULL) {
const Message* default_message = DefaultRaw<const Message*>(field);
- *result = default_message->New();
+ *result_holder = default_message->New();
}
- return *result;
+ result = *result_holder;
+ return result;
+ }
+}
+
+Message* GeneratedMessageReflection::ReleaseMessage(
+ Message* message,
+ const FieldDescriptor* field,
+ MessageFactory* factory) const {
+ USAGE_CHECK_ALL(ReleaseMessage, SINGULAR, MESSAGE);
+
+ if (factory == NULL) factory = message_factory_;
+
+ if (field->is_extension()) {
+ return static_cast<Message*>(
+ MutableExtensionSet(message)->ReleaseMessage(field, factory));
+ } else {
+ ClearBit(message, field);
+ Message** result = MutableRaw<Message*>(message, field);
+ Message* ret = *result;
+ *result = NULL;
+ return ret;
}
}
@@ -1034,7 +1080,7 @@ Message* GeneratedMessageReflection::AddMessage(
// We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
// know how to allocate one.
RepeatedPtrFieldBase* repeated =
- MutableRaw<RepeatedPtrFieldBase>(message, field);
+ MutableRaw<RepeatedPtrFieldBase>(message, field);
Message* result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
if (result == NULL) {
// We must allocate a new object.
@@ -1051,7 +1097,26 @@ Message* GeneratedMessageReflection::AddMessage(
}
}
-// -------------------------------------------------------------------
+void* GeneratedMessageReflection::MutableRawRepeatedField(
+ Message* message, const FieldDescriptor* field,
+ FieldDescriptor::CppType cpptype,
+ int ctype, const Descriptor* desc) const {
+ USAGE_CHECK_REPEATED("MutableRawRepeatedField");
+ if (field->cpp_type() != cpptype)
+ ReportReflectionUsageTypeError(descriptor_,
+ field, "MutableRawRepeatedField", cpptype);
+ if (ctype >= 0)
+ GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch";
+ if (desc != NULL)
+ GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+ if (field->is_extension())
+ return MutableExtensionSet(message)->MutableRawRepeatedField(
+ field->number());
+ else
+ return reinterpret_cast<uint8*>(message) + offsets_[field->index()];
+}
+
+// -----------------------------------------------------------------------------
const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName(
const string& name) const {
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index b545fa1a..e6670aea 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -40,17 +40,23 @@
#include <string>
#include <vector>
+#include <google/protobuf/stubs/common.h>
+// TODO(jasonh): Remove this once the compiler change to directly include this
+// is released to components.
+#include <google/protobuf/generated_enum_reflection.h>
#include <google/protobuf/message.h>
#include <google/protobuf/unknown_field_set.h>
namespace google {
+namespace upb {
+namespace proto2_bridge_opensource {
+class FieldAccessor;
+} // namespace protobuf_bridge_google3
+} // namespace upb
+
namespace protobuf {
class DescriptorPool;
- // Generated code needs these to have been forward-declared. Easier to do it
- // here than to print them inside every .pb.h file.
- class FileDescriptor;
- class EnumDescriptor;
}
namespace protobuf {
@@ -141,6 +147,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
int FieldSize(const Message& message, const FieldDescriptor* field) const;
void ClearField(Message* message, const FieldDescriptor* field) const;
void RemoveLast(Message* message, const FieldDescriptor* field) const;
+ Message* ReleaseLast(Message* message, const FieldDescriptor* field) const;
void Swap(Message* message1, Message* message2) const;
void SwapElements(Message* message, const FieldDescriptor* field,
int index1, int index2) const;
@@ -193,6 +200,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
const EnumValueDescriptor* value) const;
Message* MutableMessage(Message* message, const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
+ Message* ReleaseMessage(Message* message, const FieldDescriptor* field,
+ MessageFactory* factory = NULL) const;
int32 GetRepeatedInt32 (const Message& message,
const FieldDescriptor* field, int index) const;
@@ -270,9 +279,18 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
+ protected:
+ virtual void* MutableRawRepeatedField(
+ Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
+ int ctype, const Descriptor* desc) const;
+
private:
friend class GeneratedMessage;
+ // To parse directly into a proto2 generated class, FieldAccessor needs
+ // access to member offsets and hasbits.
+ friend class LIBPROTOBUF_EXPORT upb::proto2_bridge_opensource::FieldAccessor;
+
const Descriptor* descriptor_;
const Message* default_instance_;
const int* offsets_;
@@ -293,7 +311,6 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
- inline const Message* GetMessagePrototype(const FieldDescriptor* field) const;
inline const uint32* GetHasBits(const Message& message) const;
inline uint32* MutableHasBits(Message* message) const;
@@ -395,28 +412,6 @@ inline To dynamic_cast_if_available(From from) {
#endif
}
-// Helper for EnumType_Parse functions: try to parse the string 'name' as an
-// enum name of the given type, returning true and filling in value on success,
-// or returning false and leaving value unchanged on failure.
-LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
- const string& name,
- int* value);
-
-template<typename EnumType>
-bool ParseNamedEnum(const EnumDescriptor* descriptor,
- const string& name,
- EnumType* value) {
- int tmp;
- if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
- *value = static_cast<EnumType>(tmp);
- return true;
-}
-
-// Just a wrapper around printing the name of a value. The main point of this
-// function is not to be inlined, so that you can do this without including
-// descriptor.h.
-LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
-
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index a03bcdb7..f60e430d 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -225,11 +225,59 @@ TEST(GeneratedMessageReflectionTest, RemoveLastExtensions) {
unittest::TestAllExtensions::descriptor());
TestUtil::SetAllExtensions(&message);
+
reflection_tester.RemoveLastRepeatedsViaReflection(&message);
TestUtil::ExpectLastRepeatedExtensionsRemoved(message);
}
+TEST(GeneratedMessageReflectionTest, ReleaseLast) {
+ unittest::TestAllTypes message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ TestUtil::ReflectionTester reflection_tester(descriptor);
+
+ TestUtil::SetAllFields(&message);
+
+ reflection_tester.ReleaseLastRepeatedsViaReflection(&message, false);
+
+ TestUtil::ExpectLastRepeatedsReleased(message);
+
+ // Now test that we actually release the right message.
+ message.Clear();
+ TestUtil::SetAllFields(&message);
+ ASSERT_EQ(2, message.repeated_foreign_message_size());
+ const protobuf_unittest::ForeignMessage* expected =
+ message.mutable_repeated_foreign_message(1);
+ scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+ &message, descriptor->FindFieldByName("repeated_foreign_message")));
+ EXPECT_EQ(expected, released.get());
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseLastExtensions) {
+ unittest::TestAllExtensions message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ TestUtil::ReflectionTester reflection_tester(descriptor);
+
+ TestUtil::SetAllExtensions(&message);
+
+ reflection_tester.ReleaseLastRepeatedsViaReflection(&message, true);
+
+ TestUtil::ExpectLastRepeatedExtensionsReleased(message);
+
+ // Now test that we actually release the right message.
+ message.Clear();
+ TestUtil::SetAllExtensions(&message);
+ ASSERT_EQ(2, message.ExtensionSize(
+ unittest::repeated_foreign_message_extension));
+ const protobuf_unittest::ForeignMessage* expected = message.MutableExtension(
+ unittest::repeated_foreign_message_extension, 1);
+ scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+ &message, descriptor->file()->FindExtensionByName(
+ "repeated_foreign_message_extension")));
+ EXPECT_EQ(expected, released.get());
+
+}
+
TEST(GeneratedMessageReflectionTest, SwapRepeatedElements) {
unittest::TestAllTypes message;
TestUtil::ReflectionTester reflection_tester(
@@ -327,6 +375,58 @@ TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) {
FindKnownExtensionByName(extension1->full_name()) == NULL);
}
+TEST(GeneratedMessageReflectionTest, ReleaseMessageTest) {
+ unittest::TestAllTypes message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ message.Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+ // Test a different code path for setting after releasing.
+ TestUtil::SetAllFields(&message);
+ TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseExtensionMessageTest) {
+ unittest::TestAllExtensions message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllExtensions::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ message.Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+ // Test a different code path for setting after releasing.
+ TestUtil::SetAllExtensions(&message);
+ TestUtil::ExpectAllExtensionsSet(message);
+}
+
#ifdef GTEST_HAS_DEATH_TEST
TEST(GeneratedMessageReflectionTest, UsageErrors) {
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 76e547bb..ac321501 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -49,7 +49,6 @@ double NaN() {
const ::std::string kEmptyString;
-
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 77ae1064..b2fb8f0b 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -41,16 +41,8 @@
#include <string>
#include <google/protobuf/stubs/common.h>
-
-
namespace google {
namespace protobuf {
- namespace io {
- class CodedInputStream; // coded_stream.h
- }
-}
-
-namespace protobuf {
namespace internal {
// Annotation for the compiler to emit a deprecation message if a field marked
@@ -60,11 +52,7 @@ namespace internal {
// For internal use in the pb.cc files, deprecation warnings are suppressed
// there.
#undef DEPRECATED_PROTOBUF_FIELD
-#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
-# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED
-#else
-# define PROTOBUF_DEPRECATED
-#endif
+#define PROTOBUF_DEPRECATED
// Constants for special floating point values.
@@ -74,6 +62,13 @@ LIBPROTOBUF_EXPORT double NaN();
// Constant used for empty default strings.
LIBPROTOBUF_EXPORT extern const ::std::string kEmptyString;
+// Defined in generated_message_reflection.cc -- not actually part of the lite
+// library.
+//
+// TODO(jasonh): The various callers get this declaration from a variety of
+// places: probably in most cases repeated_field.h. Clean these up so they all
+// get the declaration from this file.
+LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 402a3ad3..36add8c3 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -43,7 +43,7 @@
#include <limits.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -69,6 +69,19 @@ inline bool NextNonEmpty(ZeroCopyInputStream* input,
// CodedInputStream ==================================================
+CodedInputStream::~CodedInputStream() {
+ if (input_ != NULL) {
+ BackUpInputToCurrentPosition();
+ }
+
+ if (total_bytes_warning_threshold_ == -2) {
+ GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
+ }
+}
+
+// Static.
+int CodedInputStream::default_recursion_limit_ = 100;
+
void CodedInputStream::BackUpInputToCurrentPosition() {
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
@@ -98,8 +111,7 @@ inline void CodedInputStream::RecomputeBufferLimits() {
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
// Current position relative to the beginning of the stream.
- int current_position = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
Limit old_limit = current_limit_;
@@ -133,10 +145,9 @@ void CodedInputStream::PopLimit(Limit limit) {
legitimate_message_end_ = false;
}
-int CodedInputStream::BytesUntilLimit() {
+int CodedInputStream::BytesUntilLimit() const {
if (current_limit_ == INT_MAX) return -1;
- int current_position = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
return current_limit_ - current_position;
}
@@ -145,10 +156,14 @@ void CodedInputStream::SetTotalBytesLimit(
int total_bytes_limit, int warning_threshold) {
// Make sure the limit isn't already past, since this could confuse other
// code.
- int current_position = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
total_bytes_limit_ = max(current_position, total_bytes_limit);
- total_bytes_warning_threshold_ = warning_threshold;
+ if (warning_threshold >= 0) {
+ total_bytes_warning_threshold_ = warning_threshold;
+ } else {
+ // warning_threshold is negative
+ total_bytes_warning_threshold_ = -1;
+ }
RecomputeBufferLimits();
}
@@ -368,16 +383,17 @@ uint32 CodedInputStream::ReadTagSlow() {
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
// again, since we have now refreshed the buffer.
- uint64 result;
+ uint64 result = 0;
if (!ReadVarint64(&result)) return 0;
return static_cast<uint32>(result);
}
uint32 CodedInputStream::ReadTagFallback() {
- if (BufferSize() >= kMaxVarintBytes ||
+ const int buf_size = BufferSize();
+ if (buf_size >= kMaxVarintBytes ||
// Optimization: If the varint ends at exactly the end of the buffer,
// we can detect that and still use the fast path.
- (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+ (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
uint32 tag;
const uint8* end = ReadVarint32FromArray(buffer_, &tag);
if (end == NULL) {
@@ -388,7 +404,9 @@ uint32 CodedInputStream::ReadTagFallback() {
} else {
// We are commonly at a limit when attempting to read tags. Try to quickly
// detect this case without making another function call.
- if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
+ if ((buf_size == 0) &&
+ ((buffer_size_after_limit_ > 0) ||
+ (total_bytes_read_ == current_limit_)) &&
// Make sure that the limit we hit is not total_bytes_limit_, since
// in that case we still need to call Refresh() so that it prints an
// error.
@@ -492,8 +510,8 @@ bool CodedInputStream::Refresh() {
"CodedInputStream::SetTotalBytesLimit() in "
"google/protobuf/io/coded_stream.h.";
- // Don't warn again for this stream.
- total_bytes_warning_threshold_ = -1;
+ // Don't warn again for this stream, and print total size at the end.
+ total_bytes_warning_threshold_ = -2;
}
const void* void_buffer;
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 97ac5079..66cbee00 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -170,6 +170,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// successfully and the stream's byte limit.
~CodedInputStream();
+ // Return true if this CodedInputStream reads from a flat array instead of
+ // a ZeroCopyInputStream.
+ inline bool IsFlat() const;
// Skips a number of bytes. Returns false if an underlying read error
// occurs.
@@ -311,7 +314,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Returns the number of bytes left until the nearest limit on the
// stack is hit, or -1 if no limits are in place.
- int BytesUntilLimit();
+ int BytesUntilLimit() const;
+
+ // Returns current position relative to the beginning of the input stream.
+ int CurrentPosition() const;
// Total Bytes Limit -----------------------------------------------
// To prevent malicious users from sending excessively large messages
@@ -327,8 +333,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// cause integer overflows is 512MB. The default limit is 64MB. Apps
// should set shorter limits if possible. If warning_threshold is not -1,
// a warning will be printed to stderr after warning_threshold bytes are
- // read. An error will always be printed to stderr if the limit is
- // reached.
+ // read. For backwards compatibility all negative values get squached to -1,
+ // as other negative values might have special internal meanings.
+ // An error will always be printed to stderr if the limit is reached.
//
// This is unrelated to PushLimit()/PopLimit().
//
@@ -355,9 +362,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// messages and groups. CodedInputStream keeps track of this because it
// is the only object that is passed down the stack during parsing.
- // Sets the maximum recursion depth. The default is 64.
+ // Sets the maximum recursion depth. The default is 100.
void SetRecursionLimit(int limit);
+
// Increments the current recursion depth. Returns true if the depth is
// under the limit, false if it has gone over.
bool IncrementRecursionDepth();
@@ -433,7 +441,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
//
// Note that this feature is ignored when parsing "lite" messages as they do
// not have descriptors.
- void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory);
+ void SetExtensionRegistry(const DescriptorPool* pool,
+ MessageFactory* factory);
// Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
// has been provided.
@@ -482,6 +491,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Maximum number of bytes to read, period. This is unrelated to
// current_limit_. Set using SetTotalBytesLimit().
int total_bytes_limit_;
+
+ // If positive/0: Limit for bytes read after which a warning due to size
+ // should be logged.
+ // If -1: Printing of warning disabled. Can be set by client.
+ // If -2: Internal: Limit has been reached, print full size when destructing.
int total_bytes_warning_threshold_;
// Current recursion depth, controlled by IncrementRecursionDepth() and
@@ -539,7 +553,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB
static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB
- static const int kDefaultRecursionLimit = 64;
+
+ static int default_recursion_limit_; // 100 by default.
};
// Class which encodes and writes binary data which is composed of varint-
@@ -891,7 +906,9 @@ inline bool CodedInputStream::ExpectAtEnd() {
// If we are at a limit we know no more bytes can be read. Otherwise, it's
// hard to say without calling Refresh(), and we'd rather not do that.
- if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) {
+ if (buffer_ == buffer_end_ &&
+ ((buffer_size_after_limit_ != 0) ||
+ (total_bytes_read_ == current_limit_))) {
last_tag_ = 0; // Pretend we called ReadTag()...
legitimate_message_end_ = true; // ... and it hit EOF.
return true;
@@ -900,6 +917,10 @@ inline bool CodedInputStream::ExpectAtEnd() {
}
}
+inline int CodedInputStream::CurrentPosition() const {
+ return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
+}
+
inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
if (buffer_size_ < size) {
return NULL;
@@ -1039,7 +1060,7 @@ inline void CodedInputStream::DecrementRecursionDepth() {
if (recursion_depth_ > 0) --recursion_depth_;
}
-inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool,
+inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
MessageFactory* factory) {
extension_pool_ = pool;
extension_factory_ = factory;
@@ -1071,7 +1092,7 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
- recursion_limit_(kDefaultRecursionLimit),
+ recursion_limit_(default_recursion_limit_),
extension_pool_(NULL),
extension_factory_(NULL) {
// Eagerly Refresh() so buffer space is immediately available.
@@ -1092,17 +1113,15 @@ inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
- recursion_limit_(kDefaultRecursionLimit),
+ recursion_limit_(default_recursion_limit_),
extension_pool_(NULL),
extension_factory_(NULL) {
// Note that setting current_limit_ == size is important to prevent some
// code paths from trying to access input_ and segfaulting.
}
-inline CodedInputStream::~CodedInputStream() {
- if (input_ != NULL) {
- BackUpInputToCurrentPosition();
- }
+inline bool CodedInputStream::IsFlat() const {
+ return input_ == NULL;
}
} // namespace io
diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h
index e9799d47..94495fb8 100644
--- a/src/google/protobuf/io/coded_stream_inl.h
+++ b/src/google/protobuf/io/coded_stream_inl.h
@@ -38,7 +38,7 @@
#include <google/protobuf/io/coded_stream.h>
#include <string>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index ff268ab9..2daab194 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -44,7 +44,6 @@
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/strutil.h>
// This declares an unsigned long long integer literal in a portable way.
@@ -125,6 +124,13 @@ namespace {
class CodedStreamTest : public testing::Test {
protected:
+ // Helper method used by tests for bytes warning. See implementation comment
+ // for further information.
+ static void SetupTotalBytesLimitWarningTest(
+ int total_bytes_limit, int warning_threshold,
+ vector<string>* out_errors, vector<string>* out_warnings);
+
+ // Buffer used during most of the tests. This assumes tests run sequentially.
static const int kBufferSize = 1024 * 64;
static uint8 buffer_[kBufferSize];
};
@@ -1022,6 +1028,59 @@ TEST_F(CodedStreamTest, TotalBytesLimitNotValidMessageEnd) {
EXPECT_FALSE(coded_input.ConsumedEntireMessage());
}
+// This method is used by the tests below.
+// It constructs a CodedInputStream with the given limits and tries to read 2KiB
+// of data from it. Then it returns the logged errors and warnings in the given
+// vectors.
+void CodedStreamTest::SetupTotalBytesLimitWarningTest(
+ int total_bytes_limit, int warning_threshold,
+ vector<string>* out_errors, vector<string>* out_warnings) {
+ ArrayInputStream raw_input(buffer_, sizeof(buffer_), 128);
+
+ ScopedMemoryLog scoped_log;
+ {
+ CodedInputStream input(&raw_input);
+ input.SetTotalBytesLimit(total_bytes_limit, warning_threshold);
+ string str;
+ EXPECT_TRUE(input.ReadString(&str, 2048));
+ }
+
+ *out_errors = scoped_log.GetMessages(ERROR);
+ *out_warnings = scoped_log.GetMessages(WARNING);
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimitWarning) {
+ vector<string> errors;
+ vector<string> warnings;
+ SetupTotalBytesLimitWarningTest(10240, 1024, &errors, &warnings);
+
+ EXPECT_EQ(0, errors.size());
+
+ ASSERT_EQ(2, warnings.size());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring,
+ "Reading dangerously large protocol message. If the message turns out to "
+ "be larger than 10240 bytes, parsing will be halted for security reasons.",
+ warnings[0]);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring,
+ "The total number of bytes read was 2048",
+ warnings[1]);
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimitWarningDisabled) {
+ vector<string> errors;
+ vector<string> warnings;
+
+ // Test with -1
+ SetupTotalBytesLimitWarningTest(10240, -1, &errors, &warnings);
+ EXPECT_EQ(0, errors.size());
+ EXPECT_EQ(0, warnings.size());
+
+ // Test again with -2, expecting the same result
+ SetupTotalBytesLimitWarningTest(10240, -2, &errors, &warnings);
+ EXPECT_EQ(0, errors.size());
+ EXPECT_EQ(0, warnings.size());
+}
+
TEST_F(CodedStreamTest, RecursionLimit) {
ArrayInputStream input(buffer_, sizeof(buffer_));
@@ -1060,6 +1119,7 @@ TEST_F(CodedStreamTest, RecursionLimit) {
EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 7
}
+
class ReallyBigInputStream : public ZeroCopyInputStream {
public:
ReallyBigInputStream() : backup_amount_(0), buffer_count_(0) {}
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index 0f1ff872..fe1f3319 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -199,16 +199,6 @@ GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
Init(sub_stream, options);
}
-GzipOutputStream::GzipOutputStream(
- ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) {
- Options options;
- options.format = format;
- if (buffer_size != -1) {
- options.buffer_size = buffer_size;
- }
- Init(sub_stream, options);
-}
-
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
const Options& options) {
sub_stream_ = sub_stream;
@@ -309,10 +299,11 @@ int64 GzipOutputStream::ByteCount() const {
}
bool GzipOutputStream::Flush() {
- do {
- zerror_ = Deflate(Z_FULL_FLUSH);
- } while (zerror_ == Z_OK);
- return zerror_ == Z_OK;
+ zerror_ = Deflate(Z_FULL_FLUSH);
+ // Return true if the flush succeeded or if it was a no-op.
+ return (zerror_ == Z_OK) ||
+ (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
+ zcontext_.avail_out != 0);
}
bool GzipOutputStream::Close() {
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
index 65dbc5b5..7ee24bc3 100644
--- a/src/google/protobuf/io/gzip_stream.h
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -45,6 +45,7 @@
#include <zlib.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream.h>
namespace google {
@@ -144,12 +145,6 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
ZeroCopyOutputStream* sub_stream,
const Options& options);
- // DEPRECATED: Use one of the above constructors instead.
- GzipOutputStream(
- ZeroCopyOutputStream* sub_stream,
- Format format,
- int buffer_size = -1) GOOGLE_ATTRIBUTE_DEPRECATED;
-
virtual ~GzipOutputStream();
// Return last error message or NULL if no error.
@@ -165,6 +160,13 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
// necessary.
// Compression may be less efficient stopping and starting around flushes.
// Returns true if no error.
+ //
+ // Please ensure that block size is > 6. Here is an excerpt from the zlib
+ // doc that explains why:
+ //
+ // In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
+ // is greater than six to avoid repeated flush markers due to
+ // avail_out == 0 on return.
bool Flush();
// Writes out all data and closes the gzip stream.
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index 9ab90dee..d2bf3f54 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -35,7 +35,6 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
@@ -51,8 +50,8 @@ Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
}
Printer::~Printer() {
- // Only BackUp() if we're sure we've successfully called Next() at least once.
- if (buffer_size_ > 0) {
+ // Only BackUp() if we have called Next() at least once and never failed.
+ if (buffer_size_ > 0 && !failed_) {
output_->BackUp(buffer_size_);
}
}
@@ -169,7 +168,7 @@ void Printer::WriteRaw(const char* data, int size) {
if (failed_) return;
if (size == 0) return;
- if (at_start_of_line_) {
+ if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
// Insert an indent.
at_start_of_line_ = false;
WriteRaw(indent_.data(), indent_.size());
diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
index 580a53da..399395c8 100644
--- a/src/google/protobuf/io/printer_unittest.cc
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -233,7 +233,31 @@ TEST(Printer, Death) {
}
#endif // GTEST_HAS_DEATH_TEST
-TEST(Printer, WriteFailure) {
+TEST(Printer, WriteFailurePartial) {
+ char buffer[17];
+
+ ArrayOutputStream output(buffer, sizeof(buffer));
+ Printer printer(&output, '$');
+
+ // Print 16 bytes to almost fill the buffer (should not fail).
+ printer.Print("0123456789abcdef");
+ EXPECT_FALSE(printer.failed());
+
+ // Try to print 2 chars. Only one fits.
+ printer.Print("<>");
+ EXPECT_TRUE(printer.failed());
+
+ // Anything else should fail too.
+ printer.Print(" ");
+ EXPECT_TRUE(printer.failed());
+ printer.Print("blah");
+ EXPECT_TRUE(printer.failed());
+
+ // Buffer should contain the first 17 bytes written.
+ EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
+}
+
+TEST(Printer, WriteFailureExact) {
char buffer[16];
ArrayOutputStream output(buffer, sizeof(buffer));
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index 513831d5..a022b71d 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -89,8 +89,11 @@
// exactly pretty.
#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -118,6 +121,8 @@ namespace {
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' ||
c == '\r' || c == '\v' || c == '\f');
+CHARACTER_CLASS(WhitespaceNoNewline, c == ' ' || c == '\t' ||
+ c == '\r' || c == '\v' || c == '\f');
CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0');
@@ -187,7 +192,8 @@ Tokenizer::Tokenizer(ZeroCopyInputStream* input,
read_error_(false),
line_(0),
column_(0),
- token_start_(-1),
+ record_target_(NULL),
+ record_start_(-1),
allow_f_after_float_(false),
comment_style_(CPP_COMMENT_STYLE) {
@@ -238,9 +244,9 @@ void Tokenizer::Refresh() {
}
// If we're in a token, append the rest of the buffer to it.
- if (token_start_ >= 0 && token_start_ < buffer_size_) {
- current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_);
- token_start_ = 0;
+ if (record_target_ != NULL && record_start_ < buffer_size_) {
+ record_target_->append(buffer_ + record_start_, buffer_size_ - record_start_);
+ record_start_ = 0;
}
const void* data = NULL;
@@ -261,23 +267,33 @@ void Tokenizer::Refresh() {
current_char_ = buffer_[0];
}
+inline void Tokenizer::RecordTo(string* target) {
+ record_target_ = target;
+ record_start_ = buffer_pos_;
+}
+
+inline void Tokenizer::StopRecording() {
+ // Note: The if() is necessary because some STL implementations crash when
+ // you call string::append(NULL, 0), presumably because they are trying to
+ // be helpful by detecting the NULL pointer, even though there's nothing
+ // wrong with reading zero bytes from NULL.
+ if (buffer_pos_ != record_start_) {
+ record_target_->append(buffer_ + record_start_, buffer_pos_ - record_start_);
+ }
+ record_target_ = NULL;
+ record_start_ = -1;
+}
+
inline void Tokenizer::StartToken() {
- token_start_ = buffer_pos_;
current_.type = TYPE_START; // Just for the sake of initializing it.
current_.text.clear();
current_.line = line_;
current_.column = column_;
+ RecordTo(&current_.text);
}
inline void Tokenizer::EndToken() {
- // Note: The if() is necessary because some STL implementations crash when
- // you call string::append(NULL, 0), presumably because they are trying to
- // be helpful by detecting the NULL pointer, even though there's nothing
- // wrong with reading zero bytes from NULL.
- if (buffer_pos_ != token_start_) {
- current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_);
- }
- token_start_ = -1;
+ StopRecording();
current_.end_column = column_;
}
@@ -353,6 +369,27 @@ void Tokenizer::ConsumeString(char delimiter) {
AddError("Expected hex digits for escape sequence.");
}
// Possibly followed by another hex digit, but again we don't care.
+ } else if (TryConsume('u')) {
+ if (!TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>()) {
+ AddError("Expected four hex digits for \\u escape sequence.");
+ }
+ } else if (TryConsume('U')) {
+ // We expect 8 hex digits; but only the range up to 0x10ffff is
+ // legal.
+ if (!TryConsume('0') ||
+ !TryConsume('0') ||
+ !(TryConsume('0') || TryConsume('1')) ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>()) {
+ AddError("Expected eight hex digits up to 10ffff for \\U escape "
+ "sequence");
+ }
} else {
AddError("Invalid escape sequence in string literal.");
}
@@ -426,26 +463,51 @@ Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
return is_float ? TYPE_FLOAT : TYPE_INTEGER;
}
-void Tokenizer::ConsumeLineComment() {
+void Tokenizer::ConsumeLineComment(string* content) {
+ if (content != NULL) RecordTo(content);
+
while (current_char_ != '\0' && current_char_ != '\n') {
NextChar();
}
TryConsume('\n');
+
+ if (content != NULL) StopRecording();
}
-void Tokenizer::ConsumeBlockComment() {
+void Tokenizer::ConsumeBlockComment(string* content) {
int start_line = line_;
int start_column = column_ - 2;
+ if (content != NULL) RecordTo(content);
+
while (true) {
while (current_char_ != '\0' &&
current_char_ != '*' &&
- current_char_ != '/') {
+ current_char_ != '/' &&
+ current_char_ != '\n') {
NextChar();
}
- if (TryConsume('*') && TryConsume('/')) {
+ if (TryConsume('\n')) {
+ if (content != NULL) StopRecording();
+
+ // Consume leading whitespace and asterisk;
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ if (TryConsume('*')) {
+ if (TryConsume('/')) {
+ // End of comment.
+ break;
+ }
+ }
+
+ if (content != NULL) RecordTo(content);
+ } else if (TryConsume('*') && TryConsume('/')) {
// End of comment.
+ if (content != NULL) {
+ StopRecording();
+ // Strip trailing "*/".
+ content->erase(content->size() - 2);
+ }
break;
} else if (TryConsume('/') && current_char_ == '*') {
// Note: We didn't consume the '*' because if there is a '/' after it
@@ -456,42 +518,59 @@ void Tokenizer::ConsumeBlockComment() {
AddError("End-of-file inside block comment.");
error_collector_->AddError(
start_line, start_column, " Comment started here.");
+ if (content != NULL) StopRecording();
break;
}
}
}
+Tokenizer::NextCommentStatus Tokenizer::TryConsumeCommentStart() {
+ if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
+ if (TryConsume('/')) {
+ return LINE_COMMENT;
+ } else if (TryConsume('*')) {
+ return BLOCK_COMMENT;
+ } else {
+ // Oops, it was just a slash. Return it.
+ current_.type = TYPE_SYMBOL;
+ current_.text = "/";
+ current_.line = line_;
+ current_.column = column_ - 1;
+ current_.end_column = column_;
+ return SLASH_NOT_COMMENT;
+ }
+ } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
+ return LINE_COMMENT;
+ } else {
+ return NO_COMMENT;
+ }
+}
+
// -------------------------------------------------------------------
bool Tokenizer::Next() {
previous_ = current_;
- // Did we skip any characters after the last token?
- bool skipped_stuff = false;
-
while (!read_error_) {
- if (TryConsumeOne<Whitespace>()) {
- ConsumeZeroOrMore<Whitespace>();
-
- } else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
- // Starting a comment?
- if (TryConsume('/')) {
- ConsumeLineComment();
- } else if (TryConsume('*')) {
- ConsumeBlockComment();
- } else {
- // Oops, it was just a slash. Return it.
- current_.type = TYPE_SYMBOL;
- current_.text = "/";
- current_.line = line_;
- current_.column = column_ - 1;
+ ConsumeZeroOrMore<Whitespace>();
+
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(NULL);
+ continue;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(NULL);
+ continue;
+ case SLASH_NOT_COMMENT:
return true;
- }
+ case NO_COMMENT:
+ break;
+ }
- } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
- ConsumeLineComment();
+ // Check for EOF before continuing.
+ if (read_error_) break;
- } else if (LookingAt<Unprintable>() || current_char_ == '\0') {
+ if (LookingAt<Unprintable>() || current_char_ == '\0') {
AddError("Invalid control characters encountered in text.");
NextChar();
// Skip more unprintable characters, too. But, remember that '\0' is
@@ -519,7 +598,9 @@ bool Tokenizer::Next() {
if (TryConsumeOne<Digit>()) {
// It's a floating-point number.
- if (previous_.type == TYPE_IDENTIFIER && !skipped_stuff) {
+ if (previous_.type == TYPE_IDENTIFIER &&
+ current_.line == previous_.line &&
+ current_.column == previous_.end_column) {
// We don't accept syntax like "blah.123".
error_collector_->AddError(line_, column_ - 2,
"Need space between identifier and decimal point.");
@@ -544,8 +625,6 @@ bool Tokenizer::Next() {
EndToken();
return true;
}
-
- skipped_stuff = true;
}
// EOF
@@ -557,6 +636,195 @@ bool Tokenizer::Next() {
return false;
}
+namespace {
+
+// Helper class for collecting comments and putting them in the right places.
+//
+// This basically just buffers the most recent comment until it can be decided
+// exactly where that comment should be placed. When Flush() is called, the
+// current comment goes into either prev_trailing_comments or detached_comments.
+// When the CommentCollector is destroyed, the last buffered comment goes into
+// next_leading_comments.
+class CommentCollector {
+ public:
+ CommentCollector(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments)
+ : prev_trailing_comments_(prev_trailing_comments),
+ detached_comments_(detached_comments),
+ next_leading_comments_(next_leading_comments),
+ has_comment_(false),
+ is_line_comment_(false),
+ can_attach_to_prev_(true) {
+ if (prev_trailing_comments != NULL) prev_trailing_comments->clear();
+ if (detached_comments != NULL) detached_comments->clear();
+ if (next_leading_comments != NULL) next_leading_comments->clear();
+ }
+
+ ~CommentCollector() {
+ // Whatever is in the buffer is a leading comment.
+ if (next_leading_comments_ != NULL && has_comment_) {
+ comment_buffer_.swap(*next_leading_comments_);
+ }
+ }
+
+ // About to read a line comment. Get the comment buffer pointer in order to
+ // read into it.
+ string* GetBufferForLineComment() {
+ // We want to combine with previous line comments, but not block comments.
+ if (has_comment_ && !is_line_comment_) {
+ Flush();
+ }
+ has_comment_ = true;
+ is_line_comment_ = true;
+ return &comment_buffer_;
+ }
+
+ // About to read a block comment. Get the comment buffer pointer in order to
+ // read into it.
+ string* GetBufferForBlockComment() {
+ if (has_comment_) {
+ Flush();
+ }
+ has_comment_ = true;
+ is_line_comment_ = false;
+ return &comment_buffer_;
+ }
+
+ void ClearBuffer() {
+ comment_buffer_.clear();
+ has_comment_ = false;
+ }
+
+ // Called once we know that the comment buffer is complete and is *not*
+ // connected to the next token.
+ void Flush() {
+ if (has_comment_) {
+ if (can_attach_to_prev_) {
+ if (prev_trailing_comments_ != NULL) {
+ prev_trailing_comments_->append(comment_buffer_);
+ }
+ can_attach_to_prev_ = false;
+ } else {
+ if (detached_comments_ != NULL) {
+ detached_comments_->push_back(comment_buffer_);
+ }
+ }
+ ClearBuffer();
+ }
+ }
+
+ void DetachFromPrev() {
+ can_attach_to_prev_ = false;
+ }
+
+ private:
+ string* prev_trailing_comments_;
+ vector<string>* detached_comments_;
+ string* next_leading_comments_;
+
+ string comment_buffer_;
+
+ // True if any comments were read into comment_buffer_. This can be true even
+ // if comment_buffer_ is empty, namely if the comment was "/**/".
+ bool has_comment_;
+
+ // Is the comment in the comment buffer a line comment?
+ bool is_line_comment_;
+
+ // Is it still possible that we could be reading a comment attached to the
+ // previous token?
+ bool can_attach_to_prev_;
+};
+
+} // namespace
+
+bool Tokenizer::NextWithComments(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments) {
+ CommentCollector collector(prev_trailing_comments, detached_comments,
+ next_leading_comments);
+
+ if (current_.type == TYPE_START) {
+ collector.DetachFromPrev();
+ } else {
+ // A comment appearing on the same line must be attached to the previous
+ // declaration.
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(collector.GetBufferForLineComment());
+
+ // Don't allow comments on subsequent lines to be attached to a trailing
+ // comment.
+ collector.Flush();
+ break;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ if (!TryConsume('\n')) {
+ // Oops, the next token is on the same line. If we recorded a comment
+ // we really have no idea which token it should be attached to.
+ collector.ClearBuffer();
+ return Next();
+ }
+
+ // Don't allow comments on subsequent lines to be attached to a trailing
+ // comment.
+ collector.Flush();
+ break;
+ case SLASH_NOT_COMMENT:
+ return true;
+ case NO_COMMENT:
+ if (!TryConsume('\n')) {
+ // The next token is on the same line. There are no comments.
+ return Next();
+ }
+ break;
+ }
+ }
+
+ // OK, we are now on the line *after* the previous token.
+ while (true) {
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(collector.GetBufferForLineComment());
+ break;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+ // Consume the rest of the line so that we don't interpret it as a
+ // blank line the next time around the loop.
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ TryConsume('\n');
+ break;
+ case SLASH_NOT_COMMENT:
+ return true;
+ case NO_COMMENT:
+ if (TryConsume('\n')) {
+ // Completely blank line.
+ collector.Flush();
+ collector.DetachFromPrev();
+ } else {
+ bool result = Next();
+ if (!result ||
+ current_.text == "}" ||
+ current_.text == "]" ||
+ current_.text == ")") {
+ // It looks like we're at the end of a scope. In this case it
+ // makes no sense to attach a comment to the following token.
+ collector.Flush();
+ }
+ return result;
+ }
+ break;
+ }
+ }
+}
+
// -------------------------------------------------------------------
// Token-parsing helpers. Remember that these don't need to report
// errors since any errors should already have been reported while
@@ -626,17 +894,138 @@ double Tokenizer::ParseFloat(const string& text) {
return result;
}
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+static void AppendUTF8(uint32 code_point, string* output) {
+ uint32 tmp = 0;
+ int len = 0;
+ if (code_point <= 0x7f) {
+ tmp = code_point;
+ len = 1;
+ } else if (code_point <= 0x07ff) {
+ tmp = 0x0000c080 |
+ ((code_point & 0x07c0) << 2) |
+ (code_point & 0x003f);
+ len = 2;
+ } else if (code_point <= 0xffff) {
+ tmp = 0x00e08080 |
+ ((code_point & 0xf000) << 4) |
+ ((code_point & 0x0fc0) << 2) |
+ (code_point & 0x003f);
+ len = 3;
+ } else if (code_point <= 0x1fffff) {
+ tmp = 0xf0808080 |
+ ((code_point & 0x1c0000) << 6) |
+ ((code_point & 0x03f000) << 4) |
+ ((code_point & 0x000fc0) << 2) |
+ (code_point & 0x003f);
+ len = 4;
+ } else {
+ // UTF-16 is only defined for code points up to 0x10FFFF, and UTF-8 is
+ // normally only defined up to there as well.
+ StringAppendF(output, "\\U%08x", code_point);
+ return;
+ }
+ tmp = ghtonl(tmp);
+ output->append(reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+}
+
+// Try to read <len> hex digits from ptr, and stuff the numeric result into
+// *result. Returns true if that many digits were successfully consumed.
+static bool ReadHexDigits(const char* ptr, int len, uint32* result) {
+ *result = 0;
+ if (len == 0) return false;
+ for (const char* end = ptr + len; ptr < end; ++ptr) {
+ if (*ptr == '\0') return false;
+ *result = (*result << 4) + DigitValue(*ptr);
+ }
+ return true;
+}
+
+// Handling UTF-16 surrogate pairs. UTF-16 encodes code points in the range
+// 0x10000...0x10ffff as a pair of numbers, a head surrogate followed by a trail
+// surrogate. These numbers are in a reserved range of Unicode code points, so
+// if we encounter such a pair we know how to parse it and convert it into a
+// single code point.
+static const uint32 kMinHeadSurrogate = 0xd800;
+static const uint32 kMaxHeadSurrogate = 0xdc00;
+static const uint32 kMinTrailSurrogate = 0xdc00;
+static const uint32 kMaxTrailSurrogate = 0xe000;
+
+static inline bool IsHeadSurrogate(uint32 code_point) {
+ return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
+}
+
+static inline bool IsTrailSurrogate(uint32 code_point) {
+ return (code_point >= kMinTrailSurrogate) &&
+ (code_point < kMaxTrailSurrogate);
+}
+
+// Combine a head and trail surrogate into a single Unicode code point.
+static uint32 AssembleUTF16(uint32 head_surrogate, uint32 trail_surrogate) {
+ GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
+ GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
+ return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
+ (trail_surrogate - kMinTrailSurrogate));
+}
+
+// Convert the escape sequence parameter to a number of expected hex digits.
+static inline int UnicodeLength(char key) {
+ if (key == 'u') return 4;
+ if (key == 'U') return 8;
+ return 0;
+}
+
+// Given a pointer to the 'u' or 'U' starting a Unicode escape sequence, attempt
+// to parse that sequence. On success, returns a pointer to the first char
+// beyond that sequence, and fills in *code_point. On failure, returns ptr
+// itself.
+static const char* FetchUnicodePoint(const char* ptr, uint32* code_point) {
+ const char* p = ptr;
+ // Fetch the code point.
+ const int len = UnicodeLength(*p++);
+ if (!ReadHexDigits(p, len, code_point))
+ return ptr;
+ p += len;
+
+ // Check if the code point we read is a "head surrogate." If so, then we
+ // expect it to be immediately followed by another code point which is a valid
+ // "trail surrogate," and together they form a UTF-16 pair which decodes into
+ // a single Unicode point. Trail surrogates may only use \u, not \U.
+ if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
+ uint32 trail_surrogate;
+ if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
+ IsTrailSurrogate(trail_surrogate)) {
+ *code_point = AssembleUTF16(*code_point, trail_surrogate);
+ p += 6;
+ }
+ // If this failed, then we just emit the head surrogate as a code point.
+ // It's bogus, but so is the string.
+ }
+
+ return p;
+}
+
+// The text string must begin and end with single or double quote
+// characters.
void Tokenizer::ParseStringAppend(const string& text, string* output) {
- // Reminder: text[0] is always the quote character. (If text is
- // empty, it's invalid, so we'll just return.)
- if (text.empty()) {
+ // Reminder: text[0] is always a quote character. (If text is
+ // empty, it's invalid, so we'll just return).
+ const size_t text_size = text.size();
+ if (text_size == 0) {
GOOGLE_LOG(DFATAL)
<< " Tokenizer::ParseStringAppend() passed text that could not"
" have been tokenized as a string: " << CEscape(text);
return;
}
- output->reserve(output->size() + text.size());
+ // Reserve room for new string. The branch is necessary because if
+ // there is already space available the reserve() call might
+ // downsize the output.
+ const size_t new_len = text_size + output->size();
+ if (new_len > output->capacity()) {
+ output->reserve(new_len);
+ }
// Loop through the string copying characters to "output" and
// interpreting escape sequences. Note that any invalid escape
@@ -674,19 +1063,27 @@ void Tokenizer::ParseStringAppend(const string& text, string* output) {
}
output->push_back(static_cast<char>(code));
+ } else if (*ptr == 'u' || *ptr == 'U') {
+ uint32 unicode;
+ const char* end = FetchUnicodePoint(ptr, &unicode);
+ if (end == ptr) {
+ // Failure: Just dump out what we saw, don't try to parse it.
+ output->push_back(*ptr);
+ } else {
+ AppendUTF8(unicode, output);
+ ptr = end - 1; // Because we're about to ++ptr.
+ }
} else {
// Some other escape code.
output->push_back(TranslateEscape(*ptr));
}
- } else if (*ptr == text[0]) {
- // Ignore quote matching the starting quote.
+ } else if (*ptr == text[0] && ptr[1] == '\0') {
+ // Ignore final quote matching the starting quote.
} else {
output->push_back(*ptr);
}
}
-
- return;
}
} // namespace io
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index 8f759abb..d85b82f9 100644
--- a/src/google/protobuf/io/tokenizer.h
+++ b/src/google/protobuf/io/tokenizer.h
@@ -38,6 +38,7 @@
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
#include <string>
+#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
@@ -137,6 +138,53 @@ class LIBPROTOBUF_EXPORT Tokenizer {
// reached.
bool Next();
+ // Like Next(), but also collects comments which appear between the previous
+ // and next tokens.
+ //
+ // Comments which appear to be attached to the previous token are stored
+ // in *prev_tailing_comments. Comments which appear to be attached to the
+ // next token are stored in *next_leading_comments. Comments appearing in
+ // between which do not appear to be attached to either will be added to
+ // detached_comments. Any of these parameters can be NULL to simply discard
+ // the comments.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // Only the comment content is returned; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk will
+ // be stripped from the beginning of each line other than the first. Newlines
+ // are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to qux.
+ // //
+ // // Another line attached to qux.
+ // optional double qux = 4;
+ //
+ // // Detached comment. This is not attached to qux or corge
+ // // because there are blank lines separating it from both.
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ bool NextWithComments(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments);
+
// Parse helpers ---------------------------------------------------
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
@@ -200,11 +248,12 @@ class LIBPROTOBUF_EXPORT Tokenizer {
int line_;
int column_;
- // Position in buffer_ where StartToken() was called. If the token
- // started in the previous buffer, this is zero, and current_.text already
- // contains the part of the token from the previous buffer. If not
- // currently parsing a token, this is -1.
- int token_start_;
+ // String to which text should be appended as we advance through it.
+ // Call RecordTo(&str) to start recording and StopRecording() to stop.
+ // E.g. StartToken() calls RecordTo(&current_.text). record_start_ is the
+ // position within the current buffer where recording started.
+ string* record_target_;
+ int record_start_;
// Options.
bool allow_f_after_float_;
@@ -223,6 +272,9 @@ class LIBPROTOBUF_EXPORT Tokenizer {
// Read a new buffer from the input.
void Refresh();
+ inline void RecordTo(string* target);
+ inline void StopRecording();
+
// Called when the current character is the first character of a new
// token (not including whitespace or comments).
inline void StartToken();
@@ -255,9 +307,28 @@ class LIBPROTOBUF_EXPORT Tokenizer {
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
// Consume the rest of a line.
- void ConsumeLineComment();
+ void ConsumeLineComment(string* content);
// Consume until "*/".
- void ConsumeBlockComment();
+ void ConsumeBlockComment(string* content);
+
+ enum NextCommentStatus {
+ // Started a line comment.
+ LINE_COMMENT,
+
+ // Started a block comment.
+ BLOCK_COMMENT,
+
+ // Consumed a slash, then realized it wasn't a comment. current_ has
+ // been filled in with a slash token. The caller should return it.
+ SLASH_NOT_COMMENT,
+
+ // We do not appear to be starting a comment here.
+ NO_COMMENT
+ };
+
+ // If we're at the start of a new comment, consume it and return what kind
+ // of comment it is.
+ NextCommentStatus TryConsumeCommentStart();
// -----------------------------------------------------------------
// These helper methods make the parsing code more readable. The
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index 106d080f..8de43939 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -32,9 +32,10 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <vector>
-#include <math.h>
#include <limits.h>
+#include <math.h>
+
+#include <vector>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -514,6 +515,217 @@ TEST_1D(TokenizerTest, ShCommentStyle, kBlockSizes) {
// -------------------------------------------------------------------
+// In each case, the input is expected to have two tokens named "prev" and
+// "next" with comments in between.
+struct DocCommentCase {
+ string input;
+
+ const char* prev_trailing_comments;
+ const char* detached_comments[10];
+ const char* next_leading_comments;
+};
+
+inline ostream& operator<<(ostream& out,
+ const DocCommentCase& test_case) {
+ return out << CEscape(test_case.input);
+}
+
+DocCommentCase kDocCommentCases[] = {
+ {
+ "prev next",
+
+ "",
+ {},
+ ""
+ },
+
+ {
+ "prev /* ignored */ next",
+
+ "",
+ {},
+ ""
+ },
+
+ {
+ "prev // trailing comment\n"
+ "next",
+
+ " trailing comment\n",
+ {},
+ ""
+ },
+
+ {
+ "prev\n"
+ "// leading comment\n"
+ "// line 2\n"
+ "next",
+
+ "",
+ {},
+ " leading comment\n"
+ " line 2\n"
+ },
+
+ {
+ "prev\n"
+ "// trailing comment\n"
+ "// line 2\n"
+ "\n"
+ "next",
+
+ " trailing comment\n"
+ " line 2\n",
+ {},
+ ""
+ },
+
+ {
+ "prev // trailing comment\n"
+ "// leading comment\n"
+ "// line 2\n"
+ "next",
+
+ " trailing comment\n",
+ {},
+ " leading comment\n"
+ " line 2\n"
+ },
+
+ {
+ "prev /* trailing block comment */\n"
+ "/* leading block comment\n"
+ " * line 2\n"
+ " * line 3 */"
+ "next",
+
+ " trailing block comment ",
+ {},
+ " leading block comment\n"
+ " line 2\n"
+ " line 3 "
+ },
+
+ {
+ "prev\n"
+ "/* trailing block comment\n"
+ " * line 2\n"
+ " * line 3\n"
+ " */\n"
+ "/* leading block comment\n"
+ " * line 2\n"
+ " * line 3 */"
+ "next",
+
+ " trailing block comment\n"
+ " line 2\n"
+ " line 3\n",
+ {},
+ " leading block comment\n"
+ " line 2\n"
+ " line 3 "
+ },
+
+ {
+ "prev\n"
+ "// trailing comment\n"
+ "\n"
+ "// detached comment\n"
+ "// line 2\n"
+ "\n"
+ "// second detached comment\n"
+ "/* third detached comment\n"
+ " * line 2 */\n"
+ "// leading comment\n"
+ "next",
+
+ " trailing comment\n",
+ {
+ " detached comment\n"
+ " line 2\n",
+ " second detached comment\n",
+ " third detached comment\n"
+ " line 2 "
+ },
+ " leading comment\n"
+ },
+
+ {
+ "prev /**/\n"
+ "\n"
+ "// detached comment\n"
+ "\n"
+ "// leading comment\n"
+ "next",
+
+ "",
+ {
+ " detached comment\n"
+ },
+ " leading comment\n"
+ },
+
+ {
+ "prev /**/\n"
+ "// leading comment\n"
+ "next",
+
+ "",
+ {},
+ " leading comment\n"
+ },
+ };
+
+TEST_2D(TokenizerTest, DocComments, kDocCommentCases, kBlockSizes) {
+ // Set up the tokenizer.
+ TestInputStream input(kDocCommentCases_case.input.data(),
+ kDocCommentCases_case.input.size(),
+ kBlockSizes_case);
+ TestErrorCollector error_collector;
+ Tokenizer tokenizer(&input, &error_collector);
+
+ // Set up a second tokenizer where we'll pass all NULLs to NextWithComments().
+ TestInputStream input2(kDocCommentCases_case.input.data(),
+ kDocCommentCases_case.input.size(),
+ kBlockSizes_case);
+ Tokenizer tokenizer2(&input2, &error_collector);
+
+ tokenizer.Next();
+ tokenizer2.Next();
+
+ EXPECT_EQ("prev", tokenizer.current().text);
+ EXPECT_EQ("prev", tokenizer2.current().text);
+
+ string prev_trailing_comments;
+ vector<string> detached_comments;
+ string next_leading_comments;
+ tokenizer.NextWithComments(&prev_trailing_comments, &detached_comments,
+ &next_leading_comments);
+ tokenizer2.NextWithComments(NULL, NULL, NULL);
+ EXPECT_EQ("next", tokenizer.current().text);
+ EXPECT_EQ("next", tokenizer2.current().text);
+
+ EXPECT_EQ(kDocCommentCases_case.prev_trailing_comments,
+ prev_trailing_comments);
+
+ for (int i = 0; i < detached_comments.size(); i++) {
+ ASSERT_LT(i, GOOGLE_ARRAYSIZE(kDocCommentCases));
+ ASSERT_TRUE(kDocCommentCases_case.detached_comments[i] != NULL);
+ EXPECT_EQ(kDocCommentCases_case.detached_comments[i],
+ detached_comments[i]);
+ }
+
+ // Verify that we matched all the detached comments.
+ EXPECT_EQ(NULL,
+ kDocCommentCases_case.detached_comments[detached_comments.size()]);
+
+ EXPECT_EQ(kDocCommentCases_case.next_leading_comments,
+ next_leading_comments);
+}
+
+// -------------------------------------------------------------------
+
// Test parse helpers. It's not really worth setting up a full data-driven
// test here.
TEST_F(TokenizerTest, ParseInteger) {
@@ -614,6 +826,22 @@ TEST_F(TokenizerTest, ParseString) {
Tokenizer::ParseString("'\\", &output);
EXPECT_EQ("\\", output);
+ // Experiment with Unicode escapes. Here are one-, two- and three-byte Unicode
+ // characters.
+ Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\U00024b62XX'", &output);
+ EXPECT_EQ("$¢€𤭢XX", output);
+ // Same thing encoded using UTF16.
+ Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\ud852\\udf62XX'", &output);
+ EXPECT_EQ("$¢€𤭢XX", output);
+ // Here's some broken UTF16; there's a head surrogate with no tail surrogate.
+ // We just output this as if it were UTF8; it's not a defined code point, but
+ // it has a defined encoding.
+ Tokenizer::ParseString("'\\ud852XX'", &output);
+ EXPECT_EQ("\xed\xa1\x92XX", output);
+ // Malformed escape: Demons may fly out of the nose.
+ Tokenizer::ParseString("\\u0", &output);
+ EXPECT_EQ("u0", output);
+
// Test invalid strings that will never be tokenized as strings.
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
EXPECT_DEBUG_DEATH(Tokenizer::ParseString("", &output),
@@ -658,6 +886,12 @@ ErrorCase kErrorCases[] = {
"0:4: String literals cannot cross line boundaries.\n" },
{ "'bar\nfoo", true,
"0:4: String literals cannot cross line boundaries.\n" },
+ { "'\\u01' foo", true,
+ "0:5: Expected four hex digits for \\u escape sequence.\n" },
+ { "'\\u01' foo", true,
+ "0:5: Expected four hex digits for \\u escape sequence.\n" },
+ { "'\\uXYZ' foo", true,
+ "0:3: Expected four hex digits for \\u escape sequence.\n" },
// Integer errors.
{ "123foo", true,
@@ -734,7 +968,7 @@ TEST_2D(TokenizerTest, Errors, kErrorCases, kBlockSizes) {
}
// Check that the errors match what was expected.
- EXPECT_EQ(error_collector.text_, kErrorCases_case.errors);
+ EXPECT_EQ(kErrorCases_case.errors, error_collector.text_);
// If the error was recoverable, make sure we saw "foo" after it.
if (kErrorCases_case.recoverable) {
@@ -760,6 +994,7 @@ TEST_1D(TokenizerTest, BackUpOnDestruction, kBlockSizes) {
EXPECT_EQ(strlen("foo"), input.ByteCount());
}
+
} // namespace
} // namespace io
} // namespace protobuf
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index 1384c746..9fcbb622 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -46,7 +46,8 @@
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
+
namespace google {
namespace protobuf {
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 e8012510..f552e1f8 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -32,9 +32,9 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
index 5196d905..6f155df7 100644
--- a/src/google/protobuf/io/zero_copy_stream_unittest.cc
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -370,6 +370,100 @@ TEST_F(IoTest, GzipIo) {
delete [] buffer;
}
+TEST_F(IoTest, GzipIoWithFlush) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+ // We start with i = 4 as we want a block size > 6. With block size <= 6
+ // Flush() fills up the entire 2K buffer with flush markers and the test
+ // fails. See documentation for Flush() for more detail.
+ for (int i = 4; i < kBlockSizeCount; i++) {
+ for (int j = 0; j < kBlockSizeCount; j++) {
+ for (int z = 0; z < kBlockSizeCount; z++) {
+ int gzip_buffer_size = kBlockSizes[z];
+ int size;
+ {
+ ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ gzout.Close();
+ size = output.ByteCount();
+ }
+ {
+ ArrayInputStream input(buffer, size, kBlockSizes[j]);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+ }
+ }
+ }
+ }
+ delete [] buffer;
+}
+
+TEST_F(IoTest, GzipIoContiguousFlushes) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+
+ int block_size = kBlockSizes[4];
+ int gzip_buffer_size = block_size;
+ int size;
+
+ ArrayOutputStream output(buffer, kBufferSize, block_size);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ EXPECT_TRUE(gzout.Flush());
+ gzout.Close();
+ size = output.ByteCount();
+
+ ArrayInputStream input(buffer, size, block_size);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+
+ delete [] buffer;
+}
+
+TEST_F(IoTest, GzipIoReadAfterFlush) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+
+ int block_size = kBlockSizes[4];
+ int gzip_buffer_size = block_size;
+ int size;
+ ArrayOutputStream output(buffer, kBufferSize, block_size);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ size = output.ByteCount();
+
+ ArrayInputStream input(buffer, size, block_size);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+
+ gzout.Close();
+
+ delete [] buffer;
+}
+
TEST_F(IoTest, ZlibIo) {
const int kBufferSize = 2*1024;
uint8* buffer = new uint8[kBufferSize];
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index ffeec3c4..7a0a57b7 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -33,11 +33,32 @@
#include <string>
#include <iostream>
-#include <google/protobuf/test_util_lite.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/test_util_lite.h>
+#include <google/protobuf/unittest_lite.pb.h>
using namespace std;
+namespace {
+// Helper methods to test parsing merge behavior.
+void ExpectMessageMerged(const google::protobuf::unittest::TestAllTypesLite& message) {
+ GOOGLE_CHECK(message.optional_int32() == 3);
+ GOOGLE_CHECK(message.optional_int64() == 2);
+ GOOGLE_CHECK(message.optional_string() == "hello");
+}
+
+void AssignParsingMergeMessages(
+ google::protobuf::unittest::TestAllTypesLite* msg1,
+ google::protobuf::unittest::TestAllTypesLite* msg2,
+ google::protobuf::unittest::TestAllTypesLite* msg3) {
+ msg1->set_optional_int32(1);
+ msg2->set_optional_int64(2);
+ msg3->set_optional_int32(3);
+ msg3->set_optional_string("hello");
+}
+
+} // namespace
+
int main(int argc, char* argv[]) {
string data, packed_data;
@@ -107,6 +128,58 @@ int main(int argc, char* argv[]) {
google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
}
+ {
+ // Test that if an optional or required message/group field appears multiple
+ // times in the input, they need to be merged.
+ google::protobuf::unittest::TestParsingMergeLite::RepeatedFieldsGenerator generator;
+ google::protobuf::unittest::TestAllTypesLite* msg1;
+ google::protobuf::unittest::TestAllTypesLite* msg2;
+ google::protobuf::unittest::TestAllTypesLite* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+ msg1 = generator.add_##FIELD(); \
+ msg2 = generator.add_##FIELD(); \
+ msg3 = generator.add_##FIELD(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_FIELD(field1);
+ ASSIGN_REPEATED_FIELD(field2);
+ ASSIGN_REPEATED_FIELD(field3);
+ ASSIGN_REPEATED_FIELD(ext1);
+ ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD) \
+ msg1 = generator.add_##FIELD()->mutable_field1(); \
+ msg2 = generator.add_##FIELD()->mutable_field1(); \
+ msg3 = generator.add_##FIELD()->mutable_field1(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_GROUP(group1);
+ ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+ string buffer;
+ generator.SerializeToString(&buffer);
+ google::protobuf::unittest::TestParsingMergeLite parsing_merge;
+ parsing_merge.ParseFromString(buffer);
+
+ // Required and optional fields should be merged.
+ ExpectMessageMerged(parsing_merge.required_all_types());
+ ExpectMessageMerged(parsing_merge.optional_all_types());
+ ExpectMessageMerged(
+ parsing_merge.optionalgroup().optional_group_all_types());
+ ExpectMessageMerged(parsing_merge.GetExtension(
+ google::protobuf::unittest::TestParsingMergeLite::optional_ext));
+
+ // Repeated fields should not be merged.
+ GOOGLE_CHECK(parsing_merge.repeated_all_types_size() == 3);
+ GOOGLE_CHECK(parsing_merge.repeatedgroup_size() == 3);
+ GOOGLE_CHECK(parsing_merge.ExtensionSize(
+ google::protobuf::unittest::TestParsingMergeLite::repeated_ext) == 3);
+ }
+
cout << "PASS" << endl;
return 0;
}
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 91e6878e..6119d26a 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -43,11 +43,12 @@
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -181,9 +182,46 @@ bool Message::SerializePartialToOstream(ostream* output) const {
}
+// =============================================================================
+// Reflection and associated Template Specializations
+
Reflection::~Reflection() {}
-// ===================================================================
+#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \
+template<> \
+const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \
+ const Message& message, const FieldDescriptor* field) const { \
+ return *static_cast<RepeatedField<TYPE>* >( \
+ MutableRawRepeatedField(const_cast<Message*>(&message), \
+ field, CPPTYPE, CTYPE, NULL)); \
+} \
+ \
+template<> \
+RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \
+ Message* message, const FieldDescriptor* field) const { \
+ return static_cast<RepeatedField<TYPE>* >( \
+ MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \
+}
+
+HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1);
+HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1);
+HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1);
+HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1);
+HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
+HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
+HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
+
+
+#undef HANDLE_TYPE
+
+void* Reflection::MutableRawRepeatedString(
+ Message* message, const FieldDescriptor* field, bool is_string) const {
+ return MutableRawRepeatedField(message, field,
+ FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, NULL);
+}
+
+
+// =============================================================================
// MessageFactory
MessageFactory::~MessageFactory() {}
@@ -257,6 +295,7 @@ void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
}
}
+
const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
{
ReaderMutexLock lock(&mutex_);
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 4bbc6418..77faa9a7 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -79,18 +79,19 @@
// // Same as the last block, but do it dynamically via the Message
// // reflection interface.
// Message* foo = new Foo;
-// Descriptor* descriptor = foo->GetDescriptor();
+// const Descriptor* descriptor = foo->GetDescriptor();
//
// // Get the descriptors for the fields we're interested in and verify
// // their types.
-// FieldDescriptor* text_field = descriptor->FindFieldByName("text");
+// const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
// assert(text_field != NULL);
// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
-// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL);
-// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers");
+// assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
+// const FieldDescriptor* numbers_field = descriptor->
+// FindFieldByName("numbers");
// assert(numbers_field != NULL);
// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
-// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED);
+// assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED);
//
// // Parse the message.
// foo->ParseFromString(data);
@@ -122,6 +123,7 @@
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
namespace google {
@@ -133,17 +135,20 @@ class Reflection;
class MessageFactory;
// Defined in other files.
-class Descriptor; // descriptor.h
-class FieldDescriptor; // descriptor.h
-class EnumDescriptor; // descriptor.h
-class EnumValueDescriptor; // descriptor.h
+class UnknownFieldSet; // unknown_field_set.h
namespace io {
class ZeroCopyInputStream; // zero_copy_stream.h
class ZeroCopyOutputStream; // zero_copy_stream.h
class CodedInputStream; // coded_stream.h
class CodedOutputStream; // coded_stream.h
}
-class UnknownFieldSet; // unknown_field_set.h
+
+
+template<typename T>
+class RepeatedField; // repeated_field.h
+
+template<typename T>
+class RepeatedPtrField; // repeated_field.h
// A container to hold message metadata.
struct Metadata {
@@ -151,12 +156,6 @@ struct Metadata {
const Reflection* reflection;
};
-// Returns the EnumDescriptor for enum type E, which must be a
-// proto-declared enum type. Code generated by the protocol compiler
-// will include specializations of this template for each enum type declared.
-template <typename E>
-const EnumDescriptor* GetEnumDescriptor();
-
// Abstract interface for protocol messages.
//
// See also MessageLite, which contains most every-day operations. Message
@@ -360,7 +359,6 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite {
// write fields from a Reflection without paying attention to the type.
class LIBPROTOBUF_EXPORT Reflection {
public:
- // TODO(kenton): Remove parameter.
inline Reflection() {}
virtual ~Reflection();
@@ -390,7 +388,7 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual void ClearField(Message* message,
const FieldDescriptor* field) const = 0;
- // Remove the last element of a repeated field.
+ // Removes the last element of a repeated field.
// We don't provide a way to remove any element other than the last
// because it invites inefficient use, such as O(n^2) filtering loops
// that should have been O(n). If you want to remove an element other
@@ -399,6 +397,10 @@ class LIBPROTOBUF_EXPORT Reflection {
// call RemoveLast().
virtual void RemoveLast(Message* message,
const FieldDescriptor* field) const = 0;
+ // Removes the last element of a repeated message field, and returns the
+ // pointer to the caller. Caller takes ownership of the returned pointer.
+ virtual Message* ReleaseLast(Message* message,
+ const FieldDescriptor* field) const = 0;
// Swap the complete contents of two messages.
virtual void Swap(Message* message1, Message* message2) const = 0;
@@ -500,6 +502,16 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual Message* MutableMessage(Message* message,
const FieldDescriptor* field,
MessageFactory* factory = NULL) const = 0;
+ // Releases the message specified by 'field' and returns the pointer,
+ // ReleaseMessage() will return the message the message object if it exists.
+ // Otherwise, it may or may not return NULL. In any case, if the return value
+ // is non-NULL, the caller takes ownership of the pointer.
+ // If the field existed (HasField() is true), then the returned pointer will
+ // be the same as the pointer returned by MutableMessage().
+ // This function has the same effect as ClearField().
+ virtual Message* ReleaseMessage(Message* message,
+ const FieldDescriptor* field,
+ MessageFactory* factory = NULL) const = 0;
// Repeated field getters ------------------------------------------
@@ -607,7 +619,39 @@ class LIBPROTOBUF_EXPORT Reflection {
MessageFactory* factory = NULL) const = 0;
- // Extensions ------------------------------------------------------
+ // Repeated field accessors -------------------------------------------------
+ // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular
+ // access to the data in a RepeatedField. The methods below provide aggregate
+ // access by exposing the RepeatedField object itself with the Message.
+ // Applying these templates to inappropriate types will lead to an undefined
+ // reference at link time (e.g. GetRepeatedField<***double>), or possibly a
+ // template matching error at compile time (e.g. GetRepeatedPtrField<File>).
+ //
+ // Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
+
+ // for T = Cord and all protobuf scalar types except enums.
+ template<typename T>
+ const RepeatedField<T>& GetRepeatedField(
+ const Message&, const FieldDescriptor*) const;
+
+ // for T = Cord and all protobuf scalar types except enums.
+ template<typename T>
+ RepeatedField<T>* MutableRepeatedField(
+ Message*, const FieldDescriptor*) const;
+
+ // for T = string, google::protobuf::internal::StringPieceField
+ // google::protobuf::Message & descendants.
+ template<typename T>
+ const RepeatedPtrField<T>& GetRepeatedPtrField(
+ const Message&, const FieldDescriptor*) const;
+
+ // for T = string, google::protobuf::internal::StringPieceField
+ // google::protobuf::Message & descendants.
+ template<typename T>
+ RepeatedPtrField<T>* MutableRepeatedPtrField(
+ Message*, const FieldDescriptor*) const;
+
+ // Extensions ----------------------------------------------------------------
// Try to find an extension of this message type by fully-qualified field
// name. Returns NULL if no extension is known for this name or number.
@@ -619,7 +663,26 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual const FieldDescriptor* FindKnownExtensionByNumber(
int number) const = 0;
+ // ---------------------------------------------------------------------------
+
+ protected:
+ // Obtain a pointer to a Repeated Field Structure and do some type checking:
+ // on field->cpp_type(),
+ // on field->field_option().ctype() (if ctype >= 0)
+ // of field->message_type() (if message_type != NULL).
+ // We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer).
+ virtual void* MutableRawRepeatedField(
+ Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
+ int ctype, const Descriptor* message_type) const = 0;
+
private:
+ // Special version for specialized implementations of string. We can't call
+ // MutableRawRepeatedField directly here because we don't have access to
+ // FieldOptions::* which are defined in descriptor.pb.h. Including that
+ // file here is not possible because it would cause a circular include cycle.
+ void* MutableRawRepeatedString(
+ Message* message, const FieldDescriptor* field, bool is_string) const;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
};
@@ -682,10 +745,71 @@ class LIBPROTOBUF_EXPORT MessageFactory {
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
const Message* prototype);
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
};
+// =============================================================================
+// Implementation details for {Get,Mutable}RawRepeatedPtrField. We provide
+// specializations for <string>, <StringPieceField> and <Message> and handle
+// everything else with the default template which will match any type having
+// a method with signature "static const google::protobuf::Descriptor* descriptor()".
+// Such a type presumably is a descendant of google::protobuf::Message.
+
+template<>
+inline const RepeatedPtrField<string>& Reflection::GetRepeatedPtrField<string>(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<string>* >(
+ MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
+}
+
+template<>
+inline RepeatedPtrField<string>* Reflection::MutableRepeatedPtrField<string>(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<string>* >(
+ MutableRawRepeatedString(message, field, true));
+}
+
+
+// -----
+
+template<>
+inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrField(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<Message>* >(
+ MutableRawRepeatedField(const_cast<Message*>(&message), field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ NULL));
+}
+
+template<>
+inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrField(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<Message>* >(
+ MutableRawRepeatedField(message, field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ NULL));
+}
+
+template<typename PB>
+inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrField(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<PB>* >(
+ MutableRawRepeatedField(const_cast<Message*>(&message), field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ PB::default_instance().GetDescriptor()));
+}
+
+template<typename PB>
+inline RepeatedPtrField<PB>* Reflection::MutableRepeatedPtrField(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<PB>* >(
+ MutableRawRepeatedField(message, field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ PB::default_instance().GetDescriptor()));
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 7c8f37dc..49dbe6e0 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -37,8 +37,8 @@
#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/stubs/stl_util-inl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index ebf4ba3c..1ec3068c 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -40,11 +40,17 @@
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/io/coded_stream.h>
namespace google {
namespace protobuf {
+namespace io {
+ class CodedInputStream;
+ class CodedOutputStream;
+ class ZeroCopyInputStream;
+ class ZeroCopyOutputStream;
+}
+
// Interface to light weight protocol messages.
//
// This interface is implemented by all protocol message objects. Non-lite
@@ -158,6 +164,7 @@ class LIBPROTOBUF_EXPORT MessageLite {
// followed by IsInitialized().
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0;
+
// Serialization ---------------------------------------------------
// Methods for serializing in protocol buffer format. Most of these
// are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
index 33b9e77c..8aaeabb4 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -257,6 +257,78 @@ TEST(MessageTest, ParseFailsOnInvalidMessageEnd) {
EXPECT_FALSE(message.ParseFromArray("\014", 1));
}
+namespace {
+
+void ExpectMessageMerged(const unittest::TestAllTypes& message) {
+ EXPECT_EQ(3, message.optional_int32());
+ EXPECT_EQ(2, message.optional_int64());
+ EXPECT_EQ("hello", message.optional_string());
+}
+
+void AssignParsingMergeMessages(
+ unittest::TestAllTypes* msg1,
+ unittest::TestAllTypes* msg2,
+ unittest::TestAllTypes* msg3) {
+ msg1->set_optional_int32(1);
+ msg2->set_optional_int64(2);
+ msg3->set_optional_int32(3);
+ msg3->set_optional_string("hello");
+}
+
+} // namespace
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+TEST(MessageTest, ParsingMerge) {
+ unittest::TestParsingMerge::RepeatedFieldsGenerator generator;
+ unittest::TestAllTypes* msg1;
+ unittest::TestAllTypes* msg2;
+ unittest::TestAllTypes* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+ msg1 = generator.add_##FIELD(); \
+ msg2 = generator.add_##FIELD(); \
+ msg3 = generator.add_##FIELD(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_FIELD(field1);
+ ASSIGN_REPEATED_FIELD(field2);
+ ASSIGN_REPEATED_FIELD(field3);
+ ASSIGN_REPEATED_FIELD(ext1);
+ ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD) \
+ msg1 = generator.add_##FIELD()->mutable_field1(); \
+ msg2 = generator.add_##FIELD()->mutable_field1(); \
+ msg3 = generator.add_##FIELD()->mutable_field1(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_GROUP(group1);
+ ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+ string buffer;
+ generator.SerializeToString(&buffer);
+ unittest::TestParsingMerge parsing_merge;
+ parsing_merge.ParseFromString(buffer);
+
+ // Required and optional fields should be merged.
+ ExpectMessageMerged(parsing_merge.required_all_types());
+ ExpectMessageMerged(parsing_merge.optional_all_types());
+ ExpectMessageMerged(
+ parsing_merge.optionalgroup().optional_group_all_types());
+ ExpectMessageMerged(
+ parsing_merge.GetExtension(unittest::TestParsingMerge::optional_ext));
+
+ // Repeated fields should not be merged.
+ EXPECT_EQ(3, parsing_merge.repeated_all_types_size());
+ EXPECT_EQ(3, parsing_merge.repeatedgroup_size());
+ EXPECT_EQ(3, parsing_merge.ExtensionSize(
+ unittest::TestParsingMerge::repeated_ext));
+}
+
TEST(MessageFactoryTest, GeneratedFactoryLookup) {
EXPECT_EQ(
MessageFactory::generated_factory()->GetPrototype(
@@ -277,5 +349,6 @@ TEST(MessageFactoryTest, GeneratedFactoryUnknownType) {
MessageFactory::generated_factory()->GetPrototype(descriptor) == NULL);
}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index 897c0d7c..f00997c6 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -32,8 +32,12 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <string>
+#include <vector>
+
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/stubs/strutil.h>
@@ -151,11 +155,12 @@ bool ReflectionOps::IsInitialized(const Message& message) {
for (int i = 0; i < fields.size(); i++) {
const FieldDescriptor* field = fields[i];
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
if (field->is_repeated()) {
int size = reflection->FieldSize(message, field);
- for (int i = 0; i < size; i++) {
- if (!reflection->GetRepeatedMessage(message, field, i)
+ for (int j = 0; j < size; j++) {
+ if (!reflection->GetRepeatedMessage(message, field, j)
.IsInitialized()) {
return false;
}
@@ -183,8 +188,8 @@ void ReflectionOps::DiscardUnknownFields(Message* message) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (field->is_repeated()) {
int size = reflection->FieldSize(*message, field);
- for (int i = 0; i < size; i++) {
- reflection->MutableRepeatedMessage(message, field, i)
+ for (int j = 0; j < size; j++) {
+ reflection->MutableRepeatedMessage(message, field, j)
->DiscardUnknownFields();
}
} else {
@@ -240,11 +245,11 @@ void ReflectionOps::FindInitializationErrors(
if (field->is_repeated()) {
int size = reflection->FieldSize(message, field);
- for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
const Message& sub_message =
- reflection->GetRepeatedMessage(message, field, i);
+ reflection->GetRepeatedMessage(message, field, j);
FindInitializationErrors(sub_message,
- SubMessagePrefix(prefix, field, i),
+ SubMessagePrefix(prefix, field, j),
errors);
}
} else {
diff --git a/src/google/protobuf/reflection_ops.h b/src/google/protobuf/reflection_ops.h
index 355a0a5d..60165c2a 100644
--- a/src/google/protobuf/reflection_ops.h
+++ b/src/google/protobuf/reflection_ops.h
@@ -38,6 +38,7 @@
#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__
#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
namespace google {
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
index 09377742..87ce28c8 100644
--- a/src/google/protobuf/repeated_field.cc
+++ b/src/google/protobuf/repeated_field.cc
@@ -46,7 +46,8 @@ void RepeatedPtrFieldBase::Reserve(int new_size) {
if (total_size_ >= new_size) return;
void** old_elements = elements_;
- total_size_ = max(total_size_ * 2, new_size);
+ total_size_ = max(kMinRepeatedFieldAllocationSize,
+ max(total_size_ * 2, new_size));
elements_ = new void*[total_size_];
memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
if (old_elements != initial_space_) {
@@ -55,6 +56,7 @@ void RepeatedPtrFieldBase::Reserve(int new_size) {
}
void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
+ if (this == other) return;
void** swap_elements = elements_;
int swap_current_size = current_size_;
int swap_allocated_size = allocated_size_;
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index aed4ce9f..f0032e7d 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -46,24 +46,35 @@
#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+#include <algorithm>
#include <string>
#include <iterator>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/type_traits.h>
+#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
namespace google {
+namespace upb {
+namespace proto2_bridge_opensource {
+class FieldAccessor;
+} // namespace protobuf_bridge_opensource
+} // namespace upb
+
namespace protobuf {
class Message;
namespace internal {
-// We need this (from generated_message_reflection.cc).
-LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
+static const int kMinRepeatedFieldAllocationSize = 4;
+// A utility function for logging that doesn't need any template types.
+void LogIndexOutOfBounds(int index, int size);
} // namespace internal
+
// RepeatedField is used to represent repeated fields of a primitive type (in
// other words, everything except strings and nested Messages). Most users will
// not ever use a RepeatedField directly; they will use the get-by-index,
@@ -73,6 +84,8 @@ class RepeatedField {
public:
RepeatedField();
RepeatedField(const RepeatedField& other);
+ template <typename Iter>
+ RepeatedField(Iter begin, const Iter& end);
~RepeatedField();
RepeatedField& operator=(const RepeatedField& other);
@@ -85,12 +98,14 @@ class RepeatedField {
void Add(const Element& value);
Element* Add();
// Remove the last element in the array.
- // We don't provide a way to remove any element other than the last
- // because it invites inefficient use, such as O(n^2) filtering loops
- // that should have been O(n). If you want to remove an element other
- // than the last, the best way to do it is to re-arrange the elements
- // so that the one you want removed is at the end, then call RemoveLast().
void RemoveLast();
+
+ // Extract elements with indices in "[start .. start+num-1]".
+ // Copy them into "elements[0 .. num-1]" if "elements" is not NULL.
+ // Caution: implementation also moves elements with indices [start+num ..].
+ // Calling this routine inside a loop can cause quadratic behavior.
+ void ExtractSubrange(int start, int num, Element* elements);
+
void Clear();
void MergeFrom(const RepeatedField& other);
void CopyFrom(const RepeatedField& other);
@@ -121,25 +136,49 @@ class RepeatedField {
typedef Element* iterator;
typedef const Element* const_iterator;
typedef Element value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef int size_type;
+ typedef ptrdiff_t difference_type;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
+ // Reverse iterator support
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
// Returns the number of bytes used by the repeated field, excluding
// sizeof(*this)
int SpaceUsedExcludingSelf() const;
private:
- static const int kInitialSize = 4;
+ static const int kInitialSize = 0;
+
+ // This cannot be the last attribute defined if kInitialSize is 0 or
+ // the checks elements_ != initial_space_ to delete are not valid.
+ Element initial_space_[kInitialSize];
Element* elements_;
int current_size_;
int total_size_;
- Element initial_space_[kInitialSize];
-
// Move the contents of |from| into |to|, possibly clobbering |from| in the
// process. For primitive types this is just a memcpy(), but it could be
// specialized for non-primitive types to, say, swap each element instead.
@@ -151,7 +190,21 @@ class RepeatedField {
namespace internal {
template <typename It> class RepeatedPtrIterator;
-template <typename It> class RepeatedPtrOverPtrsIterator;
+template <typename It, typename VoidPtr> class RepeatedPtrOverPtrsIterator;
+} // namespace internal
+
+namespace internal {
+
+// This is a helper template to copy an array of elements effeciently when they
+// have a trivial copy constructor, and correctly otherwise. This really
+// shouldn't be necessary, but our compiler doesn't optimize std::copy very
+// effectively.
+template <typename Element,
+ bool HasTrivialCopy = has_trivial_copy<Element>::value>
+struct ElementCopier {
+ void operator()(Element to[], const Element from[], int array_size);
+};
+
} // namespace internal
namespace internal {
@@ -186,6 +239,10 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
// use of AddFromCleared(), which is not part of the public interface.
friend class ExtensionSet;
+ // To parse directly into a proto2 generated class, the upb FieldAccessor
+ // needs to be able to modify a RepeatedPtrFieldBase directly.
+ friend class LIBPROTOBUF_EXPORT upb::proto2_bridge_opensource::FieldAccessor;
+
RepeatedPtrFieldBase();
// Must be called from destructor.
@@ -209,6 +266,14 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
void CopyFrom(const RepeatedPtrFieldBase& other);
+ void CloseGap(int start, int num) {
+ // Close up a gap of "num" elements starting at offset "start".
+ for (int i = start + num; i < allocated_size_; ++i)
+ elements_[i - num] = elements_[i];
+ current_size_ -= num;
+ allocated_size_ -= num;
+ }
+
void Reserve(int new_size);
int Capacity() const;
@@ -250,15 +315,17 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
- static const int kInitialSize = 4;
+ static const int kInitialSize = 0;
+
+ // This cannot be the last attribute defined if kInitialSize is 0 or
+ // the checks elements_ != initial_space_ to delete are not valid.
+ void* initial_space_[kInitialSize];
void** elements_;
int current_size_;
int allocated_size_;
int total_size_;
- void* initial_space_[kInitialSize];
-
template <typename TypeHandler>
static inline typename TypeHandler::Type* cast(void* element) {
return reinterpret_cast<typename TypeHandler::Type*>(element);
@@ -280,6 +347,7 @@ class GenericTypeHandler {
to->MergeFrom(from);
}
static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); }
+ static const Type& default_instance() { return Type::default_instance(); }
};
template <>
@@ -288,6 +356,25 @@ inline void GenericTypeHandler<MessageLite>::Merge(
to->CheckTypeAndMergeFrom(from);
}
+template <>
+inline const MessageLite& GenericTypeHandler<MessageLite>::default_instance() {
+ // Yes, the behavior of the code is undefined, but this function is only
+ // called when we're already deep into the world of undefined, because the
+ // caller called Get(index) out of bounds.
+ MessageLite* null = NULL;
+ return *null;
+}
+
+template <>
+inline const Message& GenericTypeHandler<Message>::default_instance() {
+ // Yes, the behavior of the code is undefined, but this function is only
+ // called when we're already deep into the world of undefined, because the
+ // caller called Get(index) out of bounds.
+ Message* null = NULL;
+ return *null;
+}
+
+
// HACK: If a class is declared as DLL-exported in MSVC, it insists on
// generating copies of all its methods -- even inline ones -- to include
// in the DLL. But SpaceUsed() calls StringSpaceUsedExcludingSelf() which
@@ -303,6 +390,9 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
static void Delete(string* value);
static void Clear(string* value) { value->clear(); }
static void Merge(const string& from, string* to) { *to = from; }
+ static const Type& default_instance() {
+ return ::google::protobuf::internal::kEmptyString;
+ }
};
class StringTypeHandler : public StringTypeHandlerBase {
@@ -322,6 +412,8 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
public:
RepeatedPtrField();
RepeatedPtrField(const RepeatedPtrField& other);
+ template <typename Iter>
+ RepeatedPtrField(Iter begin, const Iter& end);
~RepeatedPtrField();
RepeatedPtrField& operator=(const RepeatedPtrField& other);
@@ -331,7 +423,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
const Element& Get(int index) const;
Element* Mutable(int index);
Element* Add();
- void RemoveLast(); // Remove the last element in the array.
+
+ // Remove the last element in the array.
+ // Ownership of the element is retained by the array.
+ void RemoveLast();
+
+ // Delete elements with indices in the range [start .. start+num-1].
+ // Caution: implementation moves all elements with indices [start+num .. ].
+ // Calling this routine inside a loop can cause quadratic behavior.
+ void DeleteSubrange(int start, int num);
+
void Clear();
void MergeFrom(const RepeatedPtrField& other);
void CopyFrom(const RepeatedPtrField& other);
@@ -358,42 +459,78 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
typedef internal::RepeatedPtrIterator<Element> iterator;
typedef internal::RepeatedPtrIterator<const Element> const_iterator;
typedef Element value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef int size_type;
+ typedef ptrdiff_t difference_type;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
+ // Reverse iterator support
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
// Custom STL-like iterator that iterates over and returns the underlying
// pointers to Element rather than Element itself.
- typedef internal::RepeatedPtrOverPtrsIterator<Element> pointer_iterator;
+ typedef internal::RepeatedPtrOverPtrsIterator<Element, void*>
+ pointer_iterator;
+ typedef internal::RepeatedPtrOverPtrsIterator<const Element, const void*>
+ const_pointer_iterator;
pointer_iterator pointer_begin();
+ const_pointer_iterator pointer_begin() const;
pointer_iterator pointer_end();
+ const_pointer_iterator pointer_end() const;
// Returns (an estimate of) the number of bytes used by the repeated field,
// excluding sizeof(*this).
int SpaceUsedExcludingSelf() const;
// Advanced memory management --------------------------------------
- // When hardcore memory management becomes necessary -- as it often
+ // When hardcore memory management becomes necessary -- as it sometimes
// does here at Google -- the following methods may be useful.
// Add an already-allocated object, passing ownership to the
// RepeatedPtrField.
void AddAllocated(Element* value);
- // Remove the last element and return it, passing ownership to the
- // caller.
+ // Remove the last element and return it, passing ownership to the caller.
// Requires: size() > 0
Element* ReleaseLast();
+ // Extract elements with indices in the range "[start .. start+num-1]".
+ // The caller assumes ownership of the extracted elements and is responsible
+ // for deleting them when they are no longer needed.
+ // If "elements" is non-NULL, then pointers to the extracted elements
+ // are stored in "elements[0 .. num-1]" for the convenience of the caller.
+ // If "elements" is NULL, then the caller must use some other mechanism
+ // to perform any further operations (like deletion) on these elements.
+ // Caution: implementation also moves elements with indices [start+num ..].
+ // Calling this routine inside a loop can cause quadratic behavior.
+ void ExtractSubrange(int start, int num, Element** elements);
+
// When elements are removed by calls to RemoveLast() or Clear(), they
// are not actually freed. Instead, they are cleared and kept so that
// they can be reused later. This can save lots of CPU time when
// repeatedly reusing a protocol message for similar purposes.
//
- // Really, extremely hardcore programs may actually want to manipulate
- // these objects to better-optimize memory management. These methods
- // allow that.
+ // Hardcore programs may choose to manipulate these cleared objects
+ // to better optimize memory management using the following routines.
// Get the number of cleared objects that are currently being kept
// around for reuse.
@@ -434,6 +571,17 @@ inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
}
template <typename Element>
+template <typename Iter>
+inline RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
+ : elements_(initial_space_),
+ current_size_(0),
+ total_size_(kInitialSize) {
+ for (; begin != end; ++begin) {
+ Add(*begin);
+ }
+}
+
+template <typename Element>
RepeatedField<Element>::~RepeatedField() {
if (elements_ != initial_space_) {
delete [] elements_;
@@ -443,7 +591,8 @@ RepeatedField<Element>::~RepeatedField() {
template <typename Element>
inline RepeatedField<Element>&
RepeatedField<Element>::operator=(const RepeatedField& other) {
- CopyFrom(other);
+ if (this != &other)
+ CopyFrom(other);
return *this;
}
@@ -506,6 +655,27 @@ inline void RepeatedField<Element>::RemoveLast() {
}
template <typename Element>
+void RepeatedField<Element>::ExtractSubrange(
+ int start, int num, Element* elements) {
+ GOOGLE_DCHECK_GE(start, 0);
+ GOOGLE_DCHECK_GE(num, 0);
+ GOOGLE_DCHECK_LE(start + num, this->size());
+
+ // Save the values of the removed elements if requested.
+ if (elements != NULL) {
+ for (int i = 0; i < num; ++i)
+ elements[i] = this->Get(i + start);
+ }
+
+ // Slide remaining elements down to fill the gap.
+ if (num > 0) {
+ for (int i = start + num; i < this->size(); ++i)
+ this->Set(i - num, this->Get(i));
+ this->Truncate(this->size() - num);
+ }
+}
+
+template <typename Element>
inline void RepeatedField<Element>::Clear() {
current_size_ = 0;
}
@@ -536,6 +706,7 @@ inline const Element* RepeatedField<Element>::data() const {
template <typename Element>
void RepeatedField<Element>::Swap(RepeatedField* other) {
+ if (this == other) return;
Element* swap_elements = elements_;
int swap_current_size = current_size_;
int swap_total_size = total_size_;
@@ -593,14 +764,15 @@ inline int RepeatedField<Element>::SpaceUsedExcludingSelf() const {
return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0;
}
-// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant
+// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
// amount of code bloat.
template <typename Element>
void RepeatedField<Element>::Reserve(int new_size) {
if (total_size_ >= new_size) return;
Element* old_elements = elements_;
- total_size_ = max(total_size_ * 2, new_size);
+ total_size_ = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
+ max(total_size_ * 2, new_size));
elements_ = new Element[total_size_];
MoveArray(elements_, old_elements, current_size_);
if (old_elements != initial_space_) {
@@ -617,15 +789,32 @@ inline void RepeatedField<Element>::Truncate(int new_size) {
template <typename Element>
inline void RepeatedField<Element>::MoveArray(
Element to[], Element from[], int array_size) {
- memcpy(to, from, array_size * sizeof(Element));
+ CopyArray(to, from, array_size);
}
template <typename Element>
inline void RepeatedField<Element>::CopyArray(
Element to[], const Element from[], int array_size) {
- memcpy(to, from, array_size * sizeof(Element));
+ internal::ElementCopier<Element>()(to, from, array_size);
}
+namespace internal {
+
+template <typename Element, bool HasTrivialCopy>
+void ElementCopier<Element, HasTrivialCopy>::operator()(
+ Element to[], const Element from[], int array_size) {
+ std::copy(from, from + array_size, to);
+}
+
+template <typename Element>
+struct ElementCopier<Element, true> {
+ void operator()(Element to[], const Element from[], int array_size) {
+ memcpy(to, from, array_size * sizeof(Element));
+ }
+};
+
+} // namespace internal
+
// -------------------------------------------------------------------
@@ -652,7 +841,6 @@ inline int RepeatedPtrFieldBase::size() const {
return current_size_;
}
-
template <typename TypeHandler>
inline const typename TypeHandler::Type&
RepeatedPtrFieldBase::Get(int index) const {
@@ -660,6 +848,7 @@ RepeatedPtrFieldBase::Get(int index) const {
return *cast<TypeHandler>(elements_[index]);
}
+
template <typename TypeHandler>
inline typename TypeHandler::Type*
RepeatedPtrFieldBase::Mutable(int index) {
@@ -798,7 +987,6 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() {
return result;
}
-
inline int RepeatedPtrFieldBase::ClearedCount() const {
return allocated_size_ - current_size_;
}
@@ -822,11 +1010,13 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
template <typename Element>
class RepeatedPtrField<Element>::TypeHandler
- : public internal::GenericTypeHandler<Element> {};
+ : public internal::GenericTypeHandler<Element> {
+};
template <>
class RepeatedPtrField<string>::TypeHandler
- : public internal::StringTypeHandler {};
+ : public internal::StringTypeHandler {
+};
template <typename Element>
@@ -839,6 +1029,15 @@ inline RepeatedPtrField<Element>::RepeatedPtrField(
}
template <typename Element>
+template <typename Iter>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+ Iter begin, const Iter& end) {
+ for (; begin != end; ++begin) {
+ *Add() = *begin;
+ }
+}
+
+template <typename Element>
RepeatedPtrField<Element>::~RepeatedPtrField() {
Destroy<TypeHandler>();
}
@@ -846,7 +1045,8 @@ RepeatedPtrField<Element>::~RepeatedPtrField() {
template <typename Element>
inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
const RepeatedPtrField& other) {
- CopyFrom(other);
+ if (this != &other)
+ CopyFrom(other);
return *this;
}
@@ -860,6 +1060,7 @@ inline const Element& RepeatedPtrField<Element>::Get(int index) const {
return RepeatedPtrFieldBase::Get<TypeHandler>(index);
}
+
template <typename Element>
inline Element* RepeatedPtrField<Element>::Mutable(int index) {
return RepeatedPtrFieldBase::Mutable<TypeHandler>(index);
@@ -876,6 +1077,33 @@ inline void RepeatedPtrField<Element>::RemoveLast() {
}
template <typename Element>
+inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) {
+ GOOGLE_DCHECK_GE(start, 0);
+ GOOGLE_DCHECK_GE(num, 0);
+ GOOGLE_DCHECK_LE(start + num, size());
+ for (int i = 0; i < num; ++i)
+ delete RepeatedPtrFieldBase::Mutable<TypeHandler>(start + i);
+ ExtractSubrange(start, num, NULL);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrange(
+ int start, int num, Element** elements) {
+ GOOGLE_DCHECK_GE(start, 0);
+ GOOGLE_DCHECK_GE(num, 0);
+ GOOGLE_DCHECK_LE(start + num, size());
+
+ if (num > 0) {
+ // Save the values of the removed elements if requested.
+ if (elements != NULL) {
+ for (int i = 0; i < num; ++i)
+ elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+ }
+ CloseGap(start, num);
+ }
+}
+
+template <typename Element>
inline void RepeatedPtrField<Element>::Clear() {
RepeatedPtrFieldBase::Clear<TypeHandler>();
}
@@ -961,7 +1189,7 @@ namespace internal {
// refer to this class directly; use RepeatedPtrField<T>::iterator instead.
//
// The iterator for RepeatedPtrField<T>, RepeatedPtrIterator<T>, is
-// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors-inl.h,
+// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors.h,
// but adds random-access operators and is modified to wrap a void** base
// iterator (since RepeatedPtrField stores its array as a void* array and
// casting void** to T** would violate C++ aliasing rules).
@@ -1057,11 +1285,14 @@ class RepeatedPtrIterator
// rather than the objects themselves as RepeatedPtrIterator does.
// Consider using this when working with stl algorithms that change
// the array.
-template<typename Element>
+// The VoidPtr template parameter holds the type-agnostic pointer value
+// referenced by the iterator. It should either be "void *" for a mutable
+// iterator, or "const void *" for a constant iterator.
+template<typename Element, typename VoidPtr>
class RepeatedPtrOverPtrsIterator
: public std::iterator<std::random_access_iterator_tag, Element*> {
public:
- typedef RepeatedPtrOverPtrsIterator<Element> iterator;
+ typedef RepeatedPtrOverPtrsIterator<Element, VoidPtr> iterator;
typedef std::iterator<
std::random_access_iterator_tag, Element*> superclass;
@@ -1072,7 +1303,7 @@ class RepeatedPtrOverPtrsIterator
typedef typename superclass::difference_type difference_type;
RepeatedPtrOverPtrsIterator() : it_(NULL) {}
- explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {}
+ explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
// dereferenceable
reference operator*() const { return *reinterpret_cast<Element**>(it_); }
@@ -1127,10 +1358,9 @@ class RepeatedPtrOverPtrsIterator
friend class RepeatedPtrIterator;
// The internal iterator.
- void** it_;
+ VoidPtr* it_;
};
-
} // namespace internal
template <typename Element>
@@ -1160,10 +1390,21 @@ RepeatedPtrField<Element>::pointer_begin() {
return pointer_iterator(raw_mutable_data());
}
template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() const {
+ return const_pointer_iterator(const_cast<const void**>(raw_mutable_data()));
+}
+template <typename Element>
inline typename RepeatedPtrField<Element>::pointer_iterator
RepeatedPtrField<Element>::pointer_end() {
return pointer_iterator(raw_mutable_data() + size());
}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_end() const {
+ return const_pointer_iterator(
+ const_cast<const void**>(raw_mutable_data() + size()));
+}
// Iterators and helper functions that follow the spirit of the STL
@@ -1173,7 +1414,7 @@ RepeatedPtrField<Element>::pointer_end() {
// std::copy(some_sequence.begin(), some_sequence.end(),
// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence()));
//
-// Ported by johannes from util/gtl/proto-array-iterators-inl.h
+// Ported by johannes from util/gtl/proto-array-iterators.h
namespace internal {
// A back inserter for RepeatedField objects.
@@ -1194,7 +1435,7 @@ template<typename T> class RepeatedFieldBackInsertIterator
RepeatedFieldBackInsertIterator<T>& operator++() {
return *this;
}
- RepeatedFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
+ RepeatedFieldBackInsertIterator<T>& operator++(int /* unused */) {
return *this;
}
@@ -1225,7 +1466,7 @@ template<typename T> class RepeatedPtrFieldBackInsertIterator
RepeatedPtrFieldBackInsertIterator<T>& operator++() {
return *this;
}
- RepeatedPtrFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
+ RepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
return *this;
}
@@ -1254,7 +1495,7 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
return *this;
}
AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
- int ignores_parameter) {
+ int /* unused */) {
return *this;
}
@@ -1264,16 +1505,22 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
} // namespace internal
// Provides a back insert iterator for RepeatedField instances,
-// similar to std::back_inserter(). Note the identically named
-// function for RepeatedPtrField instances.
+// similar to std::back_inserter().
template<typename T> internal::RepeatedFieldBackInsertIterator<T>
RepeatedFieldBackInserter(RepeatedField<T>* const mutable_field) {
return internal::RepeatedFieldBackInsertIterator<T>(mutable_field);
}
// Provides a back insert iterator for RepeatedPtrField instances,
-// similar to std::back_inserter(). Note the identically named
-// function for RepeatedField instances.
+// similar to std::back_inserter().
+template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
+RepeatedPtrFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
+ return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Special back insert iterator for RepeatedPtrField instances, just in
+// case someone wants to write generic template code that can access both
+// RepeatedFields and RepeatedPtrFields using a common name.
template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
RepeatedFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc
new file mode 100644
index 00000000..5fcfb007
--- /dev/null
+++ b/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -0,0 +1,193 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: tgs@google.com (Tom Szymanski)
+//
+// Test reflection methods for aggregate access to Repeated[Ptr]Fields.
+// This test proto2 methods on a proto2 layout.
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+using unittest::ForeignMessage;
+using unittest::TestAllTypes;
+using unittest::TestAllExtensions;
+
+namespace {
+
+static int Func(int i, int j) {
+ return i * j;
+}
+
+static string StrFunc(int i, int j) {
+ string str;
+ SStringPrintf(&str, "%d", Func(i, 4));
+ return str;
+}
+
+
+TEST(RepeatedFieldReflectionTest, RegularFields) {
+ TestAllTypes message;
+ const Reflection* refl = message.GetReflection();
+ const Descriptor* desc = message.GetDescriptor();
+
+ for (int i = 0; i < 10; ++i) {
+ message.add_repeated_int32(Func(i, 1));
+ message.add_repeated_double(Func(i, 2));
+ message.add_repeated_string(StrFunc(i, 5));
+ message.add_repeated_foreign_message()->set_c(Func(i, 6));
+ }
+
+ // Get FieldDescriptors for all the fields of interest.
+ const FieldDescriptor* fd_repeated_int32 =
+ desc->FindFieldByName("repeated_int32");
+ const FieldDescriptor* fd_repeated_double =
+ desc->FindFieldByName("repeated_double");
+ const FieldDescriptor* fd_repeated_string =
+ desc->FindFieldByName("repeated_string");
+ const FieldDescriptor* fd_repeated_foreign_message =
+ desc->FindFieldByName("repeated_foreign_message");
+
+ // Get RepeatedField objects for all fields of interest.
+ const RepeatedField<int32>& rf_int32 =
+ refl->GetRepeatedField<int32>(message, fd_repeated_int32);
+ const RepeatedField<double>& rf_double =
+ refl->GetRepeatedField<double>(message, fd_repeated_double);
+
+ // Get mutable RepeatedField objects for all fields of interest.
+ RepeatedField<int32>* mrf_int32 =
+ refl->MutableRepeatedField<int32>(&message, fd_repeated_int32);
+ RepeatedField<double>* mrf_double =
+ refl->MutableRepeatedField<double>(&message, fd_repeated_double);
+
+ // Get RepeatedPtrField objects for all fields of interest.
+ const RepeatedPtrField<string>& rpf_string =
+ refl->GetRepeatedPtrField<string>(message, fd_repeated_string);
+ const RepeatedPtrField<ForeignMessage>& rpf_foreign_message =
+ refl->GetRepeatedPtrField<ForeignMessage>(
+ message, fd_repeated_foreign_message);
+ const RepeatedPtrField<Message>& rpf_message =
+ refl->GetRepeatedPtrField<Message>(
+ message, fd_repeated_foreign_message);
+
+ // Get mutable RepeatedPtrField objects for all fields of interest.
+ RepeatedPtrField<string>* mrpf_string =
+ refl->MutableRepeatedPtrField<string>(&message, fd_repeated_string);
+ RepeatedPtrField<ForeignMessage>* mrpf_foreign_message =
+ refl->MutableRepeatedPtrField<ForeignMessage>(
+ &message, fd_repeated_foreign_message);
+ RepeatedPtrField<Message>* mrpf_message =
+ refl->MutableRepeatedPtrField<Message>(
+ &message, fd_repeated_foreign_message);
+
+ // Make sure we can do get and sets through the Repeated[Ptr]Field objects.
+ for (int i = 0; i < 10; ++i) {
+ // Check gets through const objects.
+ EXPECT_EQ(rf_int32.Get(i), Func(i, 1));
+ EXPECT_EQ(rf_double.Get(i), Func(i, 2));
+ EXPECT_EQ(rpf_string.Get(i), StrFunc(i, 5));
+ EXPECT_EQ(rpf_foreign_message.Get(i).c(), Func(i, 6));
+ EXPECT_EQ(down_cast<const ForeignMessage&>(rpf_message.Get(i)).c(),
+ Func(i, 6));
+
+ // Check gets through mutable objects.
+ EXPECT_EQ(mrf_int32->Get(i), Func(i, 1));
+ EXPECT_EQ(mrf_double->Get(i), Func(i, 2));
+ EXPECT_EQ(mrpf_string->Get(i), StrFunc(i, 5));
+ EXPECT_EQ(mrpf_foreign_message->Get(i).c(), Func(i, 6));
+ EXPECT_EQ(down_cast<const ForeignMessage&>(mrpf_message->Get(i)).c(),
+ Func(i, 6));
+
+ // Check sets through mutable objects.
+ mrf_int32->Set(i, Func(i, -1));
+ mrf_double->Set(i, Func(i, -2));
+ mrpf_string->Mutable(i)->assign(StrFunc(i, -5));
+ mrpf_foreign_message->Mutable(i)->set_c(Func(i, -6));
+ EXPECT_EQ(message.repeated_int32(i), Func(i, -1));
+ EXPECT_EQ(message.repeated_double(i), Func(i, -2));
+ EXPECT_EQ(message.repeated_string(i), StrFunc(i, -5));
+ EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, -6));
+ down_cast<ForeignMessage*>(mrpf_message->Mutable(i))->set_c(Func(i, 7));
+ EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
+ }
+
+ // Make sure types are checked correctly at runtime.
+ const FieldDescriptor* fd_optional_int32 =
+ desc->FindFieldByName("optional_int32");
+ EXPECT_DEATH(refl->GetRepeatedField<int32>(
+ message, fd_optional_int32), "requires a repeated field");
+ EXPECT_DEATH(refl->GetRepeatedField<double>(
+ message, fd_repeated_int32), "not the right type");
+ EXPECT_DEATH(refl->GetRepeatedPtrField<TestAllTypes>(
+ message, fd_repeated_foreign_message), "wrong submessage type");
+}
+
+
+
+
+TEST(RepeatedFieldReflectionTest, ExtensionFields) {
+ TestAllExtensions extended_message;
+ const Reflection* refl = extended_message.GetReflection();
+ const Descriptor* desc = extended_message.GetDescriptor();
+
+ for (int i = 0; i < 10; ++i) {
+ extended_message.AddExtension(
+ unittest::repeated_int64_extension, Func(i, 1));
+ }
+
+ const FieldDescriptor* fd_repeated_int64_extension =
+ desc->file()->FindExtensionByName("repeated_int64_extension");
+ GOOGLE_CHECK(fd_repeated_int64_extension != NULL);
+
+ const RepeatedField<int64>& rf_int64_extension =
+ refl->GetRepeatedField<int64>(extended_message,
+ fd_repeated_int64_extension);
+
+ RepeatedField<int64>* mrf_int64_extension =
+ refl->MutableRepeatedField<int64>(&extended_message,
+ fd_repeated_int64_extension);
+
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
+ mrf_int64_extension->Set(i, Func(i, -1));
+ EXPECT_EQ(Func(i, -1),
+ extended_message.GetExtension(unittest::repeated_int64_extension, i));
+ }
+}
+
+} // namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index e7e1e99b..99d5842d 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -36,6 +36,7 @@
// other proto2 unittests.
#include <algorithm>
+#include <limits>
#include <list>
#include <vector>
@@ -46,7 +47,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
using protobuf_unittest::TestAllTypes;
@@ -54,8 +55,7 @@ using protobuf_unittest::TestAllTypes;
namespace protobuf {
namespace {
-// Test operations on a RepeatedField which is small enough that it does
-// not allocate a separate array for storage.
+// Test operations on a small RepeatedField.
TEST(RepeatedField, Small) {
RepeatedField<int> field;
@@ -77,7 +77,6 @@ TEST(RepeatedField, Small) {
EXPECT_EQ(field.size(), 2);
EXPECT_EQ(field.Get(0), 5);
EXPECT_EQ(field.Get(1), 23);
- EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
field.RemoveLast();
@@ -87,9 +86,11 @@ TEST(RepeatedField, Small) {
field.Clear();
EXPECT_EQ(field.size(), 0);
- EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
+ int expected_usage = 4 * sizeof(int);
+ EXPECT_EQ(field.SpaceUsedExcludingSelf(), expected_usage);
}
+
// Test operations on a RepeatedField which is large enough to allocate a
// separate array.
TEST(RepeatedField, Large) {
@@ -213,10 +214,8 @@ TEST(RepeatedField, ReserveLessThanExisting) {
TEST(RepeatedField, MergeFrom) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -224,7 +223,6 @@ TEST(RepeatedField, MergeFrom) {
destination.MergeFrom(source);
ASSERT_EQ(5, destination.size());
-
EXPECT_EQ(1, destination.Get(0));
EXPECT_EQ(2, destination.Get(1));
EXPECT_EQ(3, destination.Get(2));
@@ -234,10 +232,8 @@ TEST(RepeatedField, MergeFrom) {
TEST(RepeatedField, CopyFrom) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -245,7 +241,6 @@ TEST(RepeatedField, CopyFrom) {
destination.CopyFrom(source);
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ(4, destination.Get(0));
EXPECT_EQ(5, destination.Get(1));
}
@@ -262,12 +257,26 @@ TEST(RepeatedField, CopyConstruct) {
EXPECT_EQ(2, destination.Get(1));
}
+TEST(RepeatedField, IteratorConstruct) {
+ vector<int> values;
+ values.push_back(1);
+ values.push_back(2);
+
+ RepeatedField<int> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0], field.Get(0));
+ EXPECT_EQ(values[1], field.Get(1));
+
+ RepeatedField<int> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0], other.Get(0));
+ EXPECT_EQ(values[1], other.Get(1));
+}
+
TEST(RepeatedField, CopyAssign) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -275,11 +284,24 @@ TEST(RepeatedField, CopyAssign) {
destination = source;
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ(4, destination.Get(0));
EXPECT_EQ(5, destination.Get(1));
}
+TEST(RepeatedField, SelfAssign) {
+ // Verify that assignment to self does not destroy data.
+ RepeatedField<int> source, *p;
+ p = &source;
+ source.Add(7);
+ source.Add(8);
+
+ *p = source;
+
+ ASSERT_EQ(2, source.size());
+ EXPECT_EQ(7, source.Get(0));
+ EXPECT_EQ(8, source.Get(1));
+}
+
TEST(RepeatedField, MutableDataIsMutable) {
RepeatedField<int> field;
field.Add(1);
@@ -315,6 +337,41 @@ TEST(RepeatedField, Truncate) {
}
+TEST(RepeatedField, ExtractSubrange) {
+ // Exhaustively test every subrange in arrays of all sizes from 0 through 9.
+ for (int sz = 0; sz < 10; ++sz) {
+ for (int num = 0; num <= sz; ++num) {
+ for (int start = 0; start < sz - num; ++start) {
+ // Create RepeatedField with sz elements having values 0 through sz-1.
+ RepeatedField<int32> field;
+ for (int i = 0; i < sz; ++i)
+ field.Add(i);
+ EXPECT_EQ(field.size(), sz);
+
+ // Create a catcher array and call ExtractSubrange.
+ int32 catcher[10];
+ for (int i = 0; i < 10; ++i)
+ catcher[i] = -1;
+ field.ExtractSubrange(start, num, catcher);
+
+ // Does the resulting array have the right size?
+ EXPECT_EQ(field.size(), sz - num);
+
+ // Were the removed elements extracted into the catcher array?
+ for (int i = 0; i < num; ++i)
+ EXPECT_EQ(catcher[i], start + i);
+ EXPECT_EQ(catcher[num], -1);
+
+ // Does the resulting array contain the right values?
+ for (int i = 0; i < start; ++i)
+ EXPECT_EQ(field.Get(i), i);
+ for (int i = start; i < field.size(); ++i)
+ EXPECT_EQ(field.Get(i), i + num);
+ }
+ }
+ }
+}
+
// ===================================================================
// RepeatedPtrField tests. These pretty much just mirror the RepeatedField
// tests above.
@@ -351,6 +408,7 @@ TEST(RepeatedPtrField, Small) {
EXPECT_EQ(field.size(), 0);
}
+
TEST(RepeatedPtrField, Large) {
RepeatedPtrField<string> field;
@@ -565,10 +623,8 @@ TEST(RepeatedPtrField, AddAlocated) {
TEST(RepeatedPtrField, MergeFrom) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -576,7 +632,6 @@ TEST(RepeatedPtrField, MergeFrom) {
destination.MergeFrom(source);
ASSERT_EQ(5, destination.size());
-
EXPECT_EQ("1", destination.Get(0));
EXPECT_EQ("2", destination.Get(1));
EXPECT_EQ("3", destination.Get(2));
@@ -586,10 +641,8 @@ TEST(RepeatedPtrField, MergeFrom) {
TEST(RepeatedPtrField, CopyFrom) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -597,14 +650,12 @@ TEST(RepeatedPtrField, CopyFrom) {
destination.CopyFrom(source);
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ("4", destination.Get(0));
EXPECT_EQ("5", destination.Get(1));
}
TEST(RepeatedPtrField, CopyConstruct) {
RepeatedPtrField<string> source;
-
source.Add()->assign("1");
source.Add()->assign("2");
@@ -615,12 +666,45 @@ TEST(RepeatedPtrField, CopyConstruct) {
EXPECT_EQ("2", destination.Get(1));
}
+TEST(RepeatedPtrField, IteratorConstruct_String) {
+ vector<string> values;
+ values.push_back("1");
+ values.push_back("2");
+
+ RepeatedPtrField<string> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0], field.Get(0));
+ EXPECT_EQ(values[1], field.Get(1));
+
+ RepeatedPtrField<string> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0], other.Get(0));
+ EXPECT_EQ(values[1], other.Get(1));
+}
+
+TEST(RepeatedPtrField, IteratorConstruct_Proto) {
+ typedef TestAllTypes::NestedMessage Nested;
+ vector<Nested> values;
+ values.push_back(Nested());
+ values.back().set_bb(1);
+ values.push_back(Nested());
+ values.back().set_bb(2);
+
+ RepeatedPtrField<Nested> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0].bb(), field.Get(0).bb());
+ EXPECT_EQ(values[1].bb(), field.Get(1).bb());
+
+ RepeatedPtrField<Nested> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0].bb(), other.Get(0).bb());
+ EXPECT_EQ(values[1].bb(), other.Get(1).bb());
+}
+
TEST(RepeatedPtrField, CopyAssign) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -628,11 +712,24 @@ TEST(RepeatedPtrField, CopyAssign) {
destination = source;
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ("4", destination.Get(0));
EXPECT_EQ("5", destination.Get(1));
}
+TEST(RepeatedPtrField, SelfAssign) {
+ // Verify that assignment to self does not destroy data.
+ RepeatedPtrField<string> source, *p;
+ p = &source;
+ source.Add()->assign("7");
+ source.Add()->assign("8");
+
+ *p = source;
+
+ ASSERT_EQ(2, source.size());
+ EXPECT_EQ("7", source.Get(0));
+ EXPECT_EQ("8", source.Get(1));
+}
+
TEST(RepeatedPtrField, MutableDataIsMutable) {
RepeatedPtrField<string> field;
*field.Add() = "1";
@@ -644,6 +741,77 @@ TEST(RepeatedPtrField, MutableDataIsMutable) {
EXPECT_EQ("2", field.Get(0));
}
+TEST(RepeatedPtrField, ExtractSubrange) {
+ // Exhaustively test every subrange in arrays of all sizes from 0 through 9
+ // with 0 through 3 cleared elements at the end.
+ for (int sz = 0; sz < 10; ++sz) {
+ for (int num = 0; num <= sz; ++num) {
+ for (int start = 0; start < sz - num; ++start) {
+ for (int extra = 0; extra < 4; ++extra) {
+ vector<string*> subject;
+
+ // Create an array with "sz" elements and "extra" cleared elements.
+ RepeatedPtrField<string> field;
+ for (int i = 0; i < sz + extra; ++i) {
+ subject.push_back(new string());
+ field.AddAllocated(subject[i]);
+ }
+ EXPECT_EQ(field.size(), sz + extra);
+ for (int i = 0; i < extra; ++i)
+ field.RemoveLast();
+ EXPECT_EQ(field.size(), sz);
+ EXPECT_EQ(field.ClearedCount(), extra);
+
+ // Create a catcher array and call ExtractSubrange.
+ string* catcher[10];
+ for (int i = 0; i < 10; ++i)
+ catcher[i] = NULL;
+ field.ExtractSubrange(start, num, catcher);
+
+ // Does the resulting array have the right size?
+ EXPECT_EQ(field.size(), sz - num);
+
+ // Were the removed elements extracted into the catcher array?
+ for (int i = 0; i < num; ++i)
+ EXPECT_EQ(catcher[i], subject[start + i]);
+ EXPECT_EQ(NULL, catcher[num]);
+
+ // Does the resulting array contain the right values?
+ for (int i = 0; i < start; ++i)
+ EXPECT_EQ(field.Mutable(i), subject[i]);
+ for (int i = start; i < field.size(); ++i)
+ EXPECT_EQ(field.Mutable(i), subject[i + num]);
+
+ // Reinstate the cleared elements.
+ EXPECT_EQ(field.ClearedCount(), extra);
+ for (int i = 0; i < extra; ++i)
+ field.Add();
+ EXPECT_EQ(field.ClearedCount(), 0);
+ EXPECT_EQ(field.size(), sz - num + extra);
+
+ // Make sure the extra elements are all there (in some order).
+ for (int i = sz; i < sz + extra; ++i) {
+ int count = 0;
+ for (int j = sz; j < sz + extra; ++j) {
+ if (field.Mutable(j - num) == subject[i])
+ count += 1;
+ }
+ EXPECT_EQ(count, 1);
+ }
+
+ // Release the caught elements.
+ for (int i = 0; i < num; ++i)
+ delete catcher[i];
+ }
+ }
+ }
+ }
+}
+
+TEST(RepeatedPtrField, DeleteSubrange) {
+ // DeleteSubrange is a trivial extension of ExtendSubrange.
+}
+
// ===================================================================
// Iterator tests stolen from net/proto/proto-array_unittest.
@@ -738,6 +906,30 @@ TEST_F(RepeatedPtrFieldIteratorTest, ConstIteration) {
EXPECT_EQ("baz", *(--const_proto_array.end()));
}
+TEST_F(RepeatedPtrFieldIteratorTest, MutableReverseIteration) {
+ RepeatedPtrField<string>::reverse_iterator iter = proto_array_.rbegin();
+ EXPECT_EQ("baz", *iter);
+ ++iter;
+ EXPECT_EQ("bar", *(iter++));
+ EXPECT_EQ("foo", *iter);
+ ++iter;
+ EXPECT_TRUE(proto_array_.rend() == iter);
+ EXPECT_EQ("foo", *(--proto_array_.rend()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, ConstReverseIteration) {
+ const RepeatedPtrField<string>& const_proto_array = proto_array_;
+ RepeatedPtrField<string>::const_reverse_iterator iter
+ = const_proto_array.rbegin();
+ EXPECT_EQ("baz", *iter);
+ ++iter;
+ EXPECT_EQ("bar", *(iter++));
+ EXPECT_EQ("foo", *iter);
+ ++iter;
+ EXPECT_TRUE(const_proto_array.rend() == iter);
+ EXPECT_EQ("foo", *(--const_proto_array.rend()));
+}
+
TEST_F(RepeatedPtrFieldIteratorTest, RandomAccess) {
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
RepeatedPtrField<string>::iterator iter2 = iter;
@@ -805,9 +997,11 @@ class RepeatedPtrFieldPtrsIteratorTest : public testing::Test {
proto_array_.Add()->assign("foo");
proto_array_.Add()->assign("bar");
proto_array_.Add()->assign("baz");
+ const_proto_array_ = &proto_array_;
}
RepeatedPtrField<string> proto_array_;
+ const RepeatedPtrField<string>* const_proto_array_;
};
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
@@ -815,6 +1009,11 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
proto_array_.pointer_begin();
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertibleConstPtr) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+}
+
TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
@@ -827,6 +1026,18 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
EXPECT_EQ("baz", **(--proto_array_.pointer_end()));
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutableConstPtrIteration) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ EXPECT_EQ("foo", **iter);
+ ++iter;
+ EXPECT_EQ("bar", **(iter++));
+ EXPECT_EQ("baz", **iter);
+ ++iter;
+ EXPECT_TRUE(const_proto_array_->pointer_end() == iter);
+ EXPECT_EQ("baz", **(--const_proto_array_->pointer_end()));
+}
+
TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
@@ -840,6 +1051,19 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomConstPtrAccess) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ RepeatedPtrField<string>::const_pointer_iterator iter2 = iter;
+ ++iter2;
+ ++iter2;
+ EXPECT_TRUE(iter + 2 == iter2);
+ EXPECT_TRUE(iter == iter2 - 2);
+ EXPECT_EQ("baz", *iter[2]);
+ EXPECT_EQ("baz", **(iter + 2));
+ EXPECT_EQ(3, const_proto_array_->end() - const_proto_array_->begin());
+}
+
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
@@ -854,6 +1078,20 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
EXPECT_TRUE(iter >= iter);
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparableConstPtr) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ RepeatedPtrField<string>::const_pointer_iterator iter2 = iter + 1;
+ EXPECT_TRUE(iter == iter);
+ EXPECT_TRUE(iter != iter2);
+ EXPECT_TRUE(iter < iter2);
+ EXPECT_TRUE(iter <= iter2);
+ EXPECT_TRUE(iter <= iter);
+ EXPECT_TRUE(iter2 > iter);
+ EXPECT_TRUE(iter2 >= iter);
+ EXPECT_TRUE(iter >= iter);
+}
+
// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs.
// Dereferencing an uninitialized iterator crashes the process.
TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
@@ -865,6 +1103,14 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
EXPECT_TRUE(iter != proto_array_.pointer_end());
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedConstPtrIterator) {
+ RepeatedPtrField<string>::const_pointer_iterator iter;
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin());
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 1);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 2);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 3);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_end());
+}
// This comparison functor is required by the tests for RepeatedPtrOverPtrs.
// They operate on strings and need to compare strings as strings in
@@ -889,17 +1135,33 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) {
proto_array_.Add()->assign("x");
proto_array_.Add()->assign("y");
- RepeatedPtrField<string>::pointer_iterator iter =
- proto_array_.pointer_begin();
- string v = "f";
- RepeatedPtrField<string>::pointer_iterator it =
- lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
- &v, StringLessThan());
+ {
+ RepeatedPtrField<string>::pointer_iterator iter =
+ proto_array_.pointer_begin();
+ string v = "f";
+ RepeatedPtrField<string>::pointer_iterator it =
+ lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
+ &v, StringLessThan());
- GOOGLE_CHECK(*it != NULL);
+ GOOGLE_CHECK(*it != NULL);
- EXPECT_EQ(**it, "n");
- EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
+ EXPECT_EQ(**it, "n");
+ EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
+ }
+ {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ string v = "f";
+ RepeatedPtrField<string>::const_pointer_iterator it =
+ lower_bound(const_proto_array_->pointer_begin(),
+ const_proto_array_->pointer_end(),
+ &v, StringLessThan());
+
+ GOOGLE_CHECK(*it != NULL);
+
+ EXPECT_EQ(**it, "n");
+ EXPECT_TRUE(it == const_proto_array_->pointer_begin() + 3);
+ }
}
TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) {
@@ -1025,13 +1287,24 @@ TEST_F(RepeatedFieldInsertionIteratorsTest, Halves) {
TEST_F(RepeatedFieldInsertionIteratorsTest, Words) {
ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
- EXPECT_EQ(words.at(0), protobuffer.repeated_string(0));
- EXPECT_EQ(words.at(1), protobuffer.repeated_string(1));
- EXPECT_EQ(words.at(2), protobuffer.repeated_string(2));
- EXPECT_EQ(words.at(3), protobuffer.repeated_string(3));
- EXPECT_EQ(words.at(4), protobuffer.repeated_string(4));
- EXPECT_EQ(words.at(5), protobuffer.repeated_string(5));
- EXPECT_EQ(words.at(6), protobuffer.repeated_string(6));
+ for (int i = 0; i < words.size(); ++i)
+ EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Words2) {
+ words.clear();
+ words.push_back("sing");
+ words.push_back("a");
+ words.push_back("song");
+ words.push_back("of");
+ words.push_back("six");
+ words.push_back("pence");
+ protobuffer.mutable_repeated_string()->Clear();
+ std::copy(words.begin(), words.end(), RepeatedPtrFieldBackInserter(
+ protobuffer.mutable_repeated_string()));
+ ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
+ for (int i = 0; i < words.size(); ++i)
+ EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
}
TEST_F(RepeatedFieldInsertionIteratorsTest, Nesteds) {
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index 7b15be44..16d78528 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -320,6 +320,24 @@ void Mutex::AssertHeld() {
#endif
// ===================================================================
+// emulates google3/util/endian/endian.h
+//
+// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
+// google/protobuf/io/coded_stream.h and therefore can not be used here.
+// Maybe move that macro definition here in the furture.
+uint32 ghtonl(uint32 x) {
+ union {
+ uint32 result;
+ uint8 result_array[4];
+ };
+ result_array[0] = static_cast<uint8>(x >> 24);
+ result_array[1] = static_cast<uint8>((x >> 16) & 0xFF);
+ result_array[2] = static_cast<uint8>((x >> 8) & 0xFF);
+ result_array[3] = static_cast<uint8>(x & 0xFF);
+ return result;
+}
+
+// ===================================================================
// Shutdown support.
namespace internal {
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 7f5fd4d2..07ae5307 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -341,6 +341,12 @@ inline To down_cast(From* f) { // so we only accept pointers
return static_cast<To>(f);
}
+// Simplified down_cast for reference type.
+template<typename To, typename From>
+inline To down_cast(From& f) {
+ return static_cast<To>(f);
+}
+
} // namespace internal
// We made these internal so that they would show up as such in the docs,
@@ -686,6 +692,7 @@ class LIBPROTOBUF_EXPORT LogFinisher {
#undef GOOGLE_CHECK_LE
#undef GOOGLE_CHECK_GT
#undef GOOGLE_CHECK_GE
+#undef GOOGLE_CHECK_NOTNULL
#undef GOOGLE_DLOG
#undef GOOGLE_DCHECK
@@ -712,6 +719,18 @@ class LIBPROTOBUF_EXPORT LogFinisher {
#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B))
#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
+namespace internal {
+template<typename T>
+T* CheckNotNull(const char *file, int line, const char *name, T* val) {
+ if (val == NULL) {
+ GOOGLE_LOG(FATAL) << name;
+ }
+ return val;
+}
+} // namespace internal
+#define GOOGLE_CHECK_NOTNULL(A) \
+ internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A))
+
#ifdef NDEBUG
#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false)
@@ -1136,20 +1155,10 @@ using internal::WriterMutexLock;
using internal::MutexLockMaybe;
// ===================================================================
-// from google3/base/type_traits.h
+// from google3/util/utf8/public/unilib.h
namespace internal {
-// Specified by TR1 [4.7.4] Pointer modifications.
-template<typename T> struct remove_pointer { typedef T type; };
-template<typename T> struct remove_pointer<T*> { typedef T type; };
-template<typename T> struct remove_pointer<T* const> { typedef T type; };
-template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
-template<typename T> struct remove_pointer<T* const volatile> {
- typedef T type; };
-
-// ===================================================================
-
// Checks if the buffer contains structurally-valid UTF-8. Implemented in
// structurally_valid.cc.
LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
@@ -1157,6 +1166,10 @@ LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
} // namespace internal
// ===================================================================
+// from google3/util/endian/endian.h
+LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
+
+// ===================================================================
// Shutdown support.
// Shut down the entire protocol buffers library, deleting all static-duration
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index 822d6050..f7d10712 100644
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -90,12 +90,16 @@ template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = int >
class hash_map : public std::map<Key, Data, HashFcn> {
+ public:
+ hash_map(int = 0) {}
};
template <typename Key,
typename HashFcn = hash<Key>,
typename EqualKey = int >
class hash_set : public std::set<Key, HashFcn> {
+ public:
+ hash_set(int = 0) {}
};
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
@@ -123,6 +127,8 @@ template <typename Key, typename Data,
typename EqualKey = int >
class hash_map : public HASH_NAMESPACE::hash_map<
Key, Data, HashFcn> {
+ public:
+ hash_map(int = 0) {}
};
template <typename Key,
@@ -130,6 +136,8 @@ template <typename Key,
typename EqualKey = int >
class hash_set : public HASH_NAMESPACE::hash_set<
Key, HashFcn> {
+ public:
+ hash_set(int = 0) {}
};
#else
@@ -163,6 +171,8 @@ template <typename Key, typename Data,
typename EqualKey = std::equal_to<Key> >
class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
Key, Data, HashFcn, EqualKey> {
+ public:
+ hash_map(int = 0) {}
};
template <typename Key,
@@ -170,6 +180,8 @@ template <typename Key,
typename EqualKey = std::equal_to<Key> >
class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
Key, HashFcn, EqualKey> {
+ public:
+ hash_set(int = 0) {}
};
#endif
diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h
index f5c9d6b6..775848b9 100644
--- a/src/google/protobuf/stubs/map-util.h
+++ b/src/google/protobuf/stubs/map-util.h
@@ -68,6 +68,30 @@ FindOrNull(const Collection& collection,
return &it->second;
}
+// Perform a lookup in a map or hash_map, assuming that the key exists.
+// Crash if it does not.
+//
+// This is intended as a replacement for operator[] as an rvalue (for reading)
+// when the key is guaranteed to exist.
+//
+// operator[] is discouraged for several reasons:
+// * It has a side-effect of inserting missing keys
+// * It is not thread-safe (even when it is not inserting, it can still
+// choose to resize the underlying storage)
+// * It invalidates iterators (when it chooses to resize)
+// * It default constructs a value object even if it doesn't need to
+//
+// This version assumes the key is printable, and includes it in the fatal log
+// message.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDie(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+ return it->second;
+}
+
// Perform a lookup in a map or hash_map whose values are pointers.
// If the key is present a const pointer to the associated value is returned,
// otherwise a NULL pointer is returned.
diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h
new file mode 100644
index 00000000..9021dada
--- /dev/null
+++ b/src/google/protobuf/stubs/stl_util.h
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/util/gtl/stl_util.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// STLDeleteContainerPointers()
+// For a range within a container of pointers, calls delete
+// (non-array version) on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+// Inside Google, this function implements a horrible, disgusting hack in which
+// we reach into the string's private implementation and resize it without
+// initializing the new bytes. In some cases doing this can significantly
+// improve performance. However, since it's totally non-portable it has no
+// place in open source code. Feel free to fill this function in with your
+// own disgusting hack if you want the perf boost.
+inline void STLStringResizeUninitialized(string* s, size_t new_size) {
+ s->resize(new_size);
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(string* str) {
+ // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+ return str->empty() ? NULL : &*str->begin();
+}
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container. This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// ElementDeleter (defined below), which ensures that your container's elements
+// are deleted when the ElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T *container) {
+ if (!container) return;
+ STLDeleteContainerPointers(container->begin(), container->end());
+ container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container. Does nothing
+// in the case it's given a NULL pointer.
+
+template <class T>
+void STLDeleteValues(T *v) {
+ if (!v) return;
+ for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
+ delete i->second;
+ }
+ v->clear();
+}
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc
new file mode 100644
index 00000000..d66a497a
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.cc
@@ -0,0 +1,170 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <errno.h>
+#include <stdarg.h> // For va_list and related operations
+#include <stdio.h> // MSVC requires this for _vsnprintf
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+enum { IS_COMPILER_MSVC = 1 };
+#else
+enum { IS_COMPILER_MSVC = 0 };
+#endif
+
+void StringAppendV(string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ static const int kSpaceLength = 1024;
+ char space[kSpaceLength];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result < kSpaceLength) {
+ if (result >= 0) {
+ // Normal case -- everything fit.
+ dst->append(space, result);
+ return;
+ }
+
+ if (IS_COMPILER_MSVC) {
+ // Error or MSVC running out of space. MSVC 8.0 and higher
+ // can be asked about space needed with the special idiom below:
+ va_copy(backup_ap, ap);
+ result = vsnprintf(NULL, 0, format, backup_ap);
+ va_end(backup_ap);
+ }
+
+ if (result < 0) {
+ // Just an error.
+ return;
+ }
+ }
+
+ // Increase the buffer size to the size requested by vsnprintf,
+ // plus one for the closing \0.
+ int length = result+1;
+ char* buf = new char[length];
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, length, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && result < length) {
+ // It fit
+ dst->append(buf, result);
+ }
+ delete[] buf;
+}
+
+
+string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+const string& SStringPrintf(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+void StringAppendF(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+// Max arguments supported by StringPrintVector
+const int kStringPrintfVectorMaxArgs = 32;
+
+// An empty block of zero for filler arguments. This is const so that if
+// printf tries to write to it (via %n) then the program gets a SIGSEGV
+// and we can fix the problem or protect against an attack.
+static const char string_printf_empty_block[256] = { '\0' };
+
+string StringPrintfVector(const char* format, const vector<string>& v) {
+ GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
+ << "StringPrintfVector currently only supports up to "
+ << kStringPrintfVectorMaxArgs << " arguments. "
+ << "Feel free to add support for more if you need it.";
+
+ // Add filler arguments so that bogus format+args have a harder time
+ // crashing the program, corrupting the program (%n),
+ // or displaying random chunks of memory to users.
+
+ const char* cstr[kStringPrintfVectorMaxArgs];
+ for (int i = 0; i < v.size(); ++i) {
+ cstr[i] = v[i].c_str();
+ }
+ for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
+ cstr[i] = &string_printf_empty_block[0];
+ }
+
+ // I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
+ // or any way to build a va_list by hand, or any API for printf
+ // that accepts an array of arguments. The best I can do is stick
+ // this COMPILE_ASSERT right next to the actual statement.
+
+ GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch);
+ return StringPrintf(format,
+ cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
+ cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
+ cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
+ cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
+ cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
+ cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
+ cstr[30], cstr[31]);
+}
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/stringprintf.h b/src/google/protobuf/stubs/stringprintf.h
new file mode 100644
index 00000000..573f30f3
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.h
+//
+// Printf variants that place their output in a C++ string.
+//
+// Usage:
+// string result = StringPrintf("%d %s\n", 10, "hello");
+// SStringPrintf(&result, "%d %s\n", 10, "hello");
+// StringAppendF(&result, "%d %s\n", 20, "there");
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+
+#include <stdarg.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// Return a C++ string
+extern string StringPrintf(const char* format, ...);
+
+// Store result into a supplied string and return it
+extern const string& SStringPrintf(string* dst, const char* format, ...);
+
+// Append result to a supplied string
+extern void StringAppendF(string* dst, const char* format, ...);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string. All other routines are just convenience wrappers around it.
+extern void StringAppendV(string* dst, const char* format, va_list ap);
+
+// The max arguments supported by StringPrintfVector
+extern const int kStringPrintfVectorMaxArgs;
+
+// You can use this version when all your arguments are strings, but
+// you don't know how many arguments you'll have at compile time.
+// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
+extern string StringPrintfVector(const char* format, const vector<string>& v);
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
diff --git a/src/google/protobuf/stubs/stringprintf_unittest.cc b/src/google/protobuf/stubs/stringprintf_unittest.cc
new file mode 100644
index 00000000..5cf7fffc
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf_unittest.cc
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf_unittest.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <cerrno>
+#include <string>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(StringPrintfTest, Empty) {
+#if 0
+ // gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this:
+ // warning: zero-length printf format string.
+ // so we do not allow them in google3.
+ EXPECT_EQ("", StringPrintf(""));
+#endif
+ EXPECT_EQ("", StringPrintf("%s", string().c_str()));
+ EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, Misc) {
+// MSVC does not support $ format specifier.
+#if !defined(COMPILER_MSVC)
+ EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123));
+#endif // !COMPILER_MSVC
+}
+
+TEST(StringAppendFTest, Empty) {
+ string value("Hello");
+ const char* empty = "";
+ StringAppendF(&value, "%s", empty);
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, EmptyString) {
+ string value("Hello");
+ StringAppendF(&value, "%s", "");
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, String) {
+ string value("Hello");
+ StringAppendF(&value, " %s", "World");
+ EXPECT_EQ("Hello World", value);
+}
+
+TEST(StringAppendFTest, Int) {
+ string value("Hello");
+ StringAppendF(&value, " %d", 123);
+ EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringPrintfTest, Multibyte) {
+ // If we are in multibyte mode and feed invalid multibyte sequence,
+ // StringPrintf should return an empty string instead of running
+ // out of memory while trying to determine destination buffer size.
+ // see b/4194543.
+
+ char* old_locale = setlocale(LC_CTYPE, NULL);
+ // Push locale with multibyte mode
+ setlocale(LC_CTYPE, "en_US.utf8");
+
+ const char kInvalidCodePoint[] = "\375\067s";
+ string value = StringPrintf("%.*s", 3, kInvalidCodePoint);
+
+ // In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
+ // returns error given an invalid codepoint. Other versions
+ // (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
+ // We test that the output is one of the above.
+ EXPECT_TRUE(value.empty() || value == kInvalidCodePoint);
+
+ // Repeat with longer string, to make sure that the dynamically
+ // allocated path in StringAppendV is handled correctly.
+ int n = 2048;
+ char* buf = new char[n+1];
+ memset(buf, ' ', n-3);
+ memcpy(buf + n - 3, kInvalidCodePoint, 4);
+ value = StringPrintf("%.*s", n, buf);
+ // See GRTEv2 vs. GRTEv3 comment above.
+ EXPECT_TRUE(value.empty() || value == buf);
+ delete[] buf;
+
+ setlocale(LC_CTYPE, old_locale);
+}
+
+TEST(StringPrintfTest, NoMultibyte) {
+ // No multibyte handling, but the string contains funny chars.
+ char* old_locale = setlocale(LC_CTYPE, NULL);
+ setlocale(LC_CTYPE, "POSIX");
+ string value = StringPrintf("%.*s", 3, "\375\067s");
+ setlocale(LC_CTYPE, old_locale);
+ EXPECT_EQ("\375\067s", value);
+}
+
+TEST(StringPrintfTest, DontOverwriteErrno) {
+ // Check that errno isn't overwritten unless we're printing
+ // something significantly larger than what people are normally
+ // printing in their badly written PLOG() statements.
+ errno = ECHILD;
+ string value = StringPrintf("Hello, %s!", "World");
+ EXPECT_EQ(ECHILD, errno);
+}
+
+TEST(StringPrintfTest, LargeBuf) {
+ // Check that the large buffer is handled correctly.
+ int n = 2048;
+ char* buf = new char[n+1];
+ memset(buf, ' ', n);
+ buf[n] = 0;
+ string value = StringPrintf("%s", buf);
+ EXPECT_EQ(buf, value);
+ delete[] buf;
+}
+
+} // anonymous namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index ee07ce75..917b3e9f 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -189,6 +189,44 @@ void SplitStringUsing(const string& full,
SplitStringToIteratorUsing(full, delim, it);
}
+// Split a string using a character delimiter. Append the components
+// to 'result'. If there are consecutive delimiters, this function
+// will return corresponding empty strings. The string is split into
+// at most the specified number of pieces greedily. This means that the
+// last piece may possibly be split further. To split into as many pieces
+// as possible, specify 0 as the number of pieces.
+//
+// If "full" is the empty string, yields an empty string as the only value.
+//
+// If "pieces" is negative for some reason, it returns the whole string
+// ----------------------------------------------------------------------
+template <typename StringType, typename ITR>
+static inline
+void SplitStringToIteratorAllowEmpty(const StringType& full,
+ const char* delim,
+ int pieces,
+ ITR& result) {
+ string::size_type begin_index, end_index;
+ begin_index = 0;
+
+ for (int i = 0; (i < pieces-1) || (pieces == 0); i++) {
+ end_index = full.find_first_of(delim, begin_index);
+ if (end_index == string::npos) {
+ *result++ = full.substr(begin_index);
+ return;
+ }
+ *result++ = full.substr(begin_index, (end_index - begin_index));
+ begin_index = end_index + 1;
+ }
+ *result++ = full.substr(begin_index);
+}
+
+void SplitStringAllowEmpty(const string& full, const char* delim,
+ vector<string>* result) {
+ back_insert_iterator<vector<string> > it(*result);
+ SplitStringToIteratorAllowEmpty(full, delim, 0, it);
+}
+
// ----------------------------------------------------------------------
// JoinStrings()
// This merges a vector of string components with delim inserted
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index 4a79c224..a401c63a 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -168,6 +168,18 @@ LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub,
LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim,
vector<string>* res);
+// Split a string using one or more byte delimiters, presented
+// as a nul-terminated c string. Append the components to 'result'.
+// If there are consecutive delimiters, this function will return
+// corresponding empty strings. If you want to drop the empty
+// strings, try SplitStringUsing().
+//
+// If "full" is the empty string, yields an empty string as the only value.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void SplitStringAllowEmpty(const string& full,
+ const char* delim,
+ vector<string>* result);
+
// ----------------------------------------------------------------------
// JoinStrings()
// These methods concatenate a vector of strings into a C++ string, using
@@ -453,5 +465,3 @@ LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr);
} // namespace google
#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
-
-
diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc
index b542aaa4..259245b3 100644
--- a/src/google/protobuf/stubs/substitute.cc
+++ b/src/google/protobuf/stubs/substitute.cc
@@ -32,7 +32,7 @@
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/stubs/template_util.h b/src/google/protobuf/stubs/template_util.h
new file mode 100644
index 00000000..4f30ffa3
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util.h
@@ -0,0 +1,138 @@
+// Copyright 2005 Google Inc.
+// All rights reserved.
+//
+// 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: lar@google.com (Laramie Leavitt)
+//
+// Template metaprogramming utility functions.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems. Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+//
+// The names choosen here reflect those used in tr1 and the boost::mpl
+// library, there are similar operations used in the Loki library as
+// well. I prefer the boost names for 2 reasons:
+// 1. I think that portions of the Boost libraries are more likely to
+// be included in the c++ standard.
+// 2. It is not impossible that some of the boost libraries will be
+// included in our own build in the future.
+// Both of these outcomes means that we may be able to directly replace
+// some of these with boost equivalents.
+//
+#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+ char dummy[2];
+};
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+ typedef T type;
+};
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+ static const T value = v;
+ typedef T value_type;
+ typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+
+// Abbreviations: true_type and false_type are structs that represent boolean
+// true and false values. Also define the boost::mpl versions of those names,
+// true_ and false_.
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+typedef true_type true_;
+typedef false_type false_;
+
+// if_ is a templatized conditional statement.
+// if_<cond, A, B> is a compile time evaluation of cond.
+// if_<>::type contains A if cond is true, B otherwise.
+template<bool cond, typename A, typename B>
+struct if_{
+ typedef A type;
+};
+
+template<typename A, typename B>
+struct if_<false, A, B> {
+ typedef B type;
+};
+
+
+// type_equals_ is a template type comparator, similar to Loki IsSameType.
+// type_equals_<A, B>::value is true iff "A" is the same type as "B".
+//
+// New code should prefer base::is_same, defined in base/type_traits.h.
+// It is functionally identical, but is_same is the standard spelling.
+template<typename A, typename B>
+struct type_equals_ : public false_ {
+};
+
+template<typename A>
+struct type_equals_<A, A> : public true_ {
+};
+
+// and_ is a template && operator.
+// and_<A, B>::value evaluates "A::value && B::value".
+template<typename A, typename B>
+struct and_ : public integral_constant<bool, (A::value && B::value)> {
+};
+
+// or_ is a template || operator.
+// or_<A, B>::value evaluates "A::value || B::value".
+template<typename A, typename B>
+struct or_ : public integral_constant<bool, (A::value || B::value)> {
+};
+
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
diff --git a/src/google/protobuf/stubs/template_util_unittest.cc b/src/google/protobuf/stubs/template_util_unittest.cc
new file mode 100644
index 00000000..b1745e2b
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2005 Google Inc.
+// All rights reserved.
+//
+// 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: lar@google.com (Laramie Leavitt)
+//
+// These tests are really compile time tests.
+// If you try to step through this in a debugger
+// you will not see any evaluations, merely that
+// value is assigned true or false sequentially.
+
+#include <google/protobuf/stubs/template_util.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace GOOGLE_NAMESPACE = google::protobuf::internal;
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(TemplateUtilTest, TestSize) {
+ EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_));
+}
+
+TEST(TemplateUtilTest, TestIntegralConstants) {
+ // test the built-in types.
+ EXPECT_TRUE(true_type::value);
+ EXPECT_FALSE(false_type::value);
+
+ typedef integral_constant<int, 1> one_type;
+ EXPECT_EQ(1, one_type::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateIf) {
+ typedef if_<true, true_type, false_type>::type if_true;
+ EXPECT_TRUE(if_true::value);
+
+ typedef if_<false, true_type, false_type>::type if_false;
+ EXPECT_FALSE(if_false::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateTypeEquals) {
+ // Check that the TemplateTypeEquals works correctly.
+ bool value = false;
+
+ // Test the same type is true.
+ value = type_equals_<int, int>::value;
+ EXPECT_TRUE(value);
+
+ // Test different types are false.
+ value = type_equals_<float, int>::value;
+ EXPECT_FALSE(value);
+
+ // Test type aliasing.
+ typedef const int foo;
+ value = type_equals_<const foo, const int>::value;
+ EXPECT_TRUE(value);
+}
+
+TEST(TemplateUtilTest, TestTemplateAndOr) {
+ // Check that the TemplateTypeEquals works correctly.
+ bool value = false;
+
+ // Yes && Yes == true.
+ value = and_<true_, true_>::value;
+ EXPECT_TRUE(value);
+ // Yes && No == false.
+ value = and_<true_, false_>::value;
+ EXPECT_FALSE(value);
+ // No && Yes == false.
+ value = and_<false_, true_>::value;
+ EXPECT_FALSE(value);
+ // No && No == false.
+ value = and_<false_, false_>::value;
+ EXPECT_FALSE(value);
+
+ // Yes || Yes == true.
+ value = or_<true_, true_>::value;
+ EXPECT_TRUE(value);
+ // Yes || No == true.
+ value = or_<true_, false_>::value;
+ EXPECT_TRUE(value);
+ // No || Yes == true.
+ value = or_<false_, true_>::value;
+ EXPECT_TRUE(value);
+ // No || No == false.
+ value = or_<false_, false_>::value;
+ EXPECT_FALSE(value);
+}
+
+TEST(TemplateUtilTest, TestIdentity) {
+ EXPECT_TRUE(
+ (type_equals_<GOOGLE_NAMESPACE::identity_<int>::type, int>::value));
+ EXPECT_TRUE(
+ (type_equals_<GOOGLE_NAMESPACE::identity_<void>::type, void>::value));
+}
+
+} // anonymous namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h
new file mode 100644
index 00000000..997f35d4
--- /dev/null
+++ b/src/google/protobuf/stubs/type_traits.h
@@ -0,0 +1,346 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// 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: Matt Austern
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems. Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+// Define a small subset of tr1 type traits. The traits we define are:
+// is_integral
+// is_floating_point
+// is_pointer
+// is_enum
+// is_reference
+// is_pod
+// has_trivial_constructor
+// has_trivial_copy
+// has_trivial_assign
+// has_trivial_destructor
+// remove_const
+// remove_volatile
+// remove_cv
+// remove_reference
+// add_reference
+// remove_pointer
+// is_same
+// is_convertible
+// We can add more type traits as required.
+
+#ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_
+#define GOOGLE_PROTOBUF_TYPE_TRAITS_H_
+
+#include <utility> // For pair
+
+#include <google/protobuf/stubs/template_util.h> // For true_type and false_type
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <class T> struct is_integral;
+template <class T> struct is_floating_point;
+template <class T> struct is_pointer;
+// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+// is_enum uses is_convertible, which is not available on MSVC.
+template <class T> struct is_enum;
+#endif
+template <class T> struct is_reference;
+template <class T> struct is_pod;
+template <class T> struct has_trivial_constructor;
+template <class T> struct has_trivial_copy;
+template <class T> struct has_trivial_assign;
+template <class T> struct has_trivial_destructor;
+template <class T> struct remove_const;
+template <class T> struct remove_volatile;
+template <class T> struct remove_cv;
+template <class T> struct remove_reference;
+template <class T> struct add_reference;
+template <class T> struct remove_pointer;
+template <class T, class U> struct is_same;
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+template <class From, class To> struct is_convertible;
+#endif
+
+// is_integral is false except for the built-in integer types. A
+// cv-qualified type is integral if and only if the underlying type is.
+template <class T> struct is_integral : false_type { };
+template<> struct is_integral<bool> : true_type { };
+template<> struct is_integral<char> : true_type { };
+template<> struct is_integral<unsigned char> : true_type { };
+template<> struct is_integral<signed char> : true_type { };
+#if defined(_MSC_VER)
+// wchar_t is not by default a distinct type from unsigned short in
+// Microsoft C.
+// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
+template<> struct is_integral<__wchar_t> : true_type { };
+#else
+template<> struct is_integral<wchar_t> : true_type { };
+#endif
+template<> struct is_integral<short> : true_type { };
+template<> struct is_integral<unsigned short> : true_type { };
+template<> struct is_integral<int> : true_type { };
+template<> struct is_integral<unsigned int> : true_type { };
+template<> struct is_integral<long> : true_type { };
+template<> struct is_integral<unsigned long> : true_type { };
+#ifdef HAVE_LONG_LONG
+template<> struct is_integral<long long> : true_type { };
+template<> struct is_integral<unsigned long long> : true_type { };
+#endif
+template <class T> struct is_integral<const T> : is_integral<T> { };
+template <class T> struct is_integral<volatile T> : is_integral<T> { };
+template <class T> struct is_integral<const volatile T> : is_integral<T> { };
+
+// is_floating_point is false except for the built-in floating-point types.
+// A cv-qualified type is integral if and only if the underlying type is.
+template <class T> struct is_floating_point : false_type { };
+template<> struct is_floating_point<float> : true_type { };
+template<> struct is_floating_point<double> : true_type { };
+template<> struct is_floating_point<long double> : true_type { };
+template <class T> struct is_floating_point<const T>
+ : is_floating_point<T> { };
+template <class T> struct is_floating_point<volatile T>
+ : is_floating_point<T> { };
+template <class T> struct is_floating_point<const volatile T>
+ : is_floating_point<T> { };
+
+// is_pointer is false except for pointer types. A cv-qualified type (e.g.
+// "int* const", as opposed to "int const*") is cv-qualified if and only if
+// the underlying type is.
+template <class T> struct is_pointer : false_type { };
+template <class T> struct is_pointer<T*> : true_type { };
+template <class T> struct is_pointer<const T> : is_pointer<T> { };
+template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
+template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
+
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+
+namespace internal {
+
+template <class T> struct is_class_or_union {
+ template <class U> static small_ tester(void (U::*)());
+ template <class U> static big_ tester(...);
+ static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
+};
+
+// is_convertible chokes if the first argument is an array. That's why
+// we use add_reference here.
+template <bool NotUnum, class T> struct is_enum_impl
+ : is_convertible<typename add_reference<T>::type, int> { };
+
+template <class T> struct is_enum_impl<true, T> : false_type { };
+
+} // namespace internal
+
+// Specified by TR1 [4.5.1] primary type categories.
+
+// Implementation note:
+//
+// Each type is either void, integral, floating point, array, pointer,
+// reference, member object pointer, member function pointer, enum,
+// union or class. Out of these, only integral, floating point, reference,
+// class and enum types are potentially convertible to int. Therefore,
+// if a type is not a reference, integral, floating point or class and
+// is convertible to int, it's a enum. Adding cv-qualification to a type
+// does not change whether it's an enum.
+//
+// Is-convertible-to-int check is done only if all other checks pass,
+// because it can't be used with some types (e.g. void or classes with
+// inaccessible conversion operators).
+template <class T> struct is_enum
+ : internal::is_enum_impl<
+ is_same<T, void>::value ||
+ is_integral<T>::value ||
+ is_floating_point<T>::value ||
+ is_reference<T>::value ||
+ internal::is_class_or_union<T>::value,
+ T> { };
+
+template <class T> struct is_enum<const T> : is_enum<T> { };
+template <class T> struct is_enum<volatile T> : is_enum<T> { };
+template <class T> struct is_enum<const volatile T> : is_enum<T> { };
+
+#endif
+
+// is_reference is false except for reference types.
+template<typename T> struct is_reference : false_type {};
+template<typename T> struct is_reference<T&> : true_type {};
+
+
+// We can't get is_pod right without compiler help, so fail conservatively.
+// We will assume it's false except for arithmetic types, enumerations,
+// pointers and cv-qualified versions thereof. Note that std::pair<T,U>
+// is not a POD even if T and U are PODs.
+template <class T> struct is_pod
+ : integral_constant<bool, (is_integral<T>::value ||
+ is_floating_point<T>::value ||
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ // is_enum is not available on MSVC.
+ is_enum<T>::value ||
+#endif
+ is_pointer<T>::value)> { };
+template <class T> struct is_pod<const T> : is_pod<T> { };
+template <class T> struct is_pod<volatile T> : is_pod<T> { };
+template <class T> struct is_pod<const volatile T> : is_pod<T> { };
+
+
+// We can't get has_trivial_constructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// constructors. (3) array of a type with a trivial constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_constructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_constructor<T>::value &&
+ has_trivial_constructor<U>::value)> { };
+template <class A, int N> struct has_trivial_constructor<A[N]>
+ : has_trivial_constructor<A> { };
+template <class T> struct has_trivial_constructor<const T>
+ : has_trivial_constructor<T> { };
+
+// We can't get has_trivial_copy right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial copy constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_copy : is_pod<T> { };
+template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_copy<T>::value &&
+ has_trivial_copy<U>::value)> { };
+template <class A, int N> struct has_trivial_copy<A[N]>
+ : has_trivial_copy<A> { };
+template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
+
+// We can't get has_trivial_assign right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial assign constructor.
+template <class T> struct has_trivial_assign : is_pod<T> { };
+template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_assign<T>::value &&
+ has_trivial_assign<U>::value)> { };
+template <class A, int N> struct has_trivial_assign<A[N]>
+ : has_trivial_assign<A> { };
+
+// We can't get has_trivial_destructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// destructors. (3) array of a type with a trivial destructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_destructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_destructor<T>::value &&
+ has_trivial_destructor<U>::value)> { };
+template <class A, int N> struct has_trivial_destructor<A[N]>
+ : has_trivial_destructor<A> { };
+template <class T> struct has_trivial_destructor<const T>
+ : has_trivial_destructor<T> { };
+
+// Specified by TR1 [4.7.1]
+template<typename T> struct remove_const { typedef T type; };
+template<typename T> struct remove_const<T const> { typedef T type; };
+template<typename T> struct remove_volatile { typedef T type; };
+template<typename T> struct remove_volatile<T volatile> { typedef T type; };
+template<typename T> struct remove_cv {
+ typedef typename remove_const<typename remove_volatile<T>::type>::type type;
+};
+
+
+// Specified by TR1 [4.7.2] Reference modifications.
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+
+template <typename T> struct add_reference { typedef T& type; };
+template <typename T> struct add_reference<T&> { typedef T& type; };
+
+// Specified by TR1 [4.7.4] Pointer modifications.
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T* const> { typedef T type; };
+template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
+template<typename T> struct remove_pointer<T* const volatile> {
+ typedef T type; };
+
+// Specified by TR1 [4.6] Relationships between types
+template<typename T, typename U> struct is_same : public false_type { };
+template<typename T> struct is_same<T, T> : public true_type { };
+
+// Specified by TR1 [4.6] Relationships between types
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+namespace internal {
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From. See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+template <typename From, typename To>
+struct ConvertHelper {
+ static small_ Test(To);
+ static big_ Test(...);
+ static From Create();
+};
+} // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+template <typename From, typename To>
+struct is_convertible
+ : integral_constant<bool,
+ sizeof(internal::ConvertHelper<From, To>::Test(
+ internal::ConvertHelper<From, To>::Create()))
+ == sizeof(small_)> {
+};
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Right now these macros are no-ops, and mostly just document the fact
+// these types are PODs, for human use. They may be made more contentful
+// later. The typedef is just to make it legal to put a semicolon after
+// these macros.
+#define DECLARE_POD(TypeName) typedef int Dummy_Type_For_DECLARE_POD
+#define DECLARE_NESTED_POD(TypeName) DECLARE_POD(TypeName)
+#define PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(TemplateName) \
+ typedef int Dummy_Type_For_PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT
+#define ENFORCE_POD(TypeName) typedef int Dummy_Type_For_ENFORCE_POD
+
+#endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_
diff --git a/src/google/protobuf/stubs/type_traits_unittest.cc b/src/google/protobuf/stubs/type_traits_unittest.cc
new file mode 100644
index 00000000..00e5a476
--- /dev/null
+++ b/src/google/protobuf/stubs/type_traits_unittest.cc
@@ -0,0 +1,647 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// 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: Matt Austern
+
+#include <google/protobuf/stubs/type_traits.h>
+
+#include <stdlib.h> // for exit()
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+typedef int int32;
+typedef long int64;
+
+using std::string;
+using std::vector;
+using std::pair;
+
+using google::protobuf::internal::add_reference;
+using google::protobuf::internal::has_trivial_assign;
+using google::protobuf::internal::has_trivial_constructor;
+using google::protobuf::internal::has_trivial_copy;
+using google::protobuf::internal::has_trivial_destructor;
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+using google::protobuf::internal::is_convertible;
+using google::protobuf::internal::is_enum;
+#endif
+using google::protobuf::internal::is_floating_point;
+using google::protobuf::internal::is_integral;
+using google::protobuf::internal::is_pointer;
+using google::protobuf::internal::is_pod;
+using google::protobuf::internal::is_reference;
+using google::protobuf::internal::is_same;
+using google::protobuf::internal::remove_const;
+using google::protobuf::internal::remove_cv;
+using google::protobuf::internal::remove_pointer;
+using google::protobuf::internal::remove_reference;
+using google::protobuf::internal::remove_volatile;
+
+
+// This assertion produces errors like "error: invalid use of
+// incomplete type 'struct <unnamed>::AssertTypesEq<const int, int>'"
+// when it fails.
+template<typename T, typename U> struct AssertTypesEq;
+template<typename T> struct AssertTypesEq<T, T> {};
+#define COMPILE_ASSERT_TYPES_EQ(T, U) static_cast<void>(AssertTypesEq<T, U>())
+
+// A user-defined POD type.
+struct A {
+ int n_;
+};
+
+// A user-defined non-POD type with a trivial copy constructor.
+class B {
+ public:
+ explicit B(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+// Another user-defined non-POD type with a trivial copy constructor.
+// We will explicitly declare C to have a trivial copy constructor
+// by specializing has_trivial_copy.
+class C {
+ public:
+ explicit C(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_copy<C> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial assignment operator.
+// We will explicitly declare C to have a trivial assignment operator
+// by specializing has_trivial_assign.
+class D {
+ public:
+ explicit D(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_assign<D> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial constructor.
+// We will explicitly declare E to have a trivial constructor
+// by specializing has_trivial_constructor.
+class E {
+ public:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_constructor<E> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial destructor.
+// We will explicitly declare E to have a trivial destructor
+// by specializing has_trivial_destructor.
+class F {
+ public:
+ explicit F(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_destructor<F> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+enum G {};
+
+union H {};
+
+class I {
+ public:
+ operator int() const;
+};
+
+class J {
+ private:
+ operator int() const;
+};
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// A base class and a derived class that inherits from it, used for
+// testing conversion type traits.
+class Base {
+ public:
+ virtual ~Base() { }
+};
+
+class Derived : public Base {
+};
+
+TEST(TypeTraitsTest, TestIsInteger) {
+ // Verify that is_integral is true for all integer types.
+ EXPECT_TRUE(is_integral<bool>::value);
+ EXPECT_TRUE(is_integral<char>::value);
+ EXPECT_TRUE(is_integral<unsigned char>::value);
+ EXPECT_TRUE(is_integral<signed char>::value);
+ EXPECT_TRUE(is_integral<wchar_t>::value);
+ EXPECT_TRUE(is_integral<int>::value);
+ EXPECT_TRUE(is_integral<unsigned int>::value);
+ EXPECT_TRUE(is_integral<short>::value);
+ EXPECT_TRUE(is_integral<unsigned short>::value);
+ EXPECT_TRUE(is_integral<long>::value);
+ EXPECT_TRUE(is_integral<unsigned long>::value);
+
+ // Verify that is_integral is false for a few non-integer types.
+ EXPECT_FALSE(is_integral<void>::value);
+ EXPECT_FALSE(is_integral<float>::value);
+ EXPECT_FALSE(is_integral<string>::value);
+ EXPECT_FALSE(is_integral<int*>::value);
+ EXPECT_FALSE(is_integral<A>::value);
+ EXPECT_FALSE((is_integral<pair<int, int> >::value));
+
+ // Verify that cv-qualified integral types are still integral, and
+ // cv-qualified non-integral types are still non-integral.
+ EXPECT_TRUE(is_integral<const char>::value);
+ EXPECT_TRUE(is_integral<volatile bool>::value);
+ EXPECT_TRUE(is_integral<const volatile unsigned int>::value);
+ EXPECT_FALSE(is_integral<const float>::value);
+ EXPECT_FALSE(is_integral<int* volatile>::value);
+ EXPECT_FALSE(is_integral<const volatile string>::value);
+}
+
+TEST(TypeTraitsTest, TestIsFloating) {
+ // Verify that is_floating_point is true for all floating-point types.
+ EXPECT_TRUE(is_floating_point<float>::value);
+ EXPECT_TRUE(is_floating_point<double>::value);
+ EXPECT_TRUE(is_floating_point<long double>::value);
+
+ // Verify that is_floating_point is false for a few non-float types.
+ EXPECT_FALSE(is_floating_point<void>::value);
+ EXPECT_FALSE(is_floating_point<long>::value);
+ EXPECT_FALSE(is_floating_point<string>::value);
+ EXPECT_FALSE(is_floating_point<float*>::value);
+ EXPECT_FALSE(is_floating_point<A>::value);
+ EXPECT_FALSE((is_floating_point<pair<int, int> >::value));
+
+ // Verify that cv-qualified floating point types are still floating, and
+ // cv-qualified non-floating types are still non-floating.
+ EXPECT_TRUE(is_floating_point<const float>::value);
+ EXPECT_TRUE(is_floating_point<volatile double>::value);
+ EXPECT_TRUE(is_floating_point<const volatile long double>::value);
+ EXPECT_FALSE(is_floating_point<const int>::value);
+ EXPECT_FALSE(is_floating_point<volatile string>::value);
+ EXPECT_FALSE(is_floating_point<const volatile char>::value);
+}
+
+TEST(TypeTraitsTest, TestIsPointer) {
+ // Verify that is_pointer is true for some pointer types.
+ EXPECT_TRUE(is_pointer<int*>::value);
+ EXPECT_TRUE(is_pointer<void*>::value);
+ EXPECT_TRUE(is_pointer<string*>::value);
+ EXPECT_TRUE(is_pointer<const void*>::value);
+ EXPECT_TRUE(is_pointer<volatile float* const*>::value);
+
+ // Verify that is_pointer is false for some non-pointer types.
+ EXPECT_FALSE(is_pointer<void>::value);
+ EXPECT_FALSE(is_pointer<float&>::value);
+ EXPECT_FALSE(is_pointer<long>::value);
+ EXPECT_FALSE(is_pointer<vector<int*> >::value);
+ EXPECT_FALSE(is_pointer<int[5]>::value);
+
+ // A function pointer is a pointer, but a function type, or a function
+ // reference type, is not.
+ EXPECT_TRUE(is_pointer<int (*)(int x)>::value);
+ EXPECT_FALSE(is_pointer<void(char x)>::value);
+ EXPECT_FALSE(is_pointer<double (&)(string x)>::value);
+
+ // Verify that is_pointer<T> is true for some cv-qualified pointer types,
+ // and false for some cv-qualified non-pointer types.
+ EXPECT_TRUE(is_pointer<int* const>::value);
+ EXPECT_TRUE(is_pointer<const void* volatile>::value);
+ EXPECT_TRUE(is_pointer<char** const volatile>::value);
+ EXPECT_FALSE(is_pointer<const int>::value);
+ EXPECT_FALSE(is_pointer<volatile vector<int*> >::value);
+ EXPECT_FALSE(is_pointer<const volatile double>::value);
+}
+
+TEST(TypeTraitsTest, TestIsEnum) {
+// is_enum isn't supported on MSVC or gcc 3.x
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ // Verify that is_enum is true for enum types.
+ EXPECT_TRUE(is_enum<G>::value);
+ EXPECT_TRUE(is_enum<const G>::value);
+ EXPECT_TRUE(is_enum<volatile G>::value);
+ EXPECT_TRUE(is_enum<const volatile G>::value);
+
+ // Verify that is_enum is false for a few non-enum types.
+ EXPECT_FALSE(is_enum<void>::value);
+ EXPECT_FALSE(is_enum<G&>::value);
+ EXPECT_FALSE(is_enum<G[1]>::value);
+ EXPECT_FALSE(is_enum<const G[1]>::value);
+ EXPECT_FALSE(is_enum<G[]>::value);
+ EXPECT_FALSE(is_enum<int>::value);
+ EXPECT_FALSE(is_enum<float>::value);
+ EXPECT_FALSE(is_enum<A>::value);
+ EXPECT_FALSE(is_enum<A*>::value);
+ EXPECT_FALSE(is_enum<const A>::value);
+ EXPECT_FALSE(is_enum<H>::value);
+ EXPECT_FALSE(is_enum<I>::value);
+ EXPECT_FALSE(is_enum<J>::value);
+ EXPECT_FALSE(is_enum<void()>::value);
+ EXPECT_FALSE(is_enum<void(*)()>::value);
+ EXPECT_FALSE(is_enum<int A::*>::value);
+ EXPECT_FALSE(is_enum<void (A::*)()>::value);
+#endif
+}
+
+TEST(TypeTraitsTest, TestIsReference) {
+ // Verifies that is_reference is true for all reference types.
+ typedef float& RefFloat;
+ EXPECT_TRUE(is_reference<float&>::value);
+ EXPECT_TRUE(is_reference<const int&>::value);
+ EXPECT_TRUE(is_reference<const int*&>::value);
+ EXPECT_TRUE(is_reference<int (&)(bool)>::value);
+ EXPECT_TRUE(is_reference<RefFloat>::value);
+ EXPECT_TRUE(is_reference<const RefFloat>::value);
+ EXPECT_TRUE(is_reference<volatile RefFloat>::value);
+ EXPECT_TRUE(is_reference<const volatile RefFloat>::value);
+
+
+ // Verifies that is_reference is false for all non-reference types.
+ EXPECT_FALSE(is_reference<float>::value);
+ EXPECT_FALSE(is_reference<const float>::value);
+ EXPECT_FALSE(is_reference<volatile float>::value);
+ EXPECT_FALSE(is_reference<const volatile float>::value);
+ EXPECT_FALSE(is_reference<const int*>::value);
+ EXPECT_FALSE(is_reference<int()>::value);
+ EXPECT_FALSE(is_reference<void(*)(const char&)>::value);
+}
+
+TEST(TypeTraitsTest, TestAddReference) {
+ COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int&,
+ add_reference<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(const volatile int&,
+ add_reference<const volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int&,
+ add_reference<volatile int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const volatile int&,
+ add_reference<const volatile int&>::type);
+}
+
+TEST(TypeTraitsTest, TestIsPod) {
+ // Verify that arithmetic types and pointers are marked as PODs.
+ EXPECT_TRUE(is_pod<bool>::value);
+ EXPECT_TRUE(is_pod<char>::value);
+ EXPECT_TRUE(is_pod<unsigned char>::value);
+ EXPECT_TRUE(is_pod<signed char>::value);
+ EXPECT_TRUE(is_pod<wchar_t>::value);
+ EXPECT_TRUE(is_pod<int>::value);
+ EXPECT_TRUE(is_pod<unsigned int>::value);
+ EXPECT_TRUE(is_pod<short>::value);
+ EXPECT_TRUE(is_pod<unsigned short>::value);
+ EXPECT_TRUE(is_pod<long>::value);
+ EXPECT_TRUE(is_pod<unsigned long>::value);
+ EXPECT_TRUE(is_pod<float>::value);
+ EXPECT_TRUE(is_pod<double>::value);
+ EXPECT_TRUE(is_pod<long double>::value);
+ EXPECT_TRUE(is_pod<string*>::value);
+ EXPECT_TRUE(is_pod<A*>::value);
+ EXPECT_TRUE(is_pod<const B*>::value);
+ EXPECT_TRUE(is_pod<C**>::value);
+ EXPECT_TRUE(is_pod<const int>::value);
+ EXPECT_TRUE(is_pod<char* volatile>::value);
+ EXPECT_TRUE(is_pod<const volatile double>::value);
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ EXPECT_TRUE(is_pod<G>::value);
+ EXPECT_TRUE(is_pod<const G>::value);
+ EXPECT_TRUE(is_pod<volatile G>::value);
+ EXPECT_TRUE(is_pod<const volatile G>::value);
+#endif
+
+ // Verify that some non-POD types are not marked as PODs.
+ EXPECT_FALSE(is_pod<void>::value);
+ EXPECT_FALSE(is_pod<string>::value);
+ EXPECT_FALSE((is_pod<pair<int, int> >::value));
+ EXPECT_FALSE(is_pod<A>::value);
+ EXPECT_FALSE(is_pod<B>::value);
+ EXPECT_FALSE(is_pod<C>::value);
+ EXPECT_FALSE(is_pod<const string>::value);
+ EXPECT_FALSE(is_pod<volatile A>::value);
+ EXPECT_FALSE(is_pod<const volatile B>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialConstructor) {
+ // Verify that arithmetic types and pointers have trivial constructors.
+ EXPECT_TRUE(has_trivial_constructor<bool>::value);
+ EXPECT_TRUE(has_trivial_constructor<char>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_constructor<signed char>::value);
+ EXPECT_TRUE(has_trivial_constructor<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_constructor<int>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_constructor<short>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_constructor<long>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_constructor<float>::value);
+ EXPECT_TRUE(has_trivial_constructor<double>::value);
+ EXPECT_TRUE(has_trivial_constructor<long double>::value);
+ EXPECT_TRUE(has_trivial_constructor<string*>::value);
+ EXPECT_TRUE(has_trivial_constructor<A*>::value);
+ EXPECT_TRUE(has_trivial_constructor<const B*>::value);
+ EXPECT_TRUE(has_trivial_constructor<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // constructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_constructor<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_constructor<int10>::value);
+
+ // Verify that pairs of types without trivial constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_constructor<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_constructor<pair<string, int> >::value));
+
+ // Verify that types without trivial constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_constructor<string>::value);
+ EXPECT_FALSE(has_trivial_constructor<vector<int> >::value);
+
+ // Verify that E, which we have declared to have a trivial
+ // constructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_constructor<E>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialCopy) {
+ // Verify that arithmetic types and pointers have trivial copy
+ // constructors.
+ EXPECT_TRUE(has_trivial_copy<bool>::value);
+ EXPECT_TRUE(has_trivial_copy<char>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_copy<signed char>::value);
+ EXPECT_TRUE(has_trivial_copy<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_copy<int>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_copy<short>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_copy<long>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_copy<float>::value);
+ EXPECT_TRUE(has_trivial_copy<double>::value);
+ EXPECT_TRUE(has_trivial_copy<long double>::value);
+ EXPECT_TRUE(has_trivial_copy<string*>::value);
+ EXPECT_TRUE(has_trivial_copy<A*>::value);
+ EXPECT_TRUE(has_trivial_copy<const B*>::value);
+ EXPECT_TRUE(has_trivial_copy<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // copy constructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_copy<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_copy<int10>::value);
+
+ // Verify that pairs of types without trivial copy constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_copy<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_copy<pair<string, int> >::value));
+
+ // Verify that types without trivial copy constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_copy<string>::value);
+ EXPECT_FALSE(has_trivial_copy<vector<int> >::value);
+
+ // Verify that C, which we have declared to have a trivial
+ // copy constructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_copy<C>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialAssign) {
+ // Verify that arithmetic types and pointers have trivial assignment
+ // operators.
+ EXPECT_TRUE(has_trivial_assign<bool>::value);
+ EXPECT_TRUE(has_trivial_assign<char>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_assign<signed char>::value);
+ EXPECT_TRUE(has_trivial_assign<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_assign<int>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_assign<short>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_assign<long>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_assign<float>::value);
+ EXPECT_TRUE(has_trivial_assign<double>::value);
+ EXPECT_TRUE(has_trivial_assign<long double>::value);
+ EXPECT_TRUE(has_trivial_assign<string*>::value);
+ EXPECT_TRUE(has_trivial_assign<A*>::value);
+ EXPECT_TRUE(has_trivial_assign<const B*>::value);
+ EXPECT_TRUE(has_trivial_assign<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // assignment operators.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_assign<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_assign<int10>::value);
+
+ // Verify that pairs of types without trivial assignment operators
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_assign<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_assign<pair<string, int> >::value));
+
+ // Verify that types without trivial assignment operators are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_assign<string>::value);
+ EXPECT_FALSE(has_trivial_assign<vector<int> >::value);
+
+ // Verify that D, which we have declared to have a trivial
+ // assignment operator, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_assign<D>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialDestructor) {
+ // Verify that arithmetic types and pointers have trivial destructors.
+ EXPECT_TRUE(has_trivial_destructor<bool>::value);
+ EXPECT_TRUE(has_trivial_destructor<char>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_destructor<signed char>::value);
+ EXPECT_TRUE(has_trivial_destructor<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_destructor<int>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_destructor<short>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_destructor<long>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_destructor<float>::value);
+ EXPECT_TRUE(has_trivial_destructor<double>::value);
+ EXPECT_TRUE(has_trivial_destructor<long double>::value);
+ EXPECT_TRUE(has_trivial_destructor<string*>::value);
+ EXPECT_TRUE(has_trivial_destructor<A*>::value);
+ EXPECT_TRUE(has_trivial_destructor<const B*>::value);
+ EXPECT_TRUE(has_trivial_destructor<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // destructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_destructor<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_destructor<int10>::value);
+
+ // Verify that pairs of types without trivial destructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_destructor<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_destructor<pair<string, int> >::value));
+
+ // Verify that types without trivial destructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_destructor<string>::value);
+ EXPECT_FALSE(has_trivial_destructor<vector<int> >::value);
+
+ // Verify that F, which we have declared to have a trivial
+ // destructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_destructor<F>::value);
+}
+
+// Tests remove_pointer.
+TEST(TypeTraitsTest, TestRemovePointer) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int*>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int, remove_pointer<const int*>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* const>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* volatile>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveConst) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_const<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_const<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_const<int * const>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(const int *, remove_const<const int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int,
+ remove_const<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveVolatile) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_volatile<int * volatile>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(volatile int *,
+ remove_volatile<volatile int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int,
+ remove_volatile<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveCV) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_cv<int * const volatile>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(const volatile int *,
+ remove_cv<const volatile int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(int,
+ remove_cv<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveReference) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int, remove_reference<const int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(int*, remove_reference<int * &>::type);
+}
+
+TEST(TypeTraitsTest, TestIsSame) {
+ EXPECT_TRUE((is_same<int32, int32>::value));
+ EXPECT_FALSE((is_same<int32, int64>::value));
+ EXPECT_FALSE((is_same<int64, int32>::value));
+ EXPECT_FALSE((is_same<int, const int>::value));
+
+ EXPECT_TRUE((is_same<void, void>::value));
+ EXPECT_FALSE((is_same<void, int>::value));
+ EXPECT_FALSE((is_same<int, void>::value));
+
+ EXPECT_TRUE((is_same<int*, int*>::value));
+ EXPECT_TRUE((is_same<void*, void*>::value));
+ EXPECT_FALSE((is_same<int*, void*>::value));
+ EXPECT_FALSE((is_same<void*, int*>::value));
+ EXPECT_FALSE((is_same<void*, const void*>::value));
+ EXPECT_FALSE((is_same<void*, void* const>::value));
+
+ EXPECT_TRUE((is_same<Base*, Base*>::value));
+ EXPECT_TRUE((is_same<Derived*, Derived*>::value));
+ EXPECT_FALSE((is_same<Base*, Derived*>::value));
+ EXPECT_FALSE((is_same<Derived*, Base*>::value));
+}
+
+TEST(TypeTraitsTest, TestConvertible) {
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ EXPECT_TRUE((is_convertible<int, int>::value));
+ EXPECT_TRUE((is_convertible<int, long>::value));
+ EXPECT_TRUE((is_convertible<long, int>::value));
+
+ EXPECT_TRUE((is_convertible<int*, void*>::value));
+ EXPECT_FALSE((is_convertible<void*, int*>::value));
+
+ EXPECT_TRUE((is_convertible<Derived*, Base*>::value));
+ EXPECT_FALSE((is_convertible<Base*, Derived*>::value));
+ EXPECT_TRUE((is_convertible<Derived*, const Base*>::value));
+ EXPECT_FALSE((is_convertible<const Derived*, Base*>::value));
+#endif
+}
+
+} // anonymous namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index af8b3909..841f4b30 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -50,6 +50,13 @@ namespace google {
namespace protobuf {
void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
+ SetOptionalFields(message);
+ AddRepeatedFields1(message);
+ AddRepeatedFields2(message);
+ SetDefaultFields(message);
+}
+
+void TestUtil::SetOptionalFields(unittest::TestAllTypes* message) {
message->set_optional_int32 (101);
message->set_optional_int64 (102);
message->set_optional_uint32 (103);
@@ -66,10 +73,12 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->set_optional_string ("115");
message->set_optional_bytes ("116");
- message->mutable_optionalgroup ()->set_a(117);
- message->mutable_optional_nested_message ()->set_bb(118);
- message->mutable_optional_foreign_message()->set_c(119);
- message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optionalgroup ()->set_a(117);
+ message->mutable_optional_nested_message ()->set_bb(118);
+ message->mutable_optional_foreign_message ()->set_c(119);
+ message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optional_public_import_message()->set_e(126);
+ message->mutable_optional_lazy_message ()->set_bb(127);
message->set_optional_nested_enum (unittest::TestAllTypes::BAZ);
message->set_optional_foreign_enum(unittest::FOREIGN_BAZ );
@@ -87,9 +96,11 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("optional_cord"),
"125");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
- // -----------------------------------------------------------------
+// -------------------------------------------------------------------
+void TestUtil::AddRepeatedFields1(unittest::TestAllTypes* message) {
message->add_repeated_int32 (201);
message->add_repeated_int64 (202);
message->add_repeated_uint32 (203);
@@ -110,6 +121,7 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->add_repeated_nested_message ()->set_bb(218);
message->add_repeated_foreign_message()->set_c(219);
message->add_repeated_import_message ()->set_d(220);
+ message->add_repeated_lazy_message ()->set_bb(227);
message->add_repeated_nested_enum (unittest::TestAllTypes::BAR);
message->add_repeated_foreign_enum(unittest::FOREIGN_BAR );
@@ -125,7 +137,9 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("repeated_cord"),
"225");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+void TestUtil::AddRepeatedFields2(unittest::TestAllTypes* message) {
// Add a second one of each field.
message->add_repeated_int32 (301);
message->add_repeated_int64 (302);
@@ -147,6 +161,7 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->add_repeated_nested_message ()->set_bb(318);
message->add_repeated_foreign_message()->set_c(319);
message->add_repeated_import_message ()->set_d(320);
+ message->add_repeated_lazy_message ()->set_bb(327);
message->add_repeated_nested_enum (unittest::TestAllTypes::BAZ);
message->add_repeated_foreign_enum(unittest::FOREIGN_BAZ );
@@ -162,9 +177,11 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("repeated_cord"),
"325");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
- // -----------------------------------------------------------------
+// -------------------------------------------------------------------
+void TestUtil::SetDefaultFields(unittest::TestAllTypes* message) {
message->set_default_int32 (401);
message->set_default_int64 (402);
message->set_default_uint32 (403);
@@ -220,6 +237,7 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) {
message->mutable_repeated_nested_message (1)->set_bb(518);
message->mutable_repeated_foreign_message(1)->set_c(519);
message->mutable_repeated_import_message (1)->set_d(520);
+ message->mutable_repeated_lazy_message (1)->set_bb(527);
message->set_repeated_nested_enum (1, unittest::TestAllTypes::FOO);
message->set_repeated_foreign_enum(1, unittest::FOREIGN_FOO );
@@ -256,15 +274,19 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_TRUE(message.has_optional_string ());
EXPECT_TRUE(message.has_optional_bytes ());
- EXPECT_TRUE(message.has_optionalgroup ());
- EXPECT_TRUE(message.has_optional_nested_message ());
- EXPECT_TRUE(message.has_optional_foreign_message());
- EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optionalgroup ());
+ EXPECT_TRUE(message.has_optional_nested_message ());
+ EXPECT_TRUE(message.has_optional_foreign_message ());
+ EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optional_public_import_message());
+ EXPECT_TRUE(message.has_optional_lazy_message ());
- EXPECT_TRUE(message.optionalgroup ().has_a());
- EXPECT_TRUE(message.optional_nested_message ().has_bb());
- EXPECT_TRUE(message.optional_foreign_message().has_c());
- EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optionalgroup ().has_a());
+ EXPECT_TRUE(message.optional_nested_message ().has_bb());
+ EXPECT_TRUE(message.optional_foreign_message ().has_c());
+ EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optional_public_import_message().has_e());
+ EXPECT_TRUE(message.optional_lazy_message ().has_bb());
EXPECT_TRUE(message.has_optional_nested_enum ());
EXPECT_TRUE(message.has_optional_foreign_enum());
@@ -291,10 +313,12 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ("115", message.optional_string ());
EXPECT_EQ("116", message.optional_bytes ());
- EXPECT_EQ(117, message.optionalgroup ().a());
- EXPECT_EQ(118, message.optional_nested_message ().bb());
- EXPECT_EQ(119, message.optional_foreign_message().c());
- EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(117, message.optionalgroup ().a());
+ EXPECT_EQ(118, message.optional_nested_message ().bb());
+ EXPECT_EQ(119, message.optional_foreign_message ().c());
+ EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(126, message.optional_public_import_message ().e());
+ EXPECT_EQ(127, message.optional_lazy_message ().bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.optional_nested_enum ());
EXPECT_EQ(unittest::FOREIGN_BAZ , message.optional_foreign_enum());
@@ -323,6 +347,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -352,6 +377,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
@@ -378,6 +404,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(318, message.repeated_nested_message (1).bb());
EXPECT_EQ(319, message.repeated_foreign_message(1).c());
EXPECT_EQ(320, message.repeated_import_message (1).d());
+ EXPECT_EQ(327, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.repeated_foreign_enum(1));
@@ -449,10 +476,12 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_FALSE(message.has_optional_string ());
EXPECT_FALSE(message.has_optional_bytes ());
- EXPECT_FALSE(message.has_optionalgroup ());
- EXPECT_FALSE(message.has_optional_nested_message ());
- EXPECT_FALSE(message.has_optional_foreign_message());
- EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optionalgroup ());
+ EXPECT_FALSE(message.has_optional_nested_message ());
+ EXPECT_FALSE(message.has_optional_foreign_message ());
+ EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optional_public_import_message());
+ EXPECT_FALSE(message.has_optional_lazy_message ());
EXPECT_FALSE(message.has_optional_nested_enum ());
EXPECT_FALSE(message.has_optional_foreign_enum());
@@ -479,15 +508,19 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ("" , message.optional_bytes ());
// Embedded messages should also be clear.
- EXPECT_FALSE(message.optionalgroup ().has_a());
- EXPECT_FALSE(message.optional_nested_message ().has_bb());
- EXPECT_FALSE(message.optional_foreign_message().has_c());
- EXPECT_FALSE(message.optional_import_message ().has_d());
-
- EXPECT_EQ(0, message.optionalgroup ().a());
- EXPECT_EQ(0, message.optional_nested_message ().bb());
- EXPECT_EQ(0, message.optional_foreign_message().c());
- EXPECT_EQ(0, message.optional_import_message ().d());
+ EXPECT_FALSE(message.optionalgroup ().has_a());
+ EXPECT_FALSE(message.optional_nested_message ().has_bb());
+ EXPECT_FALSE(message.optional_foreign_message ().has_c());
+ EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optional_public_import_message().has_e());
+ EXPECT_FALSE(message.optional_lazy_message ().has_bb());
+
+ EXPECT_EQ(0, message.optionalgroup ().a());
+ EXPECT_EQ(0, message.optional_nested_message ().bb());
+ EXPECT_EQ(0, message.optional_foreign_message ().c());
+ EXPECT_EQ(0, message.optional_import_message ().d());
+ EXPECT_EQ(0, message.optional_public_import_message().e());
+ EXPECT_EQ(0, message.optional_lazy_message ().bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypes::FOO, message.optional_nested_enum ());
@@ -516,6 +549,7 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ(0, message.repeated_nested_message_size ());
EXPECT_EQ(0, message.repeated_foreign_message_size());
EXPECT_EQ(0, message.repeated_import_message_size ());
+ EXPECT_EQ(0, message.repeated_lazy_message_size ());
EXPECT_EQ(0, message.repeated_nested_enum_size ());
EXPECT_EQ(0, message.repeated_foreign_enum_size ());
EXPECT_EQ(0, message.repeated_import_enum_size ());
@@ -595,6 +629,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -624,6 +659,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(0));
@@ -651,6 +687,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(518, message.repeated_nested_message (1).bb());
EXPECT_EQ(519, message.repeated_foreign_message(1).c());
EXPECT_EQ(520, message.repeated_import_message (1).d());
+ EXPECT_EQ(527, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypes::FOO, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_FOO , message.repeated_foreign_enum(1));
@@ -953,6 +990,9 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->SetExtension(unittest::optional_string_piece_extension, "124");
message->SetExtension(unittest::optional_cord_extension, "125");
+ message->MutableExtension(unittest::optional_public_import_message_extension)->set_e(126);
+ message->MutableExtension(unittest::optional_lazy_message_extension)->set_bb(127);
+
// -----------------------------------------------------------------
message->AddExtension(unittest::repeated_int32_extension , 201);
@@ -975,6 +1015,7 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->AddExtension(unittest::repeated_nested_message_extension )->set_bb(218);
message->AddExtension(unittest::repeated_foreign_message_extension)->set_c(219);
message->AddExtension(unittest::repeated_import_message_extension )->set_d(220);
+ message->AddExtension(unittest::repeated_lazy_message_extension )->set_bb(227);
message->AddExtension(unittest::repeated_nested_enum_extension , unittest::TestAllTypes::BAR);
message->AddExtension(unittest::repeated_foreign_enum_extension, unittest::FOREIGN_BAR );
@@ -1004,6 +1045,7 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->AddExtension(unittest::repeated_nested_message_extension )->set_bb(318);
message->AddExtension(unittest::repeated_foreign_message_extension)->set_c(319);
message->AddExtension(unittest::repeated_import_message_extension )->set_d(320);
+ message->AddExtension(unittest::repeated_lazy_message_extension )->set_bb(327);
message->AddExtension(unittest::repeated_nested_enum_extension , unittest::TestAllTypes::BAZ);
message->AddExtension(unittest::repeated_foreign_enum_extension, unittest::FOREIGN_BAZ );
@@ -1073,6 +1115,7 @@ void TestUtil::ModifyRepeatedExtensions(unittest::TestAllExtensions* message) {
message->MutableExtension(unittest::repeated_nested_message_extension , 1)->set_bb(518);
message->MutableExtension(unittest::repeated_foreign_message_extension, 1)->set_c(519);
message->MutableExtension(unittest::repeated_import_message_extension , 1)->set_d(520);
+ message->MutableExtension(unittest::repeated_lazy_message_extension , 1)->set_bb(527);
message->SetExtension(unittest::repeated_nested_enum_extension , 1, unittest::TestAllTypes::FOO);
message->SetExtension(unittest::repeated_foreign_enum_extension, 1, unittest::FOREIGN_FOO );
@@ -1102,15 +1145,19 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension ));
EXPECT_TRUE(message.HasExtension(unittest::optional_bytes_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension));
- EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_public_import_message_extension));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_lazy_message_extension ));
- EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
- EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
- EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension).has_c());
- EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension ).has_c());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_public_import_message_extension).has_e());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_lazy_message_extension ).has_bb());
EXPECT_TRUE(message.HasExtension(unittest::optional_nested_enum_extension ));
EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_enum_extension));
@@ -1146,6 +1193,8 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ("124", message.GetExtension(unittest::optional_string_piece_extension));
EXPECT_EQ("125", message.GetExtension(unittest::optional_cord_extension));
+ EXPECT_EQ(126, message.GetExtension(unittest::optional_public_import_message_extension ).e());
+ EXPECT_EQ(127, message.GetExtension(unittest::optional_lazy_message_extension).bb());
// -----------------------------------------------------------------
@@ -1169,6 +1218,7 @@ void TestUtil::ExpectAllExtensionsSet(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1196,6 +1246,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1224,6 +1275,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -1307,10 +1359,12 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(unittest::optional_string_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_bytes_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension));
- EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_public_import_message_extension));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_lazy_message_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_nested_enum_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_enum_extension));
@@ -1337,15 +1391,19 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ("" , message.GetExtension(unittest::optional_bytes_extension ));
// Embedded messages should also be clear.
- EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
- EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
- EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension).has_c());
- EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
-
- EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension ).a());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension ).bb());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension).c());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension ).d());
+ EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension ).has_c());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_public_import_message_extension).has_e());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_lazy_message_extension ).has_bb());
+
+ EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension ).a());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension ).bb());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension ).c());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension ).d());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_public_import_message_extension).e());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_lazy_message_extension ).bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypes::FOO, message.GetExtension(unittest::optional_nested_enum_extension ));
@@ -1376,6 +1434,7 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_message_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_message_extension));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1459,6 +1518,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1486,6 +1546,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1515,6 +1576,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(518, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(519, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(520, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(527, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::FOO, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_FOO , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -1750,6 +1812,7 @@ void TestUtil::ExpectLastRepeatedsRemoved(
ASSERT_EQ(1, message.repeated_nested_message_size ());
ASSERT_EQ(1, message.repeated_foreign_message_size());
ASSERT_EQ(1, message.repeated_import_message_size ());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
ASSERT_EQ(1, message.repeated_nested_enum_size ());
ASSERT_EQ(1, message.repeated_foreign_enum_size ());
ASSERT_EQ(1, message.repeated_import_enum_size ());
@@ -1780,6 +1843,7 @@ void TestUtil::ExpectLastRepeatedsRemoved(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(0));
@@ -1810,6 +1874,7 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1838,6 +1903,7 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1847,6 +1913,36 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
EXPECT_EQ("225", message.GetExtension(unittest::repeated_cord_extension, 0));
}
+void TestUtil::ExpectLastRepeatedsReleased(
+ const unittest::TestAllTypes& message) {
+ ASSERT_EQ(1, message.repeatedgroup_size ());
+ ASSERT_EQ(1, message.repeated_nested_message_size ());
+ ASSERT_EQ(1, message.repeated_foreign_message_size());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
+
+ EXPECT_EQ(217, message.repeatedgroup (0).a());
+ EXPECT_EQ(218, message.repeated_nested_message (0).bb());
+ EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
+}
+
+void TestUtil::ExpectLastRepeatedExtensionsReleased(
+ const unittest::TestAllExtensions& message) {
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeatedgroup_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_message_extension));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
+
+ EXPECT_EQ(217, message.GetExtension(unittest::repeatedgroup_extension , 0).a());
+ EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
+ EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
+ EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
+}
+
void TestUtil::ExpectRepeatedsSwapped(
const unittest::TestAllTypes& message) {
ASSERT_EQ(2, message.repeated_int32_size ());
@@ -1869,6 +1965,7 @@ void TestUtil::ExpectRepeatedsSwapped(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_import_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -1899,6 +1996,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(218, message.repeated_nested_message (1).bb());
EXPECT_EQ(219, message.repeated_foreign_message(1).c());
EXPECT_EQ(220, message.repeated_import_message (1).d());
+ EXPECT_EQ(220, message.repeated_import_message (1).d());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(1));
@@ -1924,6 +2022,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(318, message.repeated_nested_message (0).bb());
EXPECT_EQ(319, message.repeated_foreign_message(0).c());
EXPECT_EQ(320, message.repeated_import_message (0).d());
+ EXPECT_EQ(320, message.repeated_import_message (0).d());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.repeated_foreign_enum(0));
@@ -1953,6 +2052,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1980,6 +2080,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -2008,6 +2109,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -2031,6 +2133,8 @@ TestUtil::ReflectionTester::ReflectionTester(
pool->FindFieldByName("protobuf_unittest.ForeignMessage.c");
import_d_ =
pool->FindFieldByName("protobuf_unittest_import.ImportMessage.d");
+ import_e_ =
+ pool->FindFieldByName("protobuf_unittest_import.PublicImportMessage.e");
nested_foo_ =
pool->FindEnumValueByName("protobuf_unittest.TestAllTypes.FOO");
nested_bar_ =
@@ -2067,6 +2171,7 @@ TestUtil::ReflectionTester::ReflectionTester(
EXPECT_TRUE(nested_b_ != NULL);
EXPECT_TRUE(foreign_c_ != NULL);
EXPECT_TRUE(import_d_ != NULL);
+ EXPECT_TRUE(import_e_ != NULL);
EXPECT_TRUE(nested_foo_ != NULL);
EXPECT_TRUE(nested_bar_ != NULL);
EXPECT_TRUE(nested_baz_ != NULL);
@@ -2129,6 +2234,12 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
reflection->SetString(message, F("optional_string_piece"), "124");
reflection->SetString(message, F("optional_cord"), "125");
+ sub_message = reflection->MutableMessage(message, F("optional_public_import_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, import_e_, 126);
+
+ sub_message = reflection->MutableMessage(message, F("optional_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 127);
+
// -----------------------------------------------------------------
reflection->AddInt32 (message, F("repeated_int32" ), 201);
@@ -2155,6 +2266,8 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 219);
sub_message = reflection->AddMessage(message, F("repeated_import_message"));
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 220);
+ sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 227);
reflection->AddEnum(message, F("repeated_nested_enum" ), nested_bar_);
reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_bar_);
@@ -2188,6 +2301,8 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 319);
sub_message = reflection->AddMessage(message, F("repeated_import_message"));
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 320);
+ sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 327);
reflection->AddEnum(message, F("repeated_nested_enum" ), nested_baz_);
reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_baz_);
@@ -2289,10 +2404,12 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(reflection->HasField(message, F("optional_string" )));
EXPECT_TRUE(reflection->HasField(message, F("optional_bytes" )));
- EXPECT_TRUE(reflection->HasField(message, F("optionalgroup" )));
- EXPECT_TRUE(reflection->HasField(message, F("optional_nested_message" )));
- EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_message")));
- EXPECT_TRUE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optionalgroup" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_nested_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_public_import_message")));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_lazy_message" )));
sub_message = &reflection->GetMessage(message, F("optionalgroup"));
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, group_a_));
@@ -2302,6 +2419,10 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, foreign_c_));
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
EXPECT_TRUE(reflection->HasField(message, F("optional_nested_enum" )));
EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_enum")));
@@ -2337,6 +2458,10 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ(119, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_EQ(120, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_EQ(126, sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_EQ(127, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_baz_, reflection->GetEnum(message, F("optional_nested_enum" )));
EXPECT_EQ(foreign_baz_, reflection->GetEnum(message, F("optional_foreign_enum")));
@@ -2347,6 +2472,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ("125", reflection->GetString(message, F("optional_cord")));
EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"), &scratch));
+
}
void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
@@ -2377,6 +2503,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_message" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_message")));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_message" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_lazy_message" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_enum" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_enum" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_enum" )));
@@ -2411,6 +2538,8 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(219, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 0);
EXPECT_EQ(220, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 0);
+ EXPECT_EQ(227, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_bar_, reflection->GetRepeatedEnum(message, F("repeated_nested_enum" ),0));
EXPECT_EQ(foreign_bar_, reflection->GetRepeatedEnum(message, F("repeated_foreign_enum"),0));
@@ -2453,6 +2582,8 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(319, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 1);
EXPECT_EQ(320, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 1);
+ EXPECT_EQ(327, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_baz_, reflection->GetRepeatedEnum(message, F("repeated_nested_enum" ),1));
EXPECT_EQ(foreign_baz_, reflection->GetRepeatedEnum(message, F("repeated_foreign_enum"),1));
@@ -2609,6 +2740,8 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_FALSE(reflection->HasField(message, F("optional_nested_message" )));
EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_message")));
EXPECT_FALSE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_FALSE(reflection->HasField(message, F("optional_public_import_message")));
+ EXPECT_FALSE(reflection->HasField(message, F("optional_lazy_message")));
EXPECT_FALSE(reflection->HasField(message, F("optional_nested_enum" )));
EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_enum")));
@@ -2650,6 +2783,12 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ( nested_foo_, reflection->GetEnum(message, F("optional_nested_enum" )));
@@ -2683,6 +2822,7 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_message" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_message")));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_message" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_lazy_message" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_enum" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_enum" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_enum" )));
@@ -2796,6 +2936,8 @@ void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 519);
sub_message = reflection->MutableRepeatedMessage(message, F("repeated_import_message"), 1);
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 520);
+ sub_message = reflection->MutableRepeatedMessage(message, F("repeated_lazy_message"), 1);
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 527);
reflection->SetRepeatedEnum(message, F("repeated_nested_enum" ), 1, nested_foo_);
reflection->SetRepeatedEnum(message, F("repeated_foreign_enum"), 1, foreign_foo_);
@@ -2824,7 +2966,8 @@ void TestUtil::ReflectionTester::ModifyPackedFieldsViaReflection(
reflection->SetRepeatedEnum (message, F("packed_enum" ), 1, foreign_foo_);
}
-void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(Message* message) {
+void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(
+ Message* message) {
const Reflection* reflection = message->GetReflection();
vector<const FieldDescriptor*> output;
@@ -2837,6 +2980,26 @@ void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(Message* messa
}
}
+void TestUtil::ReflectionTester::ReleaseLastRepeatedsViaReflection(
+ Message* message, bool expect_extensions_notnull) {
+ const Reflection* reflection = message->GetReflection();
+
+ vector<const FieldDescriptor*> output;
+ reflection->ListFields(*message, &output);
+ for (int i=0; i<output.size(); ++i) {
+ const FieldDescriptor* field = output[i];
+ if (!field->is_repeated()) continue;
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+ Message* released = reflection->ReleaseLast(message, field);
+ if (!field->is_extension() || expect_extensions_notnull) {
+ ASSERT_TRUE(released != NULL) << "ReleaseLast returned NULL for: "
+ << field->name();
+ }
+ delete released;
+ }
+}
+
void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) {
const Reflection* reflection = message->GetReflection();
@@ -2850,5 +3013,35 @@ void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) {
}
}
+void TestUtil::ReflectionTester::ExpectMessagesReleasedViaReflection(
+ Message* message,
+ TestUtil::ReflectionTester::MessageReleaseState expected_release_state) {
+ const Reflection* reflection = message->GetReflection();
+
+ static const char* fields[] = {
+ "optionalgroup",
+ "optional_nested_message",
+ "optional_foreign_message",
+ "optional_import_message",
+ };
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(fields); i++) {
+ const Message& sub_message = reflection->GetMessage(*message, F(fields[i]));
+ Message* released = reflection->ReleaseMessage(message, F(fields[i]));
+ switch (expected_release_state) {
+ case IS_NULL:
+ EXPECT_TRUE(released == NULL);
+ break;
+ case NOT_NULL:
+ EXPECT_TRUE(released != NULL);
+ EXPECT_EQ(&sub_message, released);
+ break;
+ case CAN_BE_NULL:
+ break;
+ }
+ delete released;
+ EXPECT_FALSE(reflection->HasField(*message, F(fields[i])));
+ }
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index 25165f3a..45519573 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -43,13 +43,17 @@
namespace google {
namespace protobuf {
-namespace unittest = protobuf_unittest;
+namespace unittest = ::protobuf_unittest;
namespace unittest_import = protobuf_unittest_import;
class TestUtil {
public:
// Set every field in the message to a unique value.
static void SetAllFields(unittest::TestAllTypes* message);
+ static void SetOptionalFields(unittest::TestAllTypes* message);
+ static void AddRepeatedFields1(unittest::TestAllTypes* message);
+ static void AddRepeatedFields2(unittest::TestAllTypes* message);
+ static void SetDefaultFields(unittest::TestAllTypes* message);
static void SetAllExtensions(unittest::TestAllExtensions* message);
static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message);
static void SetPackedFields(unittest::TestPackedTypes* message);
@@ -104,6 +108,10 @@ class TestUtil {
const unittest::TestAllTypes& message);
static void ExpectLastRepeatedExtensionsRemoved(
const unittest::TestAllExtensions& message);
+ static void ExpectLastRepeatedsReleased(
+ const unittest::TestAllTypes& message);
+ static void ExpectLastRepeatedExtensionsReleased(
+ const unittest::TestAllExtensions& message);
// Check that all repeated fields have had their first and last elements
// swapped.
@@ -132,8 +140,18 @@ class TestUtil {
void ExpectPackedClearViaReflection(const Message& message);
void RemoveLastRepeatedsViaReflection(Message* message);
+ void ReleaseLastRepeatedsViaReflection(
+ Message* message, bool expect_extensions_notnull);
void SwapRepeatedsViaReflection(Message* message);
+ enum MessageReleaseState {
+ IS_NULL,
+ CAN_BE_NULL,
+ NOT_NULL,
+ };
+ void ExpectMessagesReleasedViaReflection(
+ Message* message, MessageReleaseState expected_release_state);
+
private:
const FieldDescriptor* F(const string& name);
@@ -144,6 +162,7 @@ class TestUtil {
const FieldDescriptor* nested_b_;
const FieldDescriptor* foreign_c_;
const FieldDescriptor* import_d_;
+ const FieldDescriptor* import_e_;
const EnumValueDescriptor* nested_foo_;
const EnumValueDescriptor* nested_bar_;
diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc
index d7140e0c..9099292a 100644
--- a/src/google/protobuf/test_util_lite.cc
+++ b/src/google/protobuf/test_util_lite.cc
@@ -62,10 +62,12 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->set_optional_string ("115");
message->set_optional_bytes ("116");
- message->mutable_optionalgroup ()->set_a(117);
- message->mutable_optional_nested_message ()->set_bb(118);
- message->mutable_optional_foreign_message()->set_c(119);
- message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optionalgroup ()->set_a(117);
+ message->mutable_optional_nested_message ()->set_bb(118);
+ message->mutable_optional_foreign_message ()->set_c(119);
+ message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optional_public_import_message()->set_e(126);
+ message->mutable_optional_lazy_message ()->set_bb(127);
message->set_optional_nested_enum (unittest::TestAllTypesLite::BAZ );
message->set_optional_foreign_enum(unittest::FOREIGN_LITE_BAZ );
@@ -94,6 +96,7 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->add_repeated_nested_message ()->set_bb(218);
message->add_repeated_foreign_message()->set_c(219);
message->add_repeated_import_message ()->set_d(220);
+ message->add_repeated_lazy_message ()->set_bb(227);
message->add_repeated_nested_enum (unittest::TestAllTypesLite::BAR );
message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAR );
@@ -121,6 +124,7 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->add_repeated_nested_message ()->set_bb(318);
message->add_repeated_foreign_message()->set_c(319);
message->add_repeated_import_message ()->set_d(320);
+ message->add_repeated_lazy_message ()->set_bb(327);
message->add_repeated_nested_enum (unittest::TestAllTypesLite::BAZ );
message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAZ );
@@ -174,6 +178,7 @@ void TestUtilLite::ModifyRepeatedFields(unittest::TestAllTypesLite* message) {
message->mutable_repeated_nested_message (1)->set_bb(518);
message->mutable_repeated_foreign_message(1)->set_c(519);
message->mutable_repeated_import_message (1)->set_d(520);
+ message->mutable_repeated_lazy_message (1)->set_bb(527);
message->set_repeated_nested_enum (1, unittest::TestAllTypesLite::FOO );
message->set_repeated_foreign_enum(1, unittest::FOREIGN_LITE_FOO );
@@ -201,15 +206,19 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_TRUE(message.has_optional_string ());
EXPECT_TRUE(message.has_optional_bytes ());
- EXPECT_TRUE(message.has_optionalgroup ());
- EXPECT_TRUE(message.has_optional_nested_message ());
- EXPECT_TRUE(message.has_optional_foreign_message());
- EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optionalgroup ());
+ EXPECT_TRUE(message.has_optional_nested_message ());
+ EXPECT_TRUE(message.has_optional_foreign_message ());
+ EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optional_public_import_message());
+ EXPECT_TRUE(message.has_optional_lazy_message ());
- EXPECT_TRUE(message.optionalgroup ().has_a());
- EXPECT_TRUE(message.optional_nested_message ().has_bb());
- EXPECT_TRUE(message.optional_foreign_message().has_c());
- EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optionalgroup ().has_a());
+ EXPECT_TRUE(message.optional_nested_message ().has_bb());
+ EXPECT_TRUE(message.optional_foreign_message ().has_c());
+ EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optional_public_import_message().has_e());
+ EXPECT_TRUE(message.optional_lazy_message ().has_bb());
EXPECT_TRUE(message.has_optional_nested_enum ());
EXPECT_TRUE(message.has_optional_foreign_enum());
@@ -232,10 +241,12 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ("115", message.optional_string ());
EXPECT_EQ("116", message.optional_bytes ());
- EXPECT_EQ(117, message.optionalgroup ().a());
- EXPECT_EQ(118, message.optional_nested_message ().bb());
- EXPECT_EQ(119, message.optional_foreign_message().c());
- EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(117, message.optionalgroup ().a());
+ EXPECT_EQ(118, message.optional_nested_message ().bb());
+ EXPECT_EQ(119, message.optional_foreign_message ().c());
+ EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(126, message.optional_public_import_message().e());
+ EXPECT_EQ(127, message.optional_lazy_message ().bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.optional_nested_enum ());
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.optional_foreign_enum());
@@ -264,6 +275,7 @@ void TestUtilLite::ExpectAllFieldsSet(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -289,6 +301,7 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.repeated_nested_enum (0));
@@ -315,6 +328,7 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ(318, message.repeated_nested_message (1).bb());
EXPECT_EQ(319, message.repeated_foreign_message(1).c());
EXPECT_EQ(320, message.repeated_import_message (1).d());
+ EXPECT_EQ(327, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.repeated_foreign_enum(1));
@@ -386,10 +400,12 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_FALSE(message.has_optional_string ());
EXPECT_FALSE(message.has_optional_bytes ());
- EXPECT_FALSE(message.has_optionalgroup ());
- EXPECT_FALSE(message.has_optional_nested_message ());
- EXPECT_FALSE(message.has_optional_foreign_message());
- EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optionalgroup ());
+ EXPECT_FALSE(message.has_optional_nested_message ());
+ EXPECT_FALSE(message.has_optional_foreign_message ());
+ EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optional_public_import_message());
+ EXPECT_FALSE(message.has_optional_lazy_message ());
EXPECT_FALSE(message.has_optional_nested_enum ());
EXPECT_FALSE(message.has_optional_foreign_enum());
@@ -414,10 +430,12 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_EQ("" , message.optional_bytes ());
// Embedded messages should also be clear.
- EXPECT_FALSE(message.optionalgroup ().has_a());
- EXPECT_FALSE(message.optional_nested_message ().has_bb());
- EXPECT_FALSE(message.optional_foreign_message().has_c());
- EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optionalgroup ().has_a());
+ EXPECT_FALSE(message.optional_nested_message ().has_bb());
+ EXPECT_FALSE(message.optional_foreign_message ().has_c());
+ EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optional_public_import_message().has_e());
+ EXPECT_FALSE(message.optional_lazy_message ().has_bb());
EXPECT_EQ(0, message.optionalgroup ().a());
EXPECT_EQ(0, message.optional_nested_message ().bb());
@@ -451,6 +469,7 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_EQ(0, message.repeated_nested_message_size ());
EXPECT_EQ(0, message.repeated_foreign_message_size());
EXPECT_EQ(0, message.repeated_import_message_size ());
+ EXPECT_EQ(0, message.repeated_lazy_message_size ());
EXPECT_EQ(0, message.repeated_nested_enum_size ());
EXPECT_EQ(0, message.repeated_foreign_enum_size ());
EXPECT_EQ(0, message.repeated_import_enum_size ());
@@ -528,6 +547,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -553,6 +573,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.repeated_foreign_enum(0));
@@ -580,6 +601,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
EXPECT_EQ(518, message.repeated_nested_message (1).bb());
EXPECT_EQ(519, message.repeated_foreign_message(1).c());
EXPECT_EQ(520, message.repeated_import_message (1).d());
+ EXPECT_EQ(527, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.repeated_foreign_enum(1));
@@ -787,10 +809,12 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->SetExtension(unittest::optional_string_extension_lite , "115");
message->SetExtension(unittest::optional_bytes_extension_lite , "116");
- message->MutableExtension(unittest::optionalgroup_extension_lite )->set_a(117);
- message->MutableExtension(unittest::optional_nested_message_extension_lite )->set_bb(118);
- message->MutableExtension(unittest::optional_foreign_message_extension_lite)->set_c(119);
- message->MutableExtension(unittest::optional_import_message_extension_lite )->set_d(120);
+ message->MutableExtension(unittest::optionalgroup_extension_lite )->set_a(117);
+ message->MutableExtension(unittest::optional_nested_message_extension_lite )->set_bb(118);
+ message->MutableExtension(unittest::optional_foreign_message_extension_lite )->set_c(119);
+ message->MutableExtension(unittest::optional_import_message_extension_lite )->set_d(120);
+ message->MutableExtension(unittest::optional_public_import_message_extension_lite)->set_e(126);
+ message->MutableExtension(unittest::optional_lazy_message_extension_lite )->set_bb(127);
message->SetExtension(unittest::optional_nested_enum_extension_lite , unittest::TestAllTypesLite::BAZ );
message->SetExtension(unittest::optional_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAZ );
@@ -819,6 +843,7 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->AddExtension(unittest::repeated_nested_message_extension_lite )->set_bb(218);
message->AddExtension(unittest::repeated_foreign_message_extension_lite)->set_c(219);
message->AddExtension(unittest::repeated_import_message_extension_lite )->set_d(220);
+ message->AddExtension(unittest::repeated_lazy_message_extension_lite )->set_bb(227);
message->AddExtension(unittest::repeated_nested_enum_extension_lite , unittest::TestAllTypesLite::BAR );
message->AddExtension(unittest::repeated_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAR );
@@ -846,6 +871,7 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->AddExtension(unittest::repeated_nested_message_extension_lite )->set_bb(318);
message->AddExtension(unittest::repeated_foreign_message_extension_lite)->set_c(319);
message->AddExtension(unittest::repeated_import_message_extension_lite )->set_d(320);
+ message->AddExtension(unittest::repeated_lazy_message_extension_lite )->set_bb(327);
message->AddExtension(unittest::repeated_nested_enum_extension_lite , unittest::TestAllTypesLite::BAZ );
message->AddExtension(unittest::repeated_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAZ );
@@ -900,6 +926,7 @@ void TestUtilLite::ModifyRepeatedExtensions(
message->MutableExtension(unittest::repeated_nested_message_extension_lite , 1)->set_bb(518);
message->MutableExtension(unittest::repeated_foreign_message_extension_lite, 1)->set_c(519);
message->MutableExtension(unittest::repeated_import_message_extension_lite , 1)->set_d(520);
+ message->MutableExtension(unittest::repeated_lazy_message_extension_lite , 1)->set_bb(527);
message->SetExtension(unittest::repeated_nested_enum_extension_lite , 1, unittest::TestAllTypesLite::FOO );
message->SetExtension(unittest::repeated_foreign_enum_extension_lite, 1, unittest::FOREIGN_LITE_FOO );
@@ -927,15 +954,19 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension_lite ));
EXPECT_TRUE(message.HasExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension_lite));
- EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_public_import_message_extension_lite));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_lazy_message_extension_lite ));
- EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
- EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
- EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension_lite).has_c());
- EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension_lite ).has_c());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_public_import_message_extension_lite).has_e());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_lazy_message_extension_lite ).has_bb());
EXPECT_TRUE(message.HasExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_enum_extension_lite));
@@ -958,10 +989,12 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ("115", message.GetExtension(unittest::optional_string_extension_lite ));
EXPECT_EQ("116", message.GetExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_EQ(117, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
- EXPECT_EQ(118, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
- EXPECT_EQ(119, message.GetExtension(unittest::optional_foreign_message_extension_lite).c());
- EXPECT_EQ(120, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(117, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
+ EXPECT_EQ(118, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
+ EXPECT_EQ(119, message.GetExtension(unittest::optional_foreign_message_extension_lite ).c());
+ EXPECT_EQ(120, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(126, message.GetExtension(unittest::optional_public_import_message_extension_lite).e());
+ EXPECT_EQ(127, message.GetExtension(unittest::optional_lazy_message_extension_lite ).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.GetExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.GetExtension(unittest::optional_foreign_enum_extension_lite));
@@ -990,6 +1023,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1015,6 +1049,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension_lite , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension_lite , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
@@ -1041,6 +1076,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension_lite , 1).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension_lite , 1).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 1));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
@@ -1118,10 +1154,12 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(unittest::optional_string_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension_lite));
- EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_public_import_message_extension_lite));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_lazy_message_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_enum_extension_lite));
@@ -1146,15 +1184,19 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_EQ("" , message.GetExtension(unittest::optional_bytes_extension_lite ));
// Embedded messages should also be clear.
- EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
- EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
- EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension_lite).has_c());
- EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
-
- EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension_lite).c());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension_lite ).has_c());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_public_import_message_extension_lite).has_e());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_lazy_message_extension_lite ).has_bb());
+
+ EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension_lite ).c());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_public_import_message_extension_lite).e());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_lazy_message_extension_lite ).bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.GetExtension(unittest::optional_nested_enum_extension_lite ));
@@ -1183,6 +1225,7 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1260,6 +1303,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1285,6 +1329,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension_lite , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension_lite , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
@@ -1312,6 +1357,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
EXPECT_EQ(518, message.GetExtension(unittest::repeated_nested_message_extension_lite , 1).bb());
EXPECT_EQ(519, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1).c());
EXPECT_EQ(520, message.GetExtension(unittest::repeated_import_message_extension_lite , 1).d());
+ EXPECT_EQ(527, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 1));
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
diff --git a/src/google/protobuf/testdata/golden_message b/src/google/protobuf/testdata/golden_message
index 94898e49..4dd62cd3 100644
--- a/src/google/protobuf/testdata/golden_message
+++ b/src/google/protobuf/testdata/golden_message
Binary files differ
diff --git a/src/google/protobuf/testdata/text_format_unittest_data.txt b/src/google/protobuf/testdata/text_format_unittest_data.txt
index feea8f7b..bbe58826 100644
--- a/src/google/protobuf/testdata/text_format_unittest_data.txt
+++ b/src/google/protobuf/testdata/text_format_unittest_data.txt
@@ -30,6 +30,12 @@ optional_foreign_enum: FOREIGN_BAZ
optional_import_enum: IMPORT_BAZ
optional_string_piece: "124"
optional_cord: "125"
+optional_public_import_message {
+ e: 126
+}
+optional_lazy_message {
+ bb: 127
+}
repeated_int32: 201
repeated_int32: 301
repeated_int64: 202
@@ -94,6 +100,12 @@ repeated_string_piece: "224"
repeated_string_piece: "324"
repeated_cord: "225"
repeated_cord: "325"
+repeated_lazy_message {
+ bb: 227
+}
+repeated_lazy_message {
+ bb: 327
+}
default_int32: 401
default_int64: 402
default_uint32: 403
diff --git a/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
index 057beae8..0a217f02 100644
--- a/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
@@ -30,6 +30,12 @@
[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ
[protobuf_unittest.optional_string_piece_extension]: "124"
[protobuf_unittest.optional_cord_extension]: "125"
+[protobuf_unittest.optional_public_import_message_extension] {
+ e: 126
+}
+[protobuf_unittest.optional_lazy_message_extension] {
+ bb: 127
+}
[protobuf_unittest.repeated_int32_extension]: 201
[protobuf_unittest.repeated_int32_extension]: 301
[protobuf_unittest.repeated_int64_extension]: 202
@@ -94,6 +100,12 @@
[protobuf_unittest.repeated_string_piece_extension]: "324"
[protobuf_unittest.repeated_cord_extension]: "225"
[protobuf_unittest.repeated_cord_extension]: "325"
+[protobuf_unittest.repeated_lazy_message_extension] {
+ bb: 227
+}
+[protobuf_unittest.repeated_lazy_message_extension] {
+ bb: 327
+}
[protobuf_unittest.default_int32_extension]: 401
[protobuf_unittest.default_int64_extension]: 402
[protobuf_unittest.default_uint32_extension]: 403
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index cd094d0c..a8da6b1d 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -223,16 +223,17 @@ ScopedMemoryLog::~ScopedMemoryLog() {
active_log_ = NULL;
}
-const vector<string>& ScopedMemoryLog::GetMessages(LogLevel dummy) const {
- GOOGLE_CHECK_EQ(dummy, ERROR);
- return messages_;
+const vector<string>& ScopedMemoryLog::GetMessages(LogLevel level) {
+ GOOGLE_CHECK(level == ERROR ||
+ level == WARNING);
+ return messages_[level];
}
void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename,
int line, const string& message) {
GOOGLE_CHECK(active_log_ != NULL);
- if (level == ERROR) {
- active_log_->messages_.push_back(message);
+ if (level == ERROR || level == WARNING) {
+ active_log_->messages_[level].push_back(message);
}
}
diff --git a/src/google/protobuf/testing/googletest.h b/src/google/protobuf/testing/googletest.h
index 71444c96..6b17ae4f 100644
--- a/src/google/protobuf/testing/googletest.h
+++ b/src/google/protobuf/testing/googletest.h
@@ -34,6 +34,7 @@
#ifndef GOOGLE_PROTOBUF_GOOGLETEST_H__
#define GOOGLE_PROTOBUF_GOOGLETEST_H__
+#include <map>
#include <vector>
#include <google/protobuf/stubs/common.h>
@@ -60,6 +61,7 @@ string GetCapturedTestStderr();
// ScopedMemoryLog refers to LOGLEVEL_ERROR as just ERROR.
#undef ERROR // defend against promiscuous windows.h
static const LogLevel ERROR = LOGLEVEL_ERROR;
+static const LogLevel WARNING = LOGLEVEL_WARNING;
// Receives copies of all LOG(ERROR) messages while in scope. Sample usage:
// {
@@ -74,14 +76,11 @@ class ScopedMemoryLog {
ScopedMemoryLog();
virtual ~ScopedMemoryLog();
- // Fetches all messages logged. The internal version of this class
- // would only fetch messages at the given security level, but the protobuf
- // open source version ignores the argument since we always pass ERROR
- // anyway.
- const vector<string>& GetMessages(LogLevel dummy) const;
+ // Fetches all messages with the given severity level.
+ const vector<string>& GetMessages(LogLevel error);
private:
- vector<string> messages_;
+ map<LogLevel, vector<string> > messages_;
LogHandler* old_handler_;
static void HandleLog(LogLevel level, const char* filename, int line,
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 1494ebd7..1ee3df50 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -49,6 +49,8 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -94,6 +96,73 @@ void Message::PrintDebugString() const {
// ===========================================================================
+// Implementation of the parse information tree class.
+TextFormat::ParseInfoTree::ParseInfoTree() { }
+
+TextFormat::ParseInfoTree::~ParseInfoTree() {
+ // Remove any nested information trees, as they are owned by this tree.
+ for (NestedMap::iterator it = nested_.begin(); it != nested_.end(); ++it) {
+ STLDeleteElements(&(it->second));
+ }
+}
+
+void TextFormat::ParseInfoTree::RecordLocation(
+ const FieldDescriptor* field,
+ TextFormat::ParseLocation location) {
+ locations_[field].push_back(location);
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
+ const FieldDescriptor* field) {
+ // Owned by us in the map.
+ TextFormat::ParseInfoTree* instance = new TextFormat::ParseInfoTree();
+ vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
+ GOOGLE_CHECK(trees);
+ trees->push_back(instance);
+ return instance;
+}
+
+void CheckFieldIndex(const FieldDescriptor* field, int index) {
+ if (field == NULL) { return; }
+
+ if (field->is_repeated() && index == -1) {
+ GOOGLE_LOG(DFATAL) << "Index must be in range of repeated field values. "
+ << "Field: " << field->name();
+ } else if (!field->is_repeated() && index != -1) {
+ GOOGLE_LOG(DFATAL) << "Index must be -1 for singular fields."
+ << "Field: " << field->name();
+ }
+}
+
+TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
+ const FieldDescriptor* field, int index) const {
+ CheckFieldIndex(field, index);
+ if (index == -1) { index = 0; }
+
+ const vector<TextFormat::ParseLocation>* locations =
+ FindOrNull(locations_, field);
+ if (locations == NULL || index >= locations->size()) {
+ return TextFormat::ParseLocation();
+ }
+
+ return (*locations)[index];
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
+ const FieldDescriptor* field, int index) const {
+ CheckFieldIndex(field, index);
+ if (index == -1) { index = 0; }
+
+ const vector<TextFormat::ParseInfoTree*>* trees = FindOrNull(nested_, field);
+ if (trees == NULL || index >= trees->size()) {
+ return NULL;
+ }
+
+ return (*trees)[index];
+}
+
+
+// ===========================================================================
// Internal class for parsing an ASCII representation of a Protocol Message.
// This class makes use of the Protocol Message compiler's tokenizer found
// in //google/protobuf/io/tokenizer.h. Note that class's Parse
@@ -120,13 +189,17 @@ class TextFormat::Parser::ParserImpl {
io::ZeroCopyInputStream* input_stream,
io::ErrorCollector* error_collector,
TextFormat::Finder* finder,
- SingularOverwritePolicy singular_overwrite_policy)
+ ParseInfoTree* parse_info_tree,
+ SingularOverwritePolicy singular_overwrite_policy,
+ bool allow_unknown_field)
: error_collector_(error_collector),
finder_(finder),
+ parse_info_tree_(parse_info_tree),
tokenizer_error_collector_(this),
tokenizer_(input_stream, &tokenizer_error_collector_),
root_message_type_(root_message_type),
singular_overwrite_policy_(singular_overwrite_policy),
+ allow_unknown_field_(allow_unknown_field),
had_errors_(false) {
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats.
@@ -240,6 +313,8 @@ class TextFormat::Parser::ParserImpl {
string field_name;
const FieldDescriptor* field = NULL;
+ int start_line = tokenizer_.current().line;
+ int start_column = tokenizer_.current().column;
if (TryConsume("[")) {
// Extension.
@@ -257,10 +332,16 @@ class TextFormat::Parser::ParserImpl {
: reflection->FindKnownExtensionByName(field_name));
if (field == NULL) {
- ReportError("Extension \"" + field_name + "\" is not defined or "
- "is not an extension of \"" +
- descriptor->full_name() + "\".");
- return false;
+ if (!allow_unknown_field_) {
+ ReportError("Extension \"" + field_name + "\" is not defined or "
+ "is not an extension of \"" +
+ descriptor->full_name() + "\".");
+ return false;
+ } else {
+ ReportWarning("Extension \"" + field_name + "\" is not defined or "
+ "is not an extension of \"" +
+ descriptor->full_name() + "\".");
+ }
}
} else {
DO(ConsumeIdentifier(&field_name));
@@ -285,9 +366,30 @@ class TextFormat::Parser::ParserImpl {
}
if (field == NULL) {
- ReportError("Message type \"" + descriptor->full_name() +
- "\" has no field named \"" + field_name + "\".");
- return false;
+ if (!allow_unknown_field_) {
+ ReportError("Message type \"" + descriptor->full_name() +
+ "\" has no field named \"" + field_name + "\".");
+ return false;
+ } else {
+ ReportWarning("Message type \"" + descriptor->full_name() +
+ "\" has no field named \"" + field_name + "\".");
+ }
+ }
+ }
+
+ // Skips unknown field.
+ if (field == NULL) {
+ GOOGLE_CHECK(allow_unknown_field_);
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the begining of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
+ return SkipFieldValue();
+ } else {
+ return SkipFieldMessage();
}
}
@@ -329,12 +431,61 @@ class TextFormat::Parser::ParserImpl {
+ field_name + "\"");
}
+ // If a parse info tree exists, add the location for the parsed
+ // field.
+ if (parse_info_tree_ != NULL) {
+ parse_info_tree_->RecordLocation(field,
+ ParseLocation(start_line, start_column));
+ }
+
+ return true;
+ }
+
+ // Skips the next field including the field's name and value.
+ bool SkipField() {
+ string field_name;
+ if (TryConsume("[")) {
+ // Extension name.
+ DO(ConsumeIdentifier(&field_name));
+ while (TryConsume(".")) {
+ string part;
+ DO(ConsumeIdentifier(&part));
+ field_name += ".";
+ field_name += part;
+ }
+ DO(Consume("]"));
+ } else {
+ DO(ConsumeIdentifier(&field_name));
+ }
+
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the begining of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
+ DO(SkipFieldValue());
+ } else {
+ DO(SkipFieldMessage());
+ }
+ // For historical reasons, fields may optionally be separated by commas or
+ // semicolons.
+ TryConsume(";") || TryConsume(",");
return true;
}
bool ConsumeFieldMessage(Message* message,
const Reflection* reflection,
const FieldDescriptor* field) {
+
+ // If the parse information tree is not NULL, create a nested one
+ // for the nested message.
+ ParseInfoTree* parent = parse_info_tree_;
+ if (parent != NULL) {
+ parse_info_tree_ = parent->CreateNested(field);
+ }
+
string delimeter;
if (TryConsume("<")) {
delimeter = ">";
@@ -349,6 +500,26 @@ class TextFormat::Parser::ParserImpl {
DO(ConsumeMessage(reflection->MutableMessage(message, field),
delimeter));
}
+
+ // Reset the parse information tree.
+ parse_info_tree_ = parent;
+ return true;
+ }
+
+ // Skips the whole body of a message including the begining delimeter and
+ // the ending delimeter.
+ bool SkipFieldMessage() {
+ string delimeter;
+ if (TryConsume("<")) {
+ delimeter = ">";
+ } else {
+ DO(Consume("{"));
+ delimeter = "}";
+ }
+ while (!LookingAt(">") && !LookingAt("}")) {
+ DO(SkipField());
+ }
+ DO(Consume(delimeter));
return true;
}
@@ -479,6 +650,60 @@ class TextFormat::Parser::ParserImpl {
return true;
}
+ bool SkipFieldValue() {
+ if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ tokenizer_.Next();
+ }
+ return true;
+ }
+ // Possible field values other than string:
+ // 12345 => TYPE_INTEGER
+ // -12345 => TYPE_SYMBOL + TYPE_INTEGER
+ // 1.2345 => TYPE_FLOAT
+ // -1.2345 => TYPE_SYMBOL + TYPE_FLOAT
+ // inf => TYPE_IDENTIFIER
+ // -inf => TYPE_SYMBOL + TYPE_IDENTIFIER
+ // TYPE_INTEGER => TYPE_IDENTIFIER
+ // Divides them into two group, one with TYPE_SYMBOL
+ // and the other without:
+ // Group one:
+ // 12345 => TYPE_INTEGER
+ // 1.2345 => TYPE_FLOAT
+ // inf => TYPE_IDENTIFIER
+ // TYPE_INTEGER => TYPE_IDENTIFIER
+ // Group two:
+ // -12345 => TYPE_SYMBOL + TYPE_INTEGER
+ // -1.2345 => TYPE_SYMBOL + TYPE_FLOAT
+ // -inf => TYPE_SYMBOL + TYPE_IDENTIFIER
+ // As we can see, the field value consists of an optional '-' and one of
+ // TYPE_INTEGER, TYPE_FLOAT and TYPE_IDENTIFIER.
+ bool has_minus = TryConsume("-");
+ if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
+ !LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
+ !LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ return false;
+ }
+ // Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
+ // value while other combinations all generate valid values.
+ // We check if the value of this combination is valid here.
+ // TYPE_IDENTIFIER after a '-' should be one of the float values listed
+ // below:
+ // inf, inff, infinity, nan
+ if (has_minus && LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ string text = tokenizer_.current().text;
+ LowerString(&text);
+ if (text != "inf" &&
+ text != "infinity" &&
+ text != "nan") {
+ ReportError("Invalid float number: " + text);
+ return false;
+ }
+ }
+ tokenizer_.Next();
+ return true;
+ }
+
// Returns true if the current token's text is equal to that specified.
bool LookingAt(const string& text) {
return tokenizer_.current().text == text;
@@ -596,7 +821,8 @@ class TextFormat::Parser::ParserImpl {
} else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
string text = tokenizer_.current().text;
LowerString(&text);
- if (text == "inf" || text == "infinity") {
+ if (text == "inf" ||
+ text == "infinity") {
*value = std::numeric_limits<double>::infinity();
tokenizer_.Next();
} else if (text == "nan") {
@@ -670,10 +896,12 @@ class TextFormat::Parser::ParserImpl {
io::ErrorCollector* error_collector_;
TextFormat::Finder* finder_;
+ ParseInfoTree* parse_info_tree_;
ParserErrorCollector tokenizer_error_collector_;
io::Tokenizer tokenizer_;
const Descriptor* root_message_type_;
SingularOverwritePolicy singular_overwrite_policy_;
+ bool allow_unknown_field_;
bool had_errors_;
};
@@ -699,7 +927,7 @@ class TextFormat::Printer::TextGenerator {
~TextGenerator() {
// Only BackUp() if we're sure we've successfully called Next() at least
// once.
- if (buffer_size_ > 0) {
+ if (!failed_ && buffer_size_ > 0) {
output_->BackUp(buffer_size_);
}
}
@@ -809,7 +1037,9 @@ TextFormat::Finder::~Finder() {
TextFormat::Parser::Parser()
: error_collector_(NULL),
finder_(NULL),
- allow_partial_(false) {
+ parse_info_tree_(NULL),
+ allow_partial_(false),
+ allow_unknown_field_(false) {
}
TextFormat::Parser::~Parser() {}
@@ -818,7 +1048,9 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
Message* output) {
output->Clear();
ParserImpl parser(output->GetDescriptor(), input, error_collector_,
- finder_, ParserImpl::FORBID_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ ParserImpl::FORBID_SINGULAR_OVERWRITES,
+ allow_unknown_field_);
return MergeUsingImpl(input, output, &parser);
}
@@ -831,7 +1063,9 @@ bool TextFormat::Parser::ParseFromString(const string& input,
bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
Message* output) {
ParserImpl parser(output->GetDescriptor(), input, error_collector_,
- finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+ allow_unknown_field_);
return MergeUsingImpl(input, output, &parser);
}
@@ -861,7 +1095,9 @@ bool TextFormat::Parser::ParseFieldValueFromString(
Message* output) {
io::ArrayInputStream input_stream(input.data(), input.size());
ParserImpl parser(output->GetDescriptor(), &input_stream, error_collector_,
- finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+ allow_unknown_field_);
return parser.ParseField(field, output);
}
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 03c04910..09741397 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -38,7 +38,10 @@
#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+#include <map>
#include <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
@@ -220,6 +223,57 @@ class LIBPROTOBUF_EXPORT TextFormat {
const string& name) const = 0;
};
+ // A location in the parsed text.
+ struct ParseLocation {
+ int line;
+ int column;
+
+ ParseLocation() : line(-1), column(-1) {}
+ ParseLocation(int line_param, int column_param)
+ : line(line_param), column(column_param) {}
+ };
+
+ // Data structure which is populated with the locations of each field
+ // value parsed from the text.
+ class LIBPROTOBUF_EXPORT ParseInfoTree {
+ public:
+ ParseInfoTree();
+ ~ParseInfoTree();
+
+ // Returns the parse location for index-th value of the field in the parsed
+ // text. If none exists, returns a location with line = -1. Index should be
+ // -1 for not-repeated fields.
+ ParseLocation GetLocation(const FieldDescriptor* field, int index) const;
+
+ // Returns the parse info tree for the given field, which must be a message
+ // type. The nested information tree is owned by the root tree and will be
+ // deleted when it is deleted.
+ ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
+ int index) const;
+
+ private:
+ // Allow the text format parser to record information into the tree.
+ friend class TextFormat;
+
+ // Records the starting location of a single value for a field.
+ void RecordLocation(const FieldDescriptor* field, ParseLocation location);
+
+ // Create and records a nested tree for a nested message field.
+ ParseInfoTree* CreateNested(const FieldDescriptor* field);
+
+ // Defines the map from the index-th field descriptor to its parse location.
+ typedef map<const FieldDescriptor*, vector<ParseLocation> > LocationMap;
+
+ // Defines the map from the index-th field descriptor to the nested parse
+ // info tree.
+ typedef map<const FieldDescriptor*, vector<ParseInfoTree*> > NestedMap;
+
+ LocationMap locations_;
+ NestedMap nested_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParseInfoTree);
+ };
+
// For more control over parsing, use this class.
class LIBPROTOBUF_EXPORT Parser {
public:
@@ -248,6 +302,12 @@ class LIBPROTOBUF_EXPORT TextFormat {
finder_ = finder;
}
+ // Sets where location information about the parse will be written. If NULL
+ // (the default), then no location will be written.
+ void WriteLocationsTo(ParseInfoTree* tree) {
+ parse_info_tree_ = tree;
+ }
+
// Normally parsing fails if, after parsing, output->IsInitialized()
// returns false. Call AllowPartialMessage(true) to skip this check.
void AllowPartialMessage(bool allow) {
@@ -259,6 +319,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
const FieldDescriptor* field,
Message* output);
+
private:
// Forward declaration of an internal class used to parse text
// representations (see text_format.cc for implementation).
@@ -272,7 +333,9 @@ class LIBPROTOBUF_EXPORT TextFormat {
io::ErrorCollector* error_collector_;
Finder* finder_;
+ ParseInfoTree* parse_info_tree_;
bool allow_partial_;
+ bool allow_unknown_field_;
};
private:
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 00ea8c3c..353a5e49 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -339,6 +339,21 @@ TEST_F(TextFormatTest, PrintMessageSingleLine) {
text);
}
+TEST_F(TextFormatTest, PrintBufferTooSmall) {
+ // Test printing a message to a buffer that is too small.
+
+ protobuf_unittest::TestAllTypes message;
+
+ message.add_repeated_string("abc");
+ message.add_repeated_string("def");
+
+ char buffer[1] = "";
+ io::ArrayOutputStream output_stream(buffer, 1);
+ EXPECT_FALSE(TextFormat::Print(message, &output_stream));
+ EXPECT_EQ(buffer[0], 'r');
+ EXPECT_EQ(output_stream.ByteCount(), 1);
+}
+
TEST_F(TextFormatTest, ParseBasic) {
io::ArrayInputStream input_stream(proto_debug_string_.data(),
proto_debug_string_.size());
@@ -728,6 +743,25 @@ class TextFormatParserTest : public testing::Test {
error_collector.text_);
}
+ void ExpectSuccessAndTree(const string& input, Message* proto,
+ TextFormat::ParseInfoTree* info_tree) {
+ TextFormat::Parser parser;
+ MockErrorCollector error_collector;
+ parser.RecordErrorsTo(&error_collector);
+ parser.WriteLocationsTo(info_tree);
+
+ EXPECT_TRUE(parser.ParseFromString(input, proto));
+ }
+
+ void ExpectLocation(TextFormat::ParseInfoTree* tree,
+ const Descriptor* d, const string& field_name,
+ int index, int line, int column) {
+ TextFormat::ParseLocation location = tree->GetLocation(
+ d->FindFieldByName(field_name), index);
+ EXPECT_EQ(line, location.line);
+ EXPECT_EQ(column, location.column);
+ }
+
// An error collector which simply concatenates all its errors into a big
// block of text which can be checked.
class MockErrorCollector : public io::ErrorCollector {
@@ -749,6 +783,71 @@ class TextFormatParserTest : public testing::Test {
};
};
+TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
+ scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+ const Descriptor* d = message->GetDescriptor();
+
+ string stringData =
+ "optional_int32: 1\n"
+ "optional_int64: 2\n"
+ " optional_double: 2.4\n"
+ "repeated_int32: 5\n"
+ "repeated_int32: 10\n"
+ "optional_nested_message <\n"
+ " bb: 78\n"
+ ">\n"
+ "repeated_nested_message <\n"
+ " bb: 79\n"
+ ">\n"
+ "repeated_nested_message <\n"
+ " bb: 80\n"
+ ">";
+
+
+ TextFormat::ParseInfoTree tree;
+ ExpectSuccessAndTree(stringData, message.get(), &tree);
+
+ // Verify that the tree has the correct positions.
+ ExpectLocation(&tree, d, "optional_int32", -1, 0, 0);
+ ExpectLocation(&tree, d, "optional_int64", -1, 1, 0);
+ ExpectLocation(&tree, d, "optional_double", -1, 2, 2);
+
+ ExpectLocation(&tree, d, "repeated_int32", 0, 3, 0);
+ ExpectLocation(&tree, d, "repeated_int32", 1, 4, 0);
+
+ ExpectLocation(&tree, d, "optional_nested_message", -1, 5, 0);
+ ExpectLocation(&tree, d, "repeated_nested_message", 0, 8, 0);
+ ExpectLocation(&tree, d, "repeated_nested_message", 1, 11, 0);
+
+ // Check for fields not set. For an invalid field, the location returned
+ // should be -1, -1.
+ ExpectLocation(&tree, d, "repeated_int64", 0, -1, -1);
+ ExpectLocation(&tree, d, "repeated_int32", 6, -1, -1);
+ ExpectLocation(&tree, d, "some_unknown_field", -1, -1, -1);
+
+ // Verify inside the nested message.
+ const FieldDescriptor* nested_field =
+ d->FindFieldByName("optional_nested_message");
+
+ TextFormat::ParseInfoTree* nested_tree =
+ tree.GetTreeForNested(nested_field, -1);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 6, 2);
+
+ // Verify inside another nested message.
+ nested_field = d->FindFieldByName("repeated_nested_message");
+ nested_tree = tree.GetTreeForNested(nested_field, 0);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 9, 2);
+
+ nested_tree = tree.GetTreeForNested(nested_field, 1);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 12, 2);
+
+ // Verify a NULL tree for an unknown nested field.
+ TextFormat::ParseInfoTree* unknown_nested_tree =
+ tree.GetTreeForNested(nested_field, 2);
+
+ EXPECT_EQ(NULL, unknown_nested_tree);
+}
+
TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
const Descriptor* d = message->GetDescriptor();
@@ -921,10 +1020,10 @@ TEST_F(TextFormatParserTest, InvalidFieldValues) {
1, 16);
ExpectFailure("optional_int32: 0x80000000\n",
"Integer out of range.", 1, 17);
- ExpectFailure("optional_int32: -0x80000001\n",
- "Integer out of range.", 1, 18);
ExpectFailure("optional_int64: 0x8000000000000000\n",
"Integer out of range.", 1, 17);
+ ExpectFailure("optional_int32: -0x80000001\n",
+ "Integer out of range.", 1, 18);
ExpectFailure("optional_int64: -0x8000000000000001\n",
"Integer out of range.", 1, 18);
@@ -1136,6 +1235,7 @@ TEST_F(TextFormatMessageSetTest, Deserialize) {
EXPECT_EQ(2, descriptors.size());
}
+
} // namespace text_format_unittest
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 97ec6747..0305be65 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -103,6 +103,12 @@ message TestAllTypes {
optional string optional_string_piece = 24 [ctype=STRING_PIECE];
optional string optional_cord = 25 [ctype=CORD];
+ // Defined in unittest_import_public.proto
+ optional protobuf_unittest_import.PublicImportMessage
+ optional_public_import_message = 26;
+
+ optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
@@ -135,6 +141,8 @@ message TestAllTypes {
repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
repeated string repeated_cord = 55 [ctype=CORD];
+ repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32 = 61 [default = 41 ];
optional int64 default_int64 = 62 [default = 42 ];
@@ -216,6 +224,12 @@ extend TestAllExtensions {
optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
optional string optional_cord_extension = 25 [ctype=CORD];
+ optional protobuf_unittest_import.PublicImportMessage
+ optional_public_import_message_extension = 26;
+
+ optional TestAllTypes.NestedMessage
+ optional_lazy_message_extension = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32_extension = 31;
repeated int64 repeated_int64_extension = 32;
@@ -250,6 +264,9 @@ extend TestAllExtensions {
repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
repeated string repeated_cord_extension = 55 [ctype=CORD];
+ repeated TestAllTypes.NestedMessage
+ repeated_lazy_message_extension = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32_extension = 61 [default = 41 ];
optional int64 default_int64_extension = 62 [default = 42 ];
@@ -397,6 +414,13 @@ message TestDupFieldNumber { // NO_PROTO1
optional group Bar = 3 { optional int32 a = 1; } // NO_PROTO1
} // NO_PROTO1
+// Additional messages for testing lazy fields.
+message TestEagerMessage {
+ optional TestAllTypes sub_message = 1 [lazy=false];
+}
+message TestLazyMessage {
+ optional TestAllTypes sub_message = 1 [lazy=true];
+}
// Needed for a Python test.
message TestNestedMessageHasBits {
@@ -470,6 +494,8 @@ message TestExtremeDefaultValues {
optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
optional int32 small_int32 = 4 [default = -0x7FFFFFFF];
optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF];
+ optional int32 really_small_int32 = 21 [default = -0x80000000];
+ optional int64 really_small_int64 = 22 [default = -0x8000000000000000];
// The default value here is UTF-8 for "\u1234". (We could also just type
// the UTF-8 text directly into this text file rather than escape it, but
@@ -500,6 +526,14 @@ message TestExtremeDefaultValues {
// Note that in .proto file, "\?" is a valid way to escape ? in string
// literals.
optional string cpp_trigraph = 20 [default = "? \? ?? \?? \??? ??/ ?\?-"];
+
+ // String defaults containing the character '\000'
+ optional string string_with_zero = 23 [default = "hel\000lo"];
+ optional bytes bytes_with_zero = 24 [default = "wor\000ld"];
+ optional string string_piece_with_zero = 25 [ctype=STRING_PIECE,
+ default="ab\000c"];
+ optional string cord_with_zero = 26 [ctype=CORD,
+ default="12\0003"];
}
message SparseEnumMessage {
@@ -511,10 +545,19 @@ message OneString {
optional string data = 1;
}
+message MoreString {
+ repeated string data = 1;
+}
+
message OneBytes {
optional bytes data = 1;
}
+message MoreBytes {
+ repeated bytes data = 1;
+}
+
+
// Test messages for packed fields
message TestPackedTypes {
@@ -615,11 +658,56 @@ message TestRepeatedScalarDifferentTagSizes {
repeated uint64 repeated_uint64 = 262143;
}
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+message TestParsingMerge {
+ // RepeatedFieldsGenerator defines matching field types as TestParsingMerge,
+ // except that all fields are repeated. In the tests, we will serialize the
+ // RepeatedFieldsGenerator to bytes, and parse the bytes to TestParsingMerge.
+ // Repeated fields in RepeatedFieldsGenerator are expected to be merged into
+ // the corresponding required/optional fields in TestParsingMerge.
+ message RepeatedFieldsGenerator {
+ repeated TestAllTypes field1 = 1;
+ repeated TestAllTypes field2 = 2;
+ repeated TestAllTypes field3 = 3;
+ repeated group Group1 = 10 {
+ optional TestAllTypes field1 = 11;
+ }
+ repeated group Group2 = 20 {
+ optional TestAllTypes field1 = 21;
+ }
+ repeated TestAllTypes ext1 = 1000;
+ repeated TestAllTypes ext2 = 1001;
+ }
+ required TestAllTypes required_all_types = 1;
+ optional TestAllTypes optional_all_types = 2;
+ repeated TestAllTypes repeated_all_types = 3;
+ optional group OptionalGroup = 10 {
+ optional TestAllTypes optional_group_all_types = 11;
+ }
+ repeated group RepeatedGroup = 20 {
+ optional TestAllTypes repeated_group_all_types = 21;
+ }
+ extensions 1000 to max;
+ extend TestParsingMerge {
+ optional TestAllTypes optional_ext = 1000;
+ repeated TestAllTypes repeated_ext = 1001;
+ }
+}
+
+message TestCommentInjectionMessage {
+ // */ <- This should not close the generated doc comment
+ optional string a = 1 [default="*/ <- Neither should this."];
+}
+
// Test that RPC services work.
message FooRequest {}
message FooResponse {}
+message FooClientMessage {}
+message FooServerMessage{}
+
service TestService {
rpc Foo(FooRequest) returns (FooResponse);
rpc Bar(BarRequest) returns (BarResponse);
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index a610785f..e591d294 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -116,6 +116,12 @@ message CustomOptionFooRequest {
message CustomOptionFooResponse {
}
+message CustomOptionFooClientMessage {
+}
+
+message CustomOptionFooServerMessage {
+}
+
service TestServiceWithCustomOptions {
option (service_opt1) = -9876543210;
@@ -364,3 +370,18 @@ enum AggregateEnum {
option (enumopt) = { s:'EnumAnnotation' };
VALUE = 1 [(enumvalopt) = { s:'EnumValueAnnotation' }];
}
+
+// Test custom options for nested type.
+message NestedOptionType {
+ message NestedMessage {
+ option (message_opt1) = 1001;
+ optional int32 nested_field = 1 [(field_opt1) = 1002];
+ }
+ enum NestedEnum {
+ option (enum_opt1) = 1003;
+ NESTED_ENUM_VALUE = 1 [(enum_value_opt1) = 1004];
+ }
+ extend google.protobuf.FileOptions {
+ optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
+ }
+}
diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto
index cd533ecd..c115b111 100644
--- a/src/google/protobuf/unittest_import.proto
+++ b/src/google/protobuf/unittest_import.proto
@@ -49,6 +49,9 @@ option java_package = "com.google.protobuf.test";
// Do not set a java_outer_classname here to verify that Proto2 works without
// one.
+// Test public import
+import public "google/protobuf/unittest_import_public.proto";
+
message ImportMessage {
optional int32 d = 1;
}
diff --git a/src/google/protobuf/unittest_import_lite.proto b/src/google/protobuf/unittest_import_lite.proto
index ebaab5c0..81b117fe 100644
--- a/src/google/protobuf/unittest_import_lite.proto
+++ b/src/google/protobuf/unittest_import_lite.proto
@@ -38,6 +38,8 @@ option optimize_for = LITE_RUNTIME;
option java_package = "com.google.protobuf";
+import public "google/protobuf/unittest_import_public_lite.proto";
+
message ImportMessageLite {
optional int32 d = 1;
}
diff --git a/src/google/protobuf/unittest_import_public.proto b/src/google/protobuf/unittest_import_public.proto
new file mode 100644
index 00000000..ea5d1b13
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+
+message PublicImportMessage {
+ optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_import_public_lite.proto b/src/google/protobuf/unittest_import_public_lite.proto
new file mode 100644
index 00000000..d077563c
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public_lite.proto
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+message PublicImportMessageLite {
+ optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
index cca6b497..a1764aac 100644
--- a/src/google/protobuf/unittest_lite.proto
+++ b/src/google/protobuf/unittest_lite.proto
@@ -85,6 +85,12 @@ message TestAllTypesLite {
optional string optional_string_piece = 24 [ctype=STRING_PIECE];
optional string optional_cord = 25 [ctype=CORD];
+ // Defined in unittest_import_public.proto
+ optional protobuf_unittest_import.PublicImportMessageLite
+ optional_public_import_message = 26;
+
+ optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
@@ -118,6 +124,8 @@ message TestAllTypesLite {
repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
repeated string repeated_cord = 55 [ctype=CORD];
+ repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32 = 61 [default = 41 ];
optional int64 default_int64 = 62 [default = 42 ];
@@ -213,6 +221,12 @@ extend TestAllExtensionsLite {
[ctype=STRING_PIECE];
optional string optional_cord_extension_lite = 25 [ctype=CORD];
+ optional protobuf_unittest_import.PublicImportMessageLite
+ optional_public_import_message_extension_lite = 26;
+
+ optional TestAllTypesLite.NestedMessage
+ optional_lazy_message_extension_lite = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32_extension_lite = 31;
repeated int64 repeated_int64_extension_lite = 32;
@@ -249,6 +263,9 @@ extend TestAllExtensionsLite {
[ctype=STRING_PIECE];
repeated string repeated_cord_extension_lite = 55 [ctype=CORD];
+ repeated TestAllTypesLite.NestedMessage
+ repeated_lazy_message_extension_lite = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32_extension_lite = 61 [default = 41 ];
optional int64 default_int64_extension_lite = 62 [default = 42 ];
@@ -310,3 +327,34 @@ message TestNestedExtensionLite {
message TestDeprecatedLite {
optional int32 deprecated_field = 1 [deprecated = true];
}
+
+// See the comments of the same type in unittest.proto.
+message TestParsingMergeLite {
+ message RepeatedFieldsGenerator {
+ repeated TestAllTypesLite field1 = 1;
+ repeated TestAllTypesLite field2 = 2;
+ repeated TestAllTypesLite field3 = 3;
+ repeated group Group1 = 10 {
+ optional TestAllTypesLite field1 = 11;
+ }
+ repeated group Group2 = 20 {
+ optional TestAllTypesLite field1 = 21;
+ }
+ repeated TestAllTypesLite ext1 = 1000;
+ repeated TestAllTypesLite ext2 = 1001;
+ }
+ required TestAllTypesLite required_all_types = 1;
+ optional TestAllTypesLite optional_all_types = 2;
+ repeated TestAllTypesLite repeated_all_types = 3;
+ optional group OptionalGroup = 10 {
+ optional TestAllTypesLite optional_group_all_types = 11;
+ }
+ repeated group RepeatedGroup = 20 {
+ optional TestAllTypesLite repeated_group_all_types = 21;
+ }
+ extensions 1000 to max;
+ extend TestParsingMergeLite {
+ optional TestAllTypesLite optional_ext = 1000;
+ repeated TestAllTypesLite repeated_ext = 1001;
+ }
+}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index e1f8b838..841433d5 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -32,13 +32,14 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+
+#include <google/protobuf/stubs/common.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>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -59,6 +60,14 @@ void UnknownFieldSet::ClearFallback() {
fields_->clear();
}
+void UnknownFieldSet::ClearAndFreeMemory() {
+ if (fields_ != NULL) {
+ Clear();
+ delete fields_;
+ fields_ = NULL;
+ }
+}
+
void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
for (int i = 0; i < other.field_count(); i++) {
AddField(other.field(i));
@@ -73,8 +82,9 @@ int UnknownFieldSet::SpaceUsedExcludingSelf() const {
const UnknownField& field = (*fields_)[i];
switch (field.type()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
- total_size += sizeof(*field.length_delimited_) +
- internal::StringSpaceUsedExcludingSelf(*field.length_delimited_);
+ total_size += sizeof(*field.length_delimited_.string_value_) +
+ internal::StringSpaceUsedExcludingSelf(
+ *field.length_delimited_.string_value_);
break;
case UnknownField::TYPE_GROUP:
total_size += field.group_->SpaceUsed();
@@ -122,11 +132,12 @@ string* UnknownFieldSet::AddLengthDelimited(int number) {
UnknownField field;
field.number_ = number;
field.type_ = UnknownField::TYPE_LENGTH_DELIMITED;
- field.length_delimited_ = new string;
+ field.length_delimited_.string_value_ = new string;
fields_->push_back(field);
- return field.length_delimited_;
+ return field.length_delimited_.string_value_;
}
+
UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
@@ -143,6 +154,39 @@ void UnknownFieldSet::AddField(const UnknownField& field) {
fields_->back().DeepCopy();
}
+void UnknownFieldSet::DeleteSubrange(int start, int num) {
+ GOOGLE_DCHECK(fields_ != NULL);
+ // Delete the specified fields.
+ for (int i = 0; i < num; ++i) {
+ (*fields_)[i + start].Delete();
+ }
+ // Slide down the remaining fields.
+ for (int i = start + num; i < fields_->size(); ++i) {
+ (*fields_)[i - num] = (*fields_)[i];
+ }
+ // Pop off the # of deleted fields.
+ for (int i = 0; i < num; ++i) {
+ fields_->pop_back();
+ }
+}
+
+void UnknownFieldSet::DeleteByNumber(int number) {
+ if (fields_ == NULL) return;
+ int left = 0; // The number of fields left after deletion.
+ for (int i = 0; i < fields_->size(); ++i) {
+ UnknownField* field = &(*fields_)[i];
+ if (field->number() == number) {
+ field->Delete();
+ } else {
+ if (i != left) {
+ (*fields_)[left] = (*fields_)[i];
+ }
+ ++left;
+ }
+ }
+ fields_->resize(left);
+}
+
bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
UnknownFieldSet other;
@@ -174,7 +218,7 @@ bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
void UnknownField::Delete() {
switch (type()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
- delete length_delimited_;
+ delete length_delimited_.string_value_;
break;
case UnknownField::TYPE_GROUP:
delete group_;
@@ -187,7 +231,8 @@ void UnknownField::Delete() {
void UnknownField::DeepCopy() {
switch (type()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
- length_delimited_ = new string(*length_delimited_);
+ length_delimited_.string_value_ = new string(
+ *length_delimited_.string_value_);
break;
case UnknownField::TYPE_GROUP: {
UnknownFieldSet* group = new UnknownFieldSet;
@@ -200,5 +245,22 @@ void UnknownField::DeepCopy() {
}
}
+
+void UnknownField::SerializeLengthDelimitedNoTag(
+ io::CodedOutputStream* output) const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type_);
+ const string& data = *length_delimited_.string_value_;
+ output->WriteVarint32(data.size());
+ output->WriteString(data);
+}
+
+uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type_);
+ const string& data = *length_delimited_.string_value_;
+ target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
+ target = io::CodedOutputStream::WriteStringToArray(data, target);
+ return target;
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 84c2e2b6..825bba83 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -38,12 +38,24 @@
#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+#include <assert.h>
#include <string>
#include <vector>
-#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/common.h>
+// TODO(jasonh): some people seem to rely on protobufs to include this for them!
namespace google {
namespace protobuf {
+ namespace io {
+ class CodedInputStream; // coded_stream.h
+ class CodedOutputStream; // coded_stream.h
+ class ZeroCopyInputStream; // zero_copy_stream.h
+ }
+ namespace internal {
+ class WireFormat; // wire_format.h
+ class UnknownFieldSetFieldSkipperUsingCord;
+ // extension_set_heavy.cc
+ }
class Message; // message.h
class UnknownField; // below
@@ -68,6 +80,9 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Remove all fields.
inline void Clear();
+ // Remove all fields and deallocate internal data objects
+ void ClearAndFreeMemory();
+
// Is this set empty?
inline bool empty() const;
@@ -107,6 +122,15 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Adds an unknown field from another set.
void AddField(const UnknownField& field);
+ // Delete fields with indices in the range [start .. start+num-1].
+ // Caution: implementation moves all fields with indices [start+num .. ].
+ void DeleteSubrange(int start, int num);
+
+ // Delete all fields with a specific field number. The order of left fields
+ // is preserved.
+ // Caution: implementation moves all fields after the first deleted field.
+ void DeleteByNumber(int number);
+
// Parsing helpers -------------------------------------------------
// These work exactly like the similarly-named methods of Message.
@@ -119,6 +143,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
}
private:
+
void ClearFallback();
vector<UnknownField>* fields_;
@@ -159,6 +184,15 @@ class LIBPROTOBUF_EXPORT UnknownField {
inline string* mutable_length_delimited();
inline UnknownFieldSet* mutable_group();
+ // Serialization API.
+ // These methods can take advantage of the underlying implementation and may
+ // archieve a better performance than using getters to retrieve the data and
+ // do the serialization yourself.
+ void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const;
+ uint8* SerializeLengthDelimitedNoTagToArray(uint8* target) const;
+
+ inline int GetLengthDelimitedSize() const;
+
private:
friend class UnknownFieldSet;
@@ -168,13 +202,16 @@ class LIBPROTOBUF_EXPORT UnknownField {
// Make a deep copy of any pointers in this UnknownField.
void DeepCopy();
+
unsigned int number_ : 29;
unsigned int type_ : 3;
union {
uint64 varint_;
uint32 fixed32_;
uint64 fixed64_;
- string* length_delimited_;
+ mutable union {
+ string* string_value_;
+ } length_delimited_;
UnknownFieldSet* group_;
};
};
@@ -211,57 +248,63 @@ inline void UnknownFieldSet::AddLengthDelimited(
AddLengthDelimited(number)->assign(value);
}
+
inline int UnknownField::number() const { return number_; }
inline UnknownField::Type UnknownField::type() const {
return static_cast<Type>(type_);
}
inline uint64 UnknownField::varint () const {
- GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
+ assert(type_ == TYPE_VARINT);
return varint_;
}
inline uint32 UnknownField::fixed32() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
+ assert(type_ == TYPE_FIXED32);
return fixed32_;
}
inline uint64 UnknownField::fixed64() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
+ assert(type_ == TYPE_FIXED64);
return fixed64_;
}
inline const string& UnknownField::length_delimited() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- return *length_delimited_;
+ assert(type_ == TYPE_LENGTH_DELIMITED);
+ return *length_delimited_.string_value_;
}
inline const UnknownFieldSet& UnknownField::group() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
+ assert(type_ == TYPE_GROUP);
return *group_;
}
inline void UnknownField::set_varint(uint64 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
+ assert(type_ == TYPE_VARINT);
varint_ = value;
}
inline void UnknownField::set_fixed32(uint32 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
+ assert(type_ == TYPE_FIXED32);
fixed32_ = value;
}
inline void UnknownField::set_fixed64(uint64 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
+ assert(type_ == TYPE_FIXED64);
fixed64_ = value;
}
inline void UnknownField::set_length_delimited(const string& value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- length_delimited_->assign(value);
+ assert(type_ == TYPE_LENGTH_DELIMITED);
+ length_delimited_.string_value_->assign(value);
}
inline string* UnknownField::mutable_length_delimited() {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- return length_delimited_;
+ assert(type_ == TYPE_LENGTH_DELIMITED);
+ return length_delimited_.string_value_;
}
inline UnknownFieldSet* UnknownField::mutable_group() {
- GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
+ assert(type_ == TYPE_GROUP);
return group_;
}
+inline int UnknownField::GetLengthDelimitedSize() const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type_);
+ return length_delimited_.string_value_->size();
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index 1235c9ee..c6b8769f 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -46,15 +46,13 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
using internal::WireFormat;
-namespace {
-
class UnknownFieldSetTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -107,6 +105,8 @@ class UnknownFieldSetTest : public testing::Test {
UnknownFieldSet* unknown_fields_;
};
+namespace {
+
TEST_F(UnknownFieldSetTest, AllFieldsPresent) {
// All fields of TestAllTypes should be present, in numeric order (because
// that's the order we parsed them in). Fields that are not valid field
@@ -297,12 +297,21 @@ TEST_F(UnknownFieldSetTest, MergeFrom) {
destination.DebugString());
}
+
TEST_F(UnknownFieldSetTest, Clear) {
// Clear the set.
empty_message_.Clear();
EXPECT_EQ(0, unknown_fields_->field_count());
}
+TEST_F(UnknownFieldSetTest, ClearAndFreeMemory) {
+ EXPECT_GT(unknown_fields_->field_count(), 0);
+ unknown_fields_->ClearAndFreeMemory();
+ EXPECT_EQ(0, unknown_fields_->field_count());
+ unknown_fields_->AddVarint(123456, 654321);
+ EXPECT_EQ(1, unknown_fields_->field_count());
+}
+
TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) {
// Test mixing known and unknown fields when parsing.
@@ -498,6 +507,7 @@ TEST_F(UnknownFieldSetTest, SpaceUsed) {
EXPECT_LT(base_size, empty_message.SpaceUsed());
}
+
TEST_F(UnknownFieldSetTest, Empty) {
UnknownFieldSet unknown_fields;
EXPECT_TRUE(unknown_fields.empty());
@@ -507,6 +517,78 @@ TEST_F(UnknownFieldSetTest, Empty) {
EXPECT_TRUE(unknown_fields.empty());
}
+TEST_F(UnknownFieldSetTest, DeleteSubrange) {
+ // Exhaustively test the deletion of every possible subrange in arrays of all
+ // sizes from 0 through 9.
+ for (int size = 0; size < 10; ++size) {
+ for (int num = 0; num <= size; ++num) {
+ for (int start = 0; start < size - num; ++start) {
+ // Create a set with "size" fields.
+ UnknownFieldSet unknown;
+ for (int i = 0; i < size; ++i) {
+ unknown.AddFixed32(i, i);
+ }
+ // Delete the specified subrange.
+ unknown.DeleteSubrange(start, num);
+ // Make sure the resulting field values are still correct.
+ EXPECT_EQ(size - num, unknown.field_count());
+ for (int i = 0; i < unknown.field_count(); ++i) {
+ if (i < start) {
+ EXPECT_EQ(i, unknown.field(i).fixed32());
+ } else {
+ EXPECT_EQ(i + num, unknown.field(i).fixed32());
+ }
+ }
+ }
+ }
+ }
+}
+
+void CheckDeleteByNumber(const vector<int>& field_numbers, int deleted_number,
+ const vector<int>& expected_field_nubmers) {
+ UnknownFieldSet unknown_fields;
+ for (int i = 0; i < field_numbers.size(); ++i) {
+ unknown_fields.AddFixed32(field_numbers[i], i);
+ }
+ unknown_fields.DeleteByNumber(deleted_number);
+ ASSERT_EQ(expected_field_nubmers.size(), unknown_fields.field_count());
+ for (int i = 0; i < expected_field_nubmers.size(); ++i) {
+ EXPECT_EQ(expected_field_nubmers[i],
+ unknown_fields.field(i).number());
+ }
+}
+
+#define MAKE_VECTOR(x) vector<int>(x, x + GOOGLE_ARRAYSIZE(x))
+TEST_F(UnknownFieldSetTest, DeleteByNumber) {
+ CheckDeleteByNumber(vector<int>(), 1, vector<int>());
+ static const int kTestFieldNumbers1[] = {1, 2, 3};
+ static const int kFieldNumberToDelete1 = 1;
+ static const int kExpectedFieldNumbers1[] = {2, 3};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers1), kFieldNumberToDelete1,
+ MAKE_VECTOR(kExpectedFieldNumbers1));
+ static const int kTestFieldNumbers2[] = {1, 2, 3};
+ static const int kFieldNumberToDelete2 = 2;
+ static const int kExpectedFieldNumbers2[] = {1, 3};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers2), kFieldNumberToDelete2,
+ MAKE_VECTOR(kExpectedFieldNumbers2));
+ static const int kTestFieldNumbers3[] = {1, 2, 3};
+ static const int kFieldNumberToDelete3 = 3;
+ static const int kExpectedFieldNumbers3[] = {1, 2};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers3), kFieldNumberToDelete3,
+ MAKE_VECTOR(kExpectedFieldNumbers3));
+ static const int kTestFieldNumbers4[] = {1, 2, 1, 4, 1};
+ static const int kFieldNumberToDelete4 = 1;
+ static const int kExpectedFieldNumbers4[] = {2, 4};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers4), kFieldNumberToDelete4,
+ MAKE_VECTOR(kExpectedFieldNumbers4));
+ static const int kTestFieldNumbers5[] = {1, 2, 3, 4, 5};
+ static const int kFieldNumberToDelete5 = 6;
+ static const int kExpectedFieldNumbers5[] = {1, 2, 3, 4, 5};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers5), kFieldNumberToDelete5,
+ MAKE_VECTOR(kExpectedFieldNumbers5));
+}
+#undef MAKE_VECTOR
} // namespace
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 831a5794..ead763b1 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -48,12 +48,11 @@
#include <google/protobuf/unknown_field_set.h>
+
namespace google {
namespace protobuf {
namespace internal {
-using internal::WireFormatLite;
-
namespace {
// This function turns out to be convenient when using some macros later.
@@ -239,8 +238,6 @@ void WireFormat::SerializeUnknownMessageSetItems(
// The only unknown fields that are allowed to exist in a MessageSet are
// messages, which are length-delimited.
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
- const string& data = field.length_delimited();
-
// Start group.
output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag);
@@ -250,8 +247,7 @@ void WireFormat::SerializeUnknownMessageSetItems(
// Write message.
output->WriteVarint32(WireFormatLite::kMessageSetMessageTag);
- output->WriteVarint32(data.size());
- output->WriteString(data);
+ field.SerializeLengthDelimitedNoTag(output);
// End group.
output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag);
@@ -268,8 +264,6 @@ uint8* WireFormat::SerializeUnknownMessageSetItemsToArray(
// The only unknown fields that are allowed to exist in a MessageSet are
// messages, which are length-delimited.
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
- const string& data = field.length_delimited();
-
// Start group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemStartTag, target);
@@ -283,8 +277,7 @@ uint8* WireFormat::SerializeUnknownMessageSetItemsToArray(
// Write message.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetMessageTag, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
- target = io::CodedOutputStream::WriteStringToArray(data, target);
+ target = field.SerializeLengthDelimitedNoTagToArray(target);
// End group.
target = io::CodedOutputStream::WriteTagToArray(
@@ -354,9 +347,10 @@ int WireFormat::ComputeUnknownMessageSetItemsSize(
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
size += WireFormatLite::kMessageSetItemTagsSize;
size += io::CodedOutputStream::VarintSize32(field.number());
- size += io::CodedOutputStream::VarintSize32(
- field.length_delimited().size());
- size += field.length_delimited().size();
+
+ int field_size = field.GetLengthDelimitedSize();
+ size += io::CodedOutputStream::VarintSize32(field_size);
+ size += field_size;
}
}
@@ -642,10 +636,7 @@ bool WireFormat::ParseAndMergeMessageSetItem(
const FieldDescriptor* field = NULL;
// If we see message data before the type_id, we'll append it to this so
- // we can parse it later. This will probably never happen in practice,
- // as no MessageSet encoder I know of writes the message before the type ID.
- // But, it's technically valid so we should allow it.
- // TODO(kenton): Use a Cord instead? Do I care?
+ // we can parse it later.
string message_data;
while (true) {
@@ -683,7 +674,10 @@ bool WireFormat::ParseAndMergeMessageSetItem(
uint32 length;
if (!input->ReadVarint32(&length)) return false;
if (!input->ReadString(&temp, length)) return false;
- message_data.append(temp);
+ io::StringOutputStream output_stream(&message_data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteVarint32(length);
+ coded_output.WriteString(temp);
} else {
// Already saw type_id, so we can parse this directly.
if (!ParseAndMergeField(fake_tag, field, message, input)) {
@@ -1056,10 +1050,10 @@ void WireFormat::VerifyUTF8StringFallback(const char* data,
break;
// no default case: have the compiler warn if a case is not covered.
}
- GOOGLE_LOG(ERROR) << "Encountered string containing invalid UTF-8 data while "
+ GOOGLE_LOG(ERROR) << "String field contains invalid UTF-8 data when "
<< operation_str
- << " protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.";
+ << " a protocol buffer. Use the 'bytes' type if you intend to "
+ "send raw bytes.";
}
}
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index c7539250..6c3f44a4 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -40,6 +40,7 @@
#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
#include <string>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
@@ -253,7 +254,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper {
virtual bool SkipMessage(io::CodedInputStream* input);
virtual void SkipUnknownEnum(int field_number, int value);
- private:
+ protected:
UnknownFieldSet* unknown_fields_;
};
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index dbd29b47..738fc421 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -40,7 +40,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream_inl.h>
#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
namespace google {
namespace protobuf {
@@ -281,12 +281,14 @@ void WireFormatLite::WriteString(int field_number, const string& value,
io::CodedOutputStream* output) {
// String is for UTF-8 text only
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
output->WriteVarint32(value.size());
output->WriteString(value);
}
void WireFormatLite::WriteBytes(int field_number, const string& value,
io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
output->WriteVarint32(value.size());
output->WriteString(value);
}
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index e3d5b2d8..cb4fc918 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -41,16 +41,14 @@
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
#include <string>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message_lite.h>
+#include <google/protobuf/io/coded_stream.h> // for CodedOutputStream::Varint32Size
namespace google {
namespace protobuf {
template <typename T> class RepeatedField; // repeated_field.h
- namespace io {
- class CodedInputStream; // coded_stream.h
- class CodedOutputStream; // coded_stream.h
- }
}
namespace protobuf {
@@ -477,6 +475,10 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
template<typename MessageType>
static inline int MessageSizeNoVirtual(const MessageType& value);
+ // Given the length of data, calculate the byte size of the data on the
+ // wire if we encode the data as a length delimited field.
+ static inline int LengthDelimitedSize(int length);
+
private:
// A helper method for the repeated primitive reader. This method has
// optimizations for primitive types that have fixed size on the wire, and
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 103b0bd0..0f97386d 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -41,7 +41,6 @@
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/io/coded_stream.h>
@@ -749,8 +748,7 @@ inline int WireFormatLite::GroupSize(const MessageLite& value) {
return value.ByteSize();
}
inline int WireFormatLite::MessageSize(const MessageLite& value) {
- int size = value.ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+ return LengthDelimitedSize(value.ByteSize());
}
// See comment on ReadGroupNoVirtual to understand the need for this template
@@ -763,8 +761,12 @@ inline int WireFormatLite::GroupSizeNoVirtual(
template<typename MessageType_WorkAroundCppLookupDefect>
inline int WireFormatLite::MessageSizeNoVirtual(
const MessageType_WorkAroundCppLookupDefect& value) {
- int size = value.MessageType_WorkAroundCppLookupDefect::ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+ return LengthDelimitedSize(
+ value.MessageType_WorkAroundCppLookupDefect::ByteSize());
+}
+
+inline int WireFormatLite::LengthDelimitedSize(int length) {
+ return io::CodedOutputStream::VarintSize32(length) + length;
}
} // namespace internal
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 867970c4..98c066a2 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -44,7 +44,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -480,6 +480,54 @@ TEST(WireFormatTest, ParseMessageSet) {
EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
}
+TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) {
+ string data;
+ {
+ unittest::TestMessageSetExtension1 message;
+ message.set_i(123);
+ // Build a MessageSet manually with its message content put before its
+ // type_id.
+ io::StringOutputStream output_stream(&data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteTag(WireFormatLite::kMessageSetItemStartTag);
+ // Write the message content first.
+ WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ &coded_output);
+ coded_output.WriteVarint32(message.ByteSize());
+ message.SerializeWithCachedSizes(&coded_output);
+ // Write the type id.
+ uint32_t type_id = message.GetDescriptor()->extension(0)->number();
+ WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+ type_id, &coded_output);
+ coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
+ }
+ {
+ unittest::TestMessageSet message_set;
+ ASSERT_TRUE(message_set.ParseFromString(data));
+
+ EXPECT_EQ(123, message_set.GetExtension(
+ unittest::TestMessageSetExtension1::message_set_extension).i());
+ }
+ {
+ // Test parse the message via Reflection.
+ unittest::TestMessageSet message_set;
+ io::CodedInputStream input(
+ reinterpret_cast<const uint8*>(data.data()), data.size());
+ EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
+ EXPECT_TRUE(input.ConsumedEntireMessage());
+
+ EXPECT_EQ(123, message_set.GetExtension(
+ unittest::TestMessageSetExtension1::message_set_extension).i());
+ }
+}
+
+TEST(WireFormatTest, ParseBrokenMessageSet) {
+ unittest::TestMessageSet message_set;
+ string input("goodbye"); // Invalid wire format data.
+ EXPECT_FALSE(message_set.ParseFromString(input));
+}
+
TEST(WireFormatTest, RecursionLimit) {
unittest::TestRecursiveMessage message;
message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
@@ -800,6 +848,10 @@ bool ReadMessage(const string &wire_buffer, T *message) {
return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
}
+bool StartsWith(const string& s, const string& prefix) {
+ return s.substr(0, prefix.length()) == prefix;
+}
+
TEST(Utf8ValidationTest, WriteInvalidUTF8String) {
string wire_buffer;
protobuf_unittest::OneString input;
@@ -811,11 +863,10 @@ TEST(Utf8ValidationTest, WriteInvalidUTF8String) {
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_EQ("Encountered string containing invalid UTF-8 data while "
- "serializing protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.",
- errors[0]);
-
+ EXPECT_TRUE(StartsWith(errors[0],
+ "String field contains invalid UTF-8 data when "
+ "serializing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
#else
ASSERT_EQ(0, errors.size());
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
@@ -834,10 +885,10 @@ TEST(Utf8ValidationTest, ReadInvalidUTF8String) {
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_EQ("Encountered string containing invalid UTF-8 data while "
- "parsing protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.",
- errors[0]);
+ EXPECT_TRUE(StartsWith(errors[0],
+ "String field contains invalid UTF-8 data when "
+ "parsing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
#else
ASSERT_EQ(0, errors.size());
@@ -899,6 +950,28 @@ TEST(Utf8ValidationTest, ReadArbitraryBytes) {
EXPECT_EQ(input.data(), output.data());
}
+TEST(Utf8ValidationTest, ParseRepeatedString) {
+ protobuf_unittest::MoreBytes input;
+ input.add_data(kValidUTF8String);
+ input.add_data(kInvalidUTF8String);
+ input.add_data(kInvalidUTF8String);
+ string wire_buffer = input.SerializeAsString();
+
+ protobuf_unittest::MoreString output;
+ vector<string> errors;
+ {
+ ScopedMemoryLog log;
+ ReadMessage(wire_buffer, &output);
+ errors = log.GetMessages(ERROR);
+ }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ ASSERT_EQ(2, errors.size());
+#else
+ ASSERT_EQ(0, errors.size());
+#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ EXPECT_EQ(wire_buffer, output.SerializeAsString());
+}
+
} // namespace
} // namespace internal
} // namespace protobuf